changeset 13023:bb286ec75b24

8138566: (Process) java.lang.Process.allChildren specification clarification 8140213: Process/ProcessHandle.onExit() spec need to be improved 8140250: (process) Process.info description is inaccurate Summary: rename to descendants() and clarify Reviewed-by: psandoz
author rriggs
date Mon, 09 Nov 2015 11:02:07 -0500
parents f3d644bd5380
children 7e2dc25eef6b
files src/java.base/share/classes/java/lang/Process.java src/java.base/share/classes/java/lang/ProcessHandle.java src/java.base/share/classes/java/lang/ProcessHandleImpl.java test/java/lang/ProcessBuilder/Basic.java test/java/lang/ProcessHandle/OnExitTest.java test/java/lang/ProcessHandle/PermissionTest.java test/java/lang/ProcessHandle/ProcessUtil.java test/java/lang/ProcessHandle/TreeTest.java
diffstat 8 files changed, 65 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Process.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/src/java.base/share/classes/java/lang/Process.java	Mon Nov 09 11:02:07 2015 -0500
@@ -83,7 +83,7 @@
  * {@link #getPid() process id},
  * {@link #info() information about the process},
  * {@link #children() direct children}, and
- * {@link #allChildren() direct and indirect children} of the process.
+ * {@link #descendants() direct children plus descendants of those children} of the process.
  * Delegating to the underlying Process or ProcessHandle is typically
  * easiest and most efficient.
  *
@@ -351,7 +351,7 @@
      * The {@link java.util.concurrent.CompletableFuture} provides the ability
      * to trigger dependent functions or actions that may be run synchronously
      * or asynchronously upon process termination.
-     * When the process terminates the CompletableFuture is
+     * When the process has terminated the CompletableFuture is
      * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
      * of the exit status of the process.
      * <p>
@@ -362,9 +362,6 @@
      * {@link java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
      * the CompletableFuture does not affect the Process.
      * <p>
-     * If the process is {@link #isAlive not alive} the {@link CompletableFuture}
-     * returned has been {@link java.util.concurrent.CompletableFuture#complete completed}.
-     * <p>
      * Processes returned from {@link ProcessBuilder#start} override the
      * default implementation to provide an efficient mechanism to wait
      * for process exit.
@@ -406,6 +403,9 @@
      *       return delegate.onExit().thenApply(p -> this);
      *    }
      * }</pre>
+     * @apiNote
+     * The process may be observed to have terminated with {@link #isAlive}
+     * before the ComputableFuture is completed and dependent actions are invoked.
      *
      * @return a new {@code CompletableFuture<Process>} for the Process
      *
@@ -464,7 +464,7 @@
      * {@link java.lang.UnsupportedOperationException} and performs no other action.
      * Subclasses should override this method to provide a ProcessHandle for the
      * process.  The methods {@link #getPid}, {@link #info}, {@link #children},
-     * and {@link #allChildren}, unless overridden, operate on the ProcessHandle.
+     * and {@link #descendants}, unless overridden, operate on the ProcessHandle.
      *
      * @return Returns a ProcessHandle for the Process
      * @throws UnsupportedOperationException if the Process implementation
@@ -481,9 +481,8 @@
     /**
      * Returns a snapshot of information about the process.
      *
-     * <p> An {@link ProcessHandle.Info} instance has various accessor methods
-     * that return information about the process, if the process is alive and
-     * the information is available, otherwise {@code null} is returned.
+     * <p> A {@link ProcessHandle.Info} instance has accessor methods
+     * that return information about the process if it is available.
      *
      * @implSpec
      * This implementation returns information about the process as:
@@ -524,9 +523,9 @@
     }
 
     /**
-     * Returns a snapshot of the direct and indirect children of the process.
-     * An indirect child is one whose parent is either a direct child or
-     * another indirect child.
+     * Returns a snapshot of the descendants of the process.
+     * The descendants of a process are the children of the process
+     * plus the descendants of those children, recursively.
      * Typically, a process that is {@link #isAlive not alive} has no children.
      * <p>
      * <em>Note that processes are created and terminate asynchronously.
@@ -535,18 +534,18 @@
      *
      * @implSpec
      * This implementation returns all children as:
-     * {@link #toHandle toHandle().allChildren()}.
+     * {@link #toHandle toHandle().descendants()}.
      *
-     * @return a sequential Stream of ProcessHandles for processes that are
-     *         direct and indirect children of the process
+     * @return a sequential Stream of ProcessHandles for processes that
+     *         are descendants of the process
      * @throws UnsupportedOperationException if the Process implementation
      *         does not support this operation
      * @throws SecurityException if a security manager has been installed and
      *         it denies RuntimePermission("manageProcess")
      * @since 1.9
      */
-    public Stream<ProcessHandle> allChildren() {
-        return toHandle().allChildren();
+    public Stream<ProcessHandle> descendants() {
+        return toHandle().descendants();
     }
 
 
--- a/src/java.base/share/classes/java/lang/ProcessHandle.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/src/java.base/share/classes/java/lang/ProcessHandle.java	Mon Nov 09 11:02:07 2015 -0500
@@ -54,7 +54,7 @@
  * Each ProcessHandle identifies and allows control of a process in the native
  * system. ProcessHandles are returned from the factory methods {@link #current()},
  * {@link #of(long)},
- * {@link #children}, {@link #allChildren}, {@link #parent()} and
+ * {@link #children}, {@link #descendants}, {@link #parent()} and
  * {@link #allProcesses()}.
  * <p>
  * The {@link Process} instances created by {@link ProcessBuilder} can be queried
@@ -164,21 +164,21 @@
     Stream<ProcessHandle> children();
 
     /**
-     * Returns a snapshot of the current direct and indirect children of the process.
-     * An indirect child is one whose parent is either a direct child or
-     * another indirect child.
+     * Returns a snapshot of the descendants of the process.
+     * The descendants of a process are the children of the process
+     * plus the descendants of those children, recursively.
      * Typically, a process that is {@link #isAlive not alive} has no children.
      * <p>
      * <em>Note that processes are created and terminate asynchronously.
      * There is no guarantee that a process is {@link #isAlive alive}.
      * </em>
      *
-     * @return a sequential Stream of ProcessHandles for processes that are
-     *         direct and indirect children of the process
+     * @return a sequential Stream of ProcessHandles for processes that
+     *         are descendants of the process
      * @throws SecurityException if a security manager has been installed and
      *         it denies RuntimePermission("manageProcess")
      */
-    Stream<ProcessHandle> allChildren();
+    Stream<ProcessHandle> descendants();
 
     /**
      * Returns a snapshot of all processes visible to the current process.
@@ -201,9 +201,8 @@
     /**
      * Returns a snapshot of information about the process.
      *
-     * <p> An {@code Info} instance has various accessor methods that return
-     * information about the process, if the process is alive and the
-     * information is available.
+     * <p> A {@link ProcessHandle.Info} instance has accessor methods that return
+     * information about the process if it is available.
      *
      * @return a snapshot of information about the process, always non-null
      */
@@ -288,7 +287,7 @@
      * The {@link java.util.concurrent.CompletableFuture} provides the ability
      * to trigger dependent functions or actions that may be run synchronously
      * or asynchronously upon process termination.
-     * When the process terminates the CompletableFuture is
+     * When the process has terminated the CompletableFuture is
      * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
      * of the exit status of the process.
      * The {@code onExit} method can be called multiple times to invoke
@@ -300,9 +299,9 @@
      * {@link java.util.concurrent.Future#get() wait} for it to terminate.
      * {@link java.util.concurrent.Future#cancel(boolean) Cancelling}
      * the CompleteableFuture does not affect the Process.
-     * <p>
-     * If the process is {@link #isAlive not alive} the {@link CompletableFuture}
-     * returned has been {@link java.util.concurrent.CompletableFuture#complete completed}.
+     * @apiNote
+     * The process may be observed to have terminated with {@link #isAlive}
+     * before the ComputableFuture is completed and dependent actions are invoked.
      *
      * @return a new {@code CompletableFuture<ProcessHandle>} for the ProcessHandle
      *
--- a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Mon Nov 09 11:02:07 2015 -0500
@@ -389,7 +389,7 @@
     }
 
     @Override
-    public Stream<ProcessHandle> allChildren() {
+    public Stream<ProcessHandle> descendants() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(new RuntimePermission("manageProcess"));
--- a/test/java/lang/ProcessBuilder/Basic.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/test/java/lang/ProcessBuilder/Basic.java	Mon Nov 09 11:02:07 2015 -0500
@@ -1248,7 +1248,7 @@
                 () -> p.toHandle(),
                 () -> p.supportsNormalTermination(),
                 () -> p.children(),
-                () -> p.allChildren());
+                () -> p.descendants());
 
     }
 
--- a/test/java/lang/ProcessHandle/OnExitTest.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/test/java/lang/ProcessHandle/OnExitTest.java	Mon Nov 09 11:02:07 2015 -0500
@@ -129,7 +129,7 @@
                 printf("         You can try to increase the timeout or%n");
                 printf("         you can try to use a faster VM (i.e. not a debug version).%n");
             }
-            children = getAllChildren(procHandle);
+            children = getDescendants(procHandle);
 
             ConcurrentHashMap<ProcessHandle, CompletableFuture<ProcessHandle>> completions =
                     new ConcurrentHashMap<>();
--- a/test/java/lang/ProcessHandle/PermissionTest.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/test/java/lang/ProcessHandle/PermissionTest.java	Mon Nov 09 11:02:07 2015 -0500
@@ -62,9 +62,9 @@
     }
 
     @Test
-    public void allChildrenWithPermission() {
+    public void descendantsWithPermission() {
         Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
-        currentHndl.allChildren();
+        currentHndl.descendants();
     }
 
     @Test
@@ -122,7 +122,7 @@
 
     @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
     public void noPermissionAllChildren() {
-        currentHndl.allChildren();
+        currentHndl.descendants();
     }
 
     @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
--- a/test/java/lang/ProcessHandle/ProcessUtil.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/test/java/lang/ProcessHandle/ProcessUtil.java	Mon Nov 09 11:02:07 2015 -0500
@@ -63,8 +63,8 @@
      * @param ph the Process to get children of
      * @return a list of child ProcessHandles
      */
-    public static List<ProcessHandle> getAllChildren(ProcessHandle ph) {
-        return ph.allChildren()
+    public static List<ProcessHandle> getDescendants(ProcessHandle ph) {
+        return ph.descendants()
                 .filter(ProcessUtil::isNotWindowsConsole)
                 .collect(Collectors.toList());
     }
@@ -117,7 +117,7 @@
                     // ignore
                 }
             }
-            subprocesses = getAllChildren(ph);
+            subprocesses = getDescendants(ph);
             count = subprocesses.size();
             System.out.printf(" waiting for subprocesses of %s to start," +
                     " expected: %d, current: %d%n", ph, nchildren, count);
@@ -133,7 +133,7 @@
      * @return the ProcessHandle
      */
     public static ProcessHandle destroyProcessTree(ProcessHandle p) {
-        Stream<ProcessHandle> children = p.allChildren().filter(ProcessUtil::isNotWindowsConsole);
+        Stream<ProcessHandle> children = p.descendants().filter(ProcessUtil::isNotWindowsConsole);
         children.forEach(ph -> {
             System.out.printf("destroyProcessTree destroyForcibly%n");
             printProcess(ph);
--- a/test/java/lang/ProcessHandle/TreeTest.java	Fri Nov 06 17:27:27 2015 -0500
+++ b/test/java/lang/ProcessHandle/TreeTest.java	Mon Nov 09 11:02:07 2015 -0500
@@ -193,21 +193,21 @@
             }
 
             // show the complete list of children (for debug)
-            List<ProcessHandle> allChildren = getAllChildren(p1Handle);
-            printf(" allChildren:  %s%n",
-                    allChildren.stream().map(p -> p.getPid())
-                            .collect(Collectors.toList()));
+            List<ProcessHandle> descendants = getDescendants(p1Handle);
+            printf(" descendants:  %s%n",
+                    descendants.stream().map(p -> p.getPid())
+                           .collect(Collectors.toList()));
 
-            // Verify that all spawned children show up in the allChildren List
+            // Verify that all spawned children show up in the descendants  List
             processes.forEach((p, parent) -> {
                 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
-                Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p);
+                Assert.assertTrue(descendants.contains(p), "Spawned child should be listed in descendants: " + p);
             });
 
             // Closing JavaChild's InputStream will cause all children to exit
             p1.getOutputStream().close();
 
-            for (ProcessHandle p : allChildren) {
+            for (ProcessHandle p : descendants) {
                 try {
                     p.onExit().get();       // wait for the child to exit
                 } catch (ExecutionException e) {
@@ -228,9 +228,9 @@
     /**
      * Test destroy of processes.
      * A JavaChild is started and it starts three children.
-     * Each one is then checked to be alive and listed by allChildren
+     * Each one is then checked to be alive and listed by descendants
      * and forcibly destroyed.
-     * After they exit they should no longer be listed by allChildren.
+     * After they exit they should no longer be listed by descendants.
      */
     @Test
     public static void test3() {
@@ -263,24 +263,24 @@
             Assert.assertTrue(spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
                     "Timeout waiting for processes to start");
 
-            // Debugging; list allChildren that are not expected in processes
-            List<ProcessHandle> allChildren = ProcessUtil.getAllChildren(p1Handle);
-            long count = allChildren.stream()
+            // Debugging; list descendants that are not expected in processes
+            List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
+            long count = descendants.stream()
                     .filter(ph -> !processes.containsKey(ph))
                     .count();
             if (count > 0) {
-                allChildren.stream()
+                descendants.stream()
                     .filter(ph -> !processes.containsKey(ph))
                     .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
                 ProcessUtil.logTaskList();
-                Assert.assertEquals(0, count, "Extra processes in allChildren");
+                Assert.assertEquals(0, count, "Extra processes in descendants");
             }
 
-            // Verify that all spawned children are alive, show up in the allChildren list
+            // Verify that all spawned children are alive, show up in the descendants list
             // then destroy them
             processes.forEach((p, parent) -> {
                 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
-                Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p);
+                Assert.assertTrue(descendants.contains(p), "Spawned child should be listed in descendants: " + p);
                 p.destroyForcibly();
             });
             Assert.assertEquals(processes.size(), newChildren, "Wrong number of children");
@@ -305,8 +305,8 @@
             p1.destroyForcibly();
             p1.waitFor();
 
-            // Verify that none of the spawned children are still listed by allChildren
-            List<ProcessHandle> remaining = getAllChildren(self);
+            // Verify that none of the spawned children are still listed by descendants
+            List<ProcessHandle> remaining = getDescendants(self);
             Assert.assertFalse(remaining.remove(p1Handle), "Child p1 should have exited");
             remaining = remaining.stream().filter(processes::containsKey).collect(Collectors.toList());
             Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining);
@@ -415,28 +415,28 @@
             Assert.assertTrue(spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
                     "Timeout waiting for processes to start");
 
-            // Debugging; list allChildren that are not expected in processes
-            List<ProcessHandle> allChildren = ProcessUtil.getAllChildren(p1Handle);
-            long count = allChildren.stream()
+            // Debugging; list descendants that are not expected in processes
+            List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
+            long count = descendants.stream()
                     .filter(ph -> !processes.containsKey(ph))
                     .count();
             if (count > 0) {
-                allChildren.stream()
+                descendants.stream()
                     .filter(ph -> !processes.containsKey(ph))
                     .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
                 ProcessUtil.logTaskList();
-                Assert.assertEquals(0, count, "Extra processes in allChildren");
+                Assert.assertEquals(0, count, "Extra processes in descendants");
             }
 
             Assert.assertEquals(getChildren(p1Handle).size(),
                     factor, "expected direct children");
-            count = getAllChildren(p1Handle).size();
+            count = getDescendants(p1Handle).size();
             long totalChildren = factor * factor * factor + factor * factor + factor;
             Assert.assertTrue(count >= totalChildren,
                     "expected at least " + totalChildren + ", actual: " + count);
 
-            List<ProcessHandle> subprocesses = getAllChildren(p1Handle);
-            printf(" allChildren:  %s%n",
+            List<ProcessHandle> subprocesses = getDescendants(p1Handle);
+            printf(" descendants:  %s%n",
                     subprocesses.stream().map(p -> p.getPid())
                     .collect(Collectors.toList()));