jdk/test/java/lang/ProcessHandle/TreeTest.java
changeset 32660 b5e9f5c24646
parent 31683 ac6d7a188995
child 32843 dc30a72ce1d9
equal deleted inserted replaced
32659:52d938abd6ba 32660:b5e9f5c24646
    27 import java.time.Duration;
    27 import java.time.Duration;
    28 import java.time.Instant;
    28 import java.time.Instant;
    29 import java.util.Arrays;
    29 import java.util.Arrays;
    30 import java.util.List;
    30 import java.util.List;
    31 import java.util.Set;
    31 import java.util.Set;
       
    32 import java.util.concurrent.ConcurrentHashMap;
    32 import java.util.concurrent.TimeUnit;
    33 import java.util.concurrent.TimeUnit;
    33 import java.util.stream.Collectors;
    34 import java.util.stream.Collectors;
    34 import java.util.stream.Stream;
    35 import java.util.stream.Stream;
    35 import java.util.concurrent.ExecutionException;
    36 import java.util.concurrent.ExecutionException;
    36 import org.testng.Assert;
    37 import org.testng.Assert;
    65         try {
    66         try {
    66             ProcessHandle self = ProcessHandle.current();
    67             ProcessHandle self = ProcessHandle.current();
    67 
    68 
    68             printf("self pid: %d%n", self.getPid());
    69             printf("self pid: %d%n", self.getPid());
    69             printDeep(self, "");
    70             printDeep(self, "");
    70             long count = getChildren(self).size();
       
    71             Assert.assertEquals(count, 0, "Start with zero children");
       
    72 
    71 
    73             for (int i = 0; i < MAXCHILDREN; i++) {
    72             for (int i = 0; i < MAXCHILDREN; i++) {
    74                 // spawn and wait for instructions
    73                 // spawn and wait for instructions
    75                 spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
    74                 spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
    76             }
    75             }
   122         } finally {
   121         } finally {
   123             // Cleanup any left over processes
   122             // Cleanup any left over processes
   124             spawned.stream()
   123             spawned.stream()
   125                     .map(Process::toHandle)
   124                     .map(Process::toHandle)
   126                     .filter(ProcessHandle::isAlive)
   125                     .filter(ProcessHandle::isAlive)
   127                     .forEach(ph -> printDeep(ph, "test1 cleanup: "));
   126                     .forEach(ph -> {
   128             destroyProcessTree(ProcessHandle.current());
   127                         printDeep(ph, "test1 cleanup: ");
       
   128                         ph.destroyForcibly();
       
   129                     });
   129         }
   130         }
   130     }
   131     }
   131 
   132 
   132     /**
   133     /**
   133      * Test counting and spawning and counting of Processes.
   134      * Test counting and spawning and counting of Processes.
   134      */
   135      */
   135     @Test
   136     @Test
   136     public static void test2() {
   137     public static void test2() {
   137         try {
   138         try {
       
   139             ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
       
   140 
   138             ProcessHandle self = ProcessHandle.current();
   141             ProcessHandle self = ProcessHandle.current();
   139             List<ProcessHandle> initialChildren = getChildren(self);
   142             List<ProcessHandle> initialChildren = getChildren(self);
   140             long count = initialChildren.size();
   143             long count = initialChildren.size();
   141             if (count > 0) {
   144             if (count > 0) {
   142                 initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
   145                 initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
   143                 Assert.assertEquals(count, 0, "Start with zero children (except Windows conhost.exe)");
       
   144             }
   146             }
   145 
   147 
   146             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
   148             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
   147             ProcessHandle p1Handle = p1.toHandle();
   149             ProcessHandle p1Handle = p1.toHandle();
   148             printf("  p1 pid: %d%n", p1.getPid());
   150             printf("  p1 pid: %d%n", p1.getPid());
       
   151 
       
   152             // Gather the PIDs from the output of the spawing process
       
   153             p1.forEachOutputLine((s) -> {
       
   154                 String[] split = s.trim().split(" ");
       
   155                 if (split.length == 3 && split[1].equals("spawn")) {
       
   156                     Long child = Long.valueOf(split[2]);
       
   157                     Long parent = Long.valueOf(split[0].split(":")[0]);
       
   158                     processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
       
   159                 }
       
   160             });
   149 
   161 
   150             int spawnNew = 3;
   162             int spawnNew = 3;
   151             p1.sendAction("spawn", spawnNew, "stdin");
   163             p1.sendAction("spawn", spawnNew, "stdin");
   152 
   164 
   153             // Wait for direct children to be created and save the list
   165             // Wait for direct children to be created and save the list
   158 
   170 
   159             // Each child spawns two processes and waits for commands
   171             // Each child spawns two processes and waits for commands
   160             int spawnNewSub = 2;
   172             int spawnNewSub = 2;
   161             p1.sendAction("child", "spawn", spawnNewSub, "stdin");
   173             p1.sendAction("child", "spawn", spawnNewSub, "stdin");
   162 
   174 
   163             // For each spawned child, wait for its children
   175             // Poll until all 9 child processes exist or the timeout is reached
   164             for (ProcessHandle p : subprocesses) {
   176             int expected = 9;
   165                 List<ProcessHandle> grandChildren = waitForChildren(p, spawnNewSub);
   177             long timeout = jdk.testlibrary.Utils.adjustTimeout(10L);
   166             }
   178             Instant endTimeout = Instant.now().plusSeconds(timeout);
   167 
   179             do {
       
   180                 Thread.sleep(200L);
       
   181                 printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
       
   182             } while (processes.size() < expected &&
       
   183                     Instant.now().isBefore(endTimeout));
       
   184 
       
   185             if (processes.size() < expected) {
       
   186                 printf("WARNING: not all children have been started. Can't complete test.%n");
       
   187                 printf("         You can try to increase the timeout or%n");
       
   188                 printf("         you can try to use a faster VM (i.e. not a debug version).%n");
       
   189             }
       
   190 
       
   191             // show the complete list of children (for debug)
   168             List<ProcessHandle> allChildren = getAllChildren(p1Handle);
   192             List<ProcessHandle> allChildren = getAllChildren(p1Handle);
   169             printf(" allChildren:  %s%n",
   193             printf(" allChildren:  %s%n",
   170                     allChildren.stream().map(p -> p.getPid())
   194                     allChildren.stream().map(p -> p.getPid())
   171                             .collect(Collectors.toList()));
   195                             .collect(Collectors.toList()));
   172             for (ProcessHandle ph : allChildren) {
   196 
   173                 Assert.assertEquals(ph.isAlive(), true, "Child should be alive: " + ph);
   197             // Verify that all spawned children show up in the allChildrenList
   174             }
   198             processes.forEach((p, parent) -> {
       
   199                 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
       
   200                 Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p);
       
   201             });
   175 
   202 
   176             // Closing JavaChild's InputStream will cause all children to exit
   203             // Closing JavaChild's InputStream will cause all children to exit
   177             p1.getOutputStream().close();
   204             p1.getOutputStream().close();
   178 
   205 
   179             for (ProcessHandle p : allChildren) {
   206             for (ProcessHandle p : allChildren) {
   183                     Assert.fail("waiting for process to exit", e);
   210                     Assert.fail("waiting for process to exit", e);
   184                 }
   211                 }
   185             }
   212             }
   186             p1.waitFor();           // wait for spawned process to exit
   213             p1.waitFor();           // wait for spawned process to exit
   187 
   214 
   188             List<ProcessHandle> remaining = getChildren(self);
   215             // Verify spawned processes are no longer alive
   189             remaining.forEach(ph -> Assert.assertFalse(ph.isAlive(),
   216             processes.forEach((ph, parent) -> Assert.assertFalse(ph.isAlive(),
   190                             "process should not be alive: " + ph));
   217                             "process should not be alive: " + ph));
   191         } catch (IOException | InterruptedException t) {
   218         } catch (IOException | InterruptedException t) {
   192             t.printStackTrace();
   219             t.printStackTrace();
   193             throw new RuntimeException(t);
   220             throw new RuntimeException(t);
   194         } finally {
       
   195             // Cleanup any left over processes
       
   196             destroyProcessTree(ProcessHandle.current());
       
   197         }
   221         }
   198     }
   222     }
   199 
   223 
   200     /**
   224     /**
   201      * Test destroy of processes.
   225      * Test destroy of processes.
   202      */
   226      */
   203     @Test
   227     @Test
   204     public static void test3() {
   228     public static void test3() {
       
   229         ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
       
   230 
   205         try {
   231         try {
   206             ProcessHandle self = ProcessHandle.current();
   232             ProcessHandle self = ProcessHandle.current();
   207 
   233 
   208             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
   234             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
   209             ProcessHandle p1Handle = p1.toHandle();
   235             ProcessHandle p1Handle = p1.toHandle();
   210             printf(" p1: %s%n", p1.getPid());
   236             printf(" p1: %s%n", p1.getPid());
   211 
   237 
   212             List<ProcessHandle> subprocesses = getChildren(self);
       
   213             long count = subprocesses.size();
       
   214             Assert.assertEquals(count, 1, "Wrong number of spawned children");
       
   215 
       
   216             int newChildren = 3;
   238             int newChildren = 3;
   217             // Spawn children and have them wait
   239             // Spawn children and have them wait
   218             p1.sendAction("spawn", newChildren, "stdin");
   240             p1.sendAction("spawn", newChildren, "stdin");
   219 
   241 
       
   242             // Gather the PIDs from the output of the spawing process
       
   243             p1.forEachOutputLine((s) -> {
       
   244                 String[] split = s.trim().split(" ");
       
   245                 if (split.length == 3 && split[1].equals("spawn")) {
       
   246                     Long child = Long.valueOf(split[2]);
       
   247                     Long parent = Long.valueOf(split[0].split(":")[0]);
       
   248                     processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
       
   249                 }
       
   250             });
       
   251 
   220             // Wait for the new processes and save the list
   252             // Wait for the new processes and save the list
   221             subprocesses = waitForAllChildren(p1Handle, newChildren);
   253             List<ProcessHandle> allChildren = waitForAllChildren(p1Handle, newChildren);
   222             Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children");
   254 
   223 
   255             // Verify that all spawned children are alive, show up in the allChildren list
   224             p1.children().filter(TreeTest::isNotWindowsConsole)
   256             // then destroy them
   225                     .forEach(ProcessHandle::destroyForcibly);
   257             processes.forEach((p, parent) -> {
   226 
   258                 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
   227             self.children().filter(TreeTest::isNotWindowsConsole)
   259                 Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p);
   228                     .forEach(ProcessHandle::destroyForcibly);
   260                 p.destroyForcibly();
   229 
   261             });
   230             for (ProcessHandle p : subprocesses) {
   262 
       
   263             processes.forEach((p, parent) ->  {
   231                 while (p.isAlive()) {
   264                 while (p.isAlive()) {
   232                     Thread.sleep(100L);  // It will happen but don't burn the cpu
   265                     try {
   233                 }
   266                         Thread.sleep(100L);  // It will happen but don't burn the cpu
   234             }
   267                     } catch (InterruptedException ie) {
       
   268                         // try again
       
   269                     }
       
   270                 }
       
   271             });
       
   272             p1.destroyForcibly();
       
   273             p1.waitFor();
   235 
   274 
   236             List<ProcessHandle> remaining = getAllChildren(self);
   275             List<ProcessHandle> remaining = getAllChildren(self);
   237             remaining.retainAll(subprocesses);
   276             remaining = remaining.stream().filter(processes::contains).collect(Collectors.toList());
   238             if (remaining.size() > 0) {
   277             Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining);
   239                 remaining.forEach(p -> printProcess(p, "     remaining: "));
       
   240                 Assert.fail("Subprocess(es) should have exited");
       
   241             }
       
   242 
   278 
   243         } catch (IOException ioe) {
   279         } catch (IOException ioe) {
   244             Assert.fail("Spawn of subprocess failed", ioe);
   280             Assert.fail("Spawn of subprocess failed", ioe);
   245         } catch (InterruptedException inte) {
   281         } catch (InterruptedException inte) {
   246             Assert.fail("InterruptedException", inte);
   282             Assert.fail("InterruptedException", inte);
   247         } finally {
   283         } finally {
   248             // Cleanup any left over processes
   284             processes.forEach((p, parent) -> p.destroyForcibly());
   249             destroyProcessTree(ProcessHandle.current());
       
   250         }
   285         }
   251     }
   286     }
   252 
   287 
   253     /**
   288     /**
   254      * Test (Not really a test) that dumps the list of all Processes.
   289      * Test (Not really a test) that dumps the list of all Processes.
   300      * A test for scale; launch a large number (14) of subprocesses.
   335      * A test for scale; launch a large number (14) of subprocesses.
   301      */
   336      */
   302     @Test
   337     @Test
   303     public static void test5() {
   338     public static void test5() {
   304         int factor = 2;
   339         int factor = 2;
       
   340         JavaChild p1 = null;
   305         Instant start = Instant.now();
   341         Instant start = Instant.now();
   306         try {
   342         try {
   307             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
   343             p1 = JavaChild.spawnJavaChild("stdin");
   308             ProcessHandle p1Handle = p1.toHandle();
   344             ProcessHandle p1Handle = p1.toHandle();
   309 
   345 
   310             printf("Spawning %d x %d x %d processes, pid: %d%n",
   346             printf("Spawning %d x %d x %d processes, pid: %d%n",
   311                     factor, factor, factor, p1.getPid());
   347                     factor, factor, factor, p1.getPid());
   312 
   348 
   338             p1.waitFor();
   374             p1.waitFor();
   339         } catch (InterruptedException | IOException ex) {
   375         } catch (InterruptedException | IOException ex) {
   340             Assert.fail("Unexpected Exception", ex);
   376             Assert.fail("Unexpected Exception", ex);
   341         } finally {
   377         } finally {
   342             printf("Duration: %s%n", Duration.between(start, Instant.now()));
   378             printf("Duration: %s%n", Duration.between(start, Instant.now()));
   343             destroyProcessTree(ProcessHandle.current());
   379             if (p1 != null) {
       
   380                 p1.destroyForcibly();
       
   381             }
   344         }
   382         }
   345     }
   383     }
   346 
   384 
   347 }
   385 }