src/solaris/classes/java/lang/UNIXProcess.java.solaris

Print this page

        

@@ -23,14 +23,27 @@
  * questions.
  */
 
 package java.lang;
 
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.security.AccessController;
+import static java.security.AccessController.doPrivileged;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
 /* java.lang.Process subclass in the UNIX environment.
  *
  * @author Mario Wolczko and Ross Knippel.
  */

@@ -106,100 +119,136 @@
      * Create a process. Depending on the mode flag, this is done by
      * one of the following mechanisms.
      * - fork(2) and exec(2)
      * - posix_spawn(2)
      *
-     * @param std_fds array of file descriptors.  Indexes 0, 1, and
-     *        2 correspond to standard input, standard output and
-     *        standard error, respectively.  On input, a value of -1
-     *        means to create a pipe to connect child and parent
-     *        processes.  On output, a value which is not -1 is the
-     *        parent pipe fd corresponding to the pipe which has
-     *        been created.  An element of this array is -1 on input
-     *        if and only if it is <em>not</em> -1 on output.
+     * @param fds an array of three file descriptors.
+     *        Indexes 0, 1, and 2 correspond to standard input,
+     *        standard output and standard error, respectively.  On
+     *        input, a value of -1 means to create a pipe to connect
+     *        child and parent processes.  On output, a value which
+     *        is not -1 is the parent pipe fd corresponding to the
+     *        pipe which has been created.  An element of this array
+     *        is -1 on input if and only if it is <em>not</em> -1 on
+     *        output.
      * @return the pid of the subprocess
      */
     private native int forkAndExec(int mode, byte[] helperpath,
                                    byte[] prog,
                                    byte[] argBlock, int argc,
                                    byte[] envBlock, int envc,
                                    byte[] dir,
-                                   int[] std_fds,
+                                   int[] fds,
                                    boolean redirectErrorStream)
         throws IOException;
 
+    /**
+     * The thread factory used to create "process reaper" daemon threads.
+     */
+    private static class ProcessReaperThreadFactory implements ThreadFactory {
+        private final static ThreadGroup group = getRootThreadGroup();
+
+        private static ThreadGroup getRootThreadGroup() {
+            return doPrivileged(new PrivilegedAction<ThreadGroup> () {
+                public ThreadGroup run() {
+                    ThreadGroup root = Thread.currentThread().getThreadGroup();
+                    while (root.getParent() != null)
+                        root = root.getParent();
+                    return root;
+                }});
+        }
+
+        public Thread newThread(Runnable grimReaper) {
+            // Our thread stack requirement is quite modest.
+            Thread t = new Thread(group, grimReaper, "process reaper", 32768);
+            t.setDaemon(true);
+            // A small attempt (probably futile) to avoid priority inversion
+            t.setPriority(Thread.MAX_PRIORITY);
+            return t;
+        }
+    }
+
+    /**
+     * The thread pool of "process reaper" daemon threads.
+     */
+    private static final Executor processReaperExecutor =
+        doPrivileged(new PrivilegedAction<Executor>() {
+            public Executor run() {
+                return Executors.newCachedThreadPool
+                    (new ProcessReaperThreadFactory());
+            }});
+
     UNIXProcess(final byte[] prog,
                 final byte[] argBlock, int argc,
                 final byte[] envBlock, int envc,
                 final byte[] dir,
-                final int[] std_fds,
+                final int[] fds,
                 final boolean redirectErrorStream)
     throws IOException {
         pid = forkAndExec(launchMechanism.value,
                           helperpath,
                           prog,
                           argBlock, argc,
                           envBlock, envc,
                           dir,
-                          std_fds,
+                          fds,
                           redirectErrorStream);
 
-        java.security.AccessController.doPrivileged(
-        new java.security.PrivilegedAction<Void>() { public Void run() {
-            if (std_fds[0] == -1)
+        try {
+            doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws IOException {
+                        initStreams(fds);
+                        return null;
+                    }
+                });
+        } catch (PrivilegedActionException ex) {
+            throw (IOException) ex.getException();
+        }
+    }
+
+    void initStreams(int[] fds) throws IOException {
+        if (fds[0] == -1)
                 stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
             else {
                 FileDescriptor stdin_fd = new FileDescriptor();
-                fdAccess.set(stdin_fd, std_fds[0]);
+            fdAccess.set(stdin_fd, fds[0]);
                 stdin_stream = new BufferedOutputStream(
                     new FileOutputStream(stdin_fd));
             }
 
-            if (std_fds[1] == -1)
+        if (fds[1] == -1)
                 stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
             else {
                 FileDescriptor stdout_fd = new FileDescriptor();
-                fdAccess.set(stdout_fd, std_fds[1]);
+            fdAccess.set(stdout_fd, fds[1]);
                 stdout_inner_stream = new DeferredCloseInputStream(stdout_fd);
                 stdout_stream = new BufferedInputStream(stdout_inner_stream);
             }
 
-            if (std_fds[2] == -1)
+        if (fds[2] == -1)
                 stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
             else {
                 FileDescriptor stderr_fd = new FileDescriptor();
-                fdAccess.set(stderr_fd, std_fds[2]);
+            fdAccess.set(stderr_fd, fds[2]);
                 stderr_stream = new DeferredCloseInputStream(stderr_fd);
             }
 
-            return null; }});
-
-        /*
-         * For each subprocess forked a corresponding reaper thread
-         * is started.  That thread is the only thread which waits
-         * for the subprocess to terminate and it doesn't hold any
-         * locks while doing so.  This design allows waitFor() and
-         * exitStatus() to be safely executed in parallel (and they
-         * need no native code).
-         */
-
-        java.security.AccessController.doPrivileged(
-            new java.security.PrivilegedAction<Void>() { public Void run() {
-                Thread t = new Thread("process reaper") {
+        processReaperExecutor.execute(new Runnable() {
                     public void run() {
-                        int res = waitForProcessExit(pid);
-                        synchronized (UNIXProcess.this) {
+                int exitcode = waitForProcessExit(pid);
+                UNIXProcess.this.processExited(exitcode);
+            }});
+    }
+
+    void processExited(int exitcode) {
+        synchronized (this) {
+            this.exitcode = exitcode;
                             hasExited = true;
-                            exitcode = res;
-                            UNIXProcess.this.notifyAll();
+            notifyAll();
                         }
                     }
-                };
-                t.setDaemon(true);
-                t.start();
-                return null; }});
-    }
 
     public OutputStream getOutputStream() {
         return stdin_stream;
     }