提交 77d81452 编写于 作者: R robm

8034944: (process) Improve subprocess handling on Solaris

Reviewed-by: alanb, martin
上级 5c0bf4d0
...@@ -25,10 +25,23 @@ ...@@ -25,10 +25,23 @@
package java.lang; 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.util.concurrent.TimeUnit;
import java.security.AccessController; import java.security.AccessController;
import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
/* java.lang.Process subclass in the UNIX environment. /* java.lang.Process subclass in the UNIX environment.
* *
...@@ -108,14 +121,15 @@ final class UNIXProcess extends Process { ...@@ -108,14 +121,15 @@ final class UNIXProcess extends Process {
* - fork(2) and exec(2) * - fork(2) and exec(2)
* - posix_spawn(2) * - posix_spawn(2)
* *
* @param std_fds array of file descriptors. Indexes 0, 1, and * @param fds an array of three file descriptors.
* 2 correspond to standard input, standard output and * Indexes 0, 1, and 2 correspond to standard input,
* standard error, respectively. On input, a value of -1 * standard output and standard error, respectively. On
* means to create a pipe to connect child and parent * input, a value of -1 means to create a pipe to connect
* processes. On output, a value which is not -1 is the * child and parent processes. On output, a value which
* parent pipe fd corresponding to the pipe which has * is not -1 is the parent pipe fd corresponding to the
* been created. An element of this array is -1 on input * pipe which has been created. An element of this array
* if and only if it is <em>not</em> -1 on output. * is -1 on input if and only if it is <em>not</em> -1 on
* output.
* @return the pid of the subprocess * @return the pid of the subprocess
*/ */
private native int forkAndExec(int mode, byte[] helperpath, private native int forkAndExec(int mode, byte[] helperpath,
...@@ -123,15 +137,51 @@ final class UNIXProcess extends Process { ...@@ -123,15 +137,51 @@ final class UNIXProcess extends Process {
byte[] argBlock, int argc, byte[] argBlock, int argc,
byte[] envBlock, int envc, byte[] envBlock, int envc,
byte[] dir, byte[] dir,
int[] std_fds, int[] fds,
boolean redirectErrorStream) boolean redirectErrorStream)
throws IOException; 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, UNIXProcess(final byte[] prog,
final byte[] argBlock, int argc, final byte[] argBlock, int argc,
final byte[] envBlock, int envc, final byte[] envBlock, int envc,
final byte[] dir, final byte[] dir,
final int[] std_fds, final int[] fds,
final boolean redirectErrorStream) final boolean redirectErrorStream)
throws IOException { throws IOException {
pid = forkAndExec(launchMechanism.value, pid = forkAndExec(launchMechanism.value,
...@@ -140,63 +190,62 @@ final class UNIXProcess extends Process { ...@@ -140,63 +190,62 @@ final class UNIXProcess extends Process {
argBlock, argc, argBlock, argc,
envBlock, envc, envBlock, envc,
dir, dir,
std_fds, fds,
redirectErrorStream); redirectErrorStream);
java.security.AccessController.doPrivileged( try {
new java.security.PrivilegedAction<Void>() { public Void run() { doPrivileged(
if (std_fds[0] == -1) new PrivilegedExceptionAction<Void>() {
stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE; public Void run() throws IOException {
else { initStreams(fds);
FileDescriptor stdin_fd = new FileDescriptor(); return null;
fdAccess.set(stdin_fd, std_fds[0]); }
stdin_stream = new BufferedOutputStream( });
new FileOutputStream(stdin_fd)); } catch (PrivilegedActionException ex) {
} throw (IOException) ex.getException();
}
}
if (std_fds[1] == -1) void initStreams(int[] fds) throws IOException {
stdout_stream = ProcessBuilder.NullInputStream.INSTANCE; if (fds[0] == -1)
else { stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
FileDescriptor stdout_fd = new FileDescriptor(); else {
fdAccess.set(stdout_fd, std_fds[1]); FileDescriptor stdin_fd = new FileDescriptor();
stdout_inner_stream = new DeferredCloseInputStream(stdout_fd); fdAccess.set(stdin_fd, fds[0]);
stdout_stream = new BufferedInputStream(stdout_inner_stream); stdin_stream = new BufferedOutputStream(
} new FileOutputStream(stdin_fd));
}
if (std_fds[2] == -1) if (fds[1] == -1)
stderr_stream = ProcessBuilder.NullInputStream.INSTANCE; stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
else { else {
FileDescriptor stderr_fd = new FileDescriptor(); FileDescriptor stdout_fd = new FileDescriptor();
fdAccess.set(stderr_fd, std_fds[2]); fdAccess.set(stdout_fd, fds[1]);
stderr_stream = new DeferredCloseInputStream(stderr_fd); stdout_inner_stream = new DeferredCloseInputStream(stdout_fd);
} stdout_stream = new BufferedInputStream(stdout_inner_stream);
}
return null; }}); if (fds[2] == -1)
stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
/* else {
* For each subprocess forked a corresponding reaper thread FileDescriptor stderr_fd = new FileDescriptor();
* is started. That thread is the only thread which waits fdAccess.set(stderr_fd, fds[2]);
* for the subprocess to terminate and it doesn't hold any stderr_stream = new DeferredCloseInputStream(stderr_fd);
* locks while doing so. This design allows waitFor() and }
* exitStatus() to be safely executed in parallel (and they
* need no native code). processReaperExecutor.execute(new Runnable() {
*/ public void run() {
int exitcode = waitForProcessExit(pid);
java.security.AccessController.doPrivileged( UNIXProcess.this.processExited(exitcode);
new java.security.PrivilegedAction<Void>() { public Void run() { }});
Thread t = new Thread("process reaper") { }
public void run() {
int res = waitForProcessExit(pid); void processExited(int exitcode) {
synchronized (UNIXProcess.this) { synchronized (this) {
hasExited = true; this.exitcode = exitcode;
exitcode = res; hasExited = true;
UNIXProcess.this.notifyAll(); notifyAll();
} }
}
};
t.setDaemon(true);
t.start();
return null; }});
} }
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册