--- old/src/java.base/unix/classes/java/lang/ProcessImpl.java 2015-04-14 15:58:55.759618455 +0200 +++ new/src/java.base/unix/classes/java/lang/ProcessImpl.java 2015-04-14 15:58:55.703618322 +0200 @@ -25,27 +25,32 @@ package java.lang; -import java.lang.ProcessBuilder.Redirect; +import sun.nio.ch.SelChImpl; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; +import java.io.Closeable; 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.lang.ProcessBuilder.Redirect; +import java.nio.channels.Pipe; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.EnumSet; import java.util.Locale; import java.util.Set; import java.util.concurrent.CompletableFuture; 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. @@ -75,6 +80,10 @@ // only used on Solaris private /* final */ DeferredCloseInputStream stdout_inner_stream; + private final Pipe.SinkChannel stdinChannel; + private final Pipe.SourceChannel stdoutChannel; + private final Pipe.SourceChannel stderrChannel; + private static enum LaunchMechanism { // order IS important! FORK, @@ -221,36 +230,62 @@ FileOutputStream f1 = null; FileOutputStream f2 = null; + Pipe p0 = null; + Pipe p1 = null; + Pipe p2 = null; + try { if (redirects == null) { std_fds = new int[] { -1, -1, -1 }; } else { std_fds = new int[3]; - if (redirects[0] == Redirect.PIPE) + if (redirects[0] == Redirect.PIPE) { std_fds[0] = -1; - else if (redirects[0] == Redirect.INHERIT) + } else if (redirects[0] == Redirect.PIPE_CHANNEL) { + p0 = Pipe.open(); + if (!(p0.source() instanceof SelChImpl)) { + throw new UnsupportedOperationException("Unsupported SelectorProvider"); + } + std_fds[0] = ((SelChImpl) p0.source()).getFDVal(); + } else if (redirects[0] == Redirect.INHERIT) { std_fds[0] = 0; - else { + } else { f0 = new FileInputStream(redirects[0].file()); std_fds[0] = fdAccess.get(f0.getFD()); } - if (redirects[1] == Redirect.PIPE) + if (redirects[1] == Redirect.PIPE) { std_fds[1] = -1; - else if (redirects[1] == Redirect.INHERIT) + } else if (redirects[1] == Redirect.PIPE_CHANNEL) { + p1 = Pipe.open(); + if (!(p1.sink() instanceof SelChImpl)) { + throw new UnsupportedOperationException("Unsupported SelectorProvider"); + } + std_fds[1] = ((SelChImpl) p1.sink()).getFDVal(); + } else if (redirects[1] == Redirect.INHERIT) { std_fds[1] = 1; - else { + } else { f1 = new FileOutputStream(redirects[1].file(), redirects[1].append()); std_fds[1] = fdAccess.get(f1.getFD()); } - if (redirects[2] == Redirect.PIPE) + if (redirects[2] == Redirect.PIPE) { std_fds[2] = -1; - else if (redirects[2] == Redirect.INHERIT) + } else if (redirects[2] == Redirect.PIPE_CHANNEL) { + if (redirectErrorStream) { + std_fds[2] = -1; + } else { + p2 = Pipe.open(); + if (!(p2.sink() instanceof SelChImpl)) { + throw new UnsupportedOperationException("Unsupported SelectorProvider"); + } + std_fds[2] = ((SelChImpl) p2.sink()).getFDVal(); + } + } else if (redirects[2] == Redirect.INHERIT) { std_fds[2] = 2; - else { + } else { f2 = new FileOutputStream(redirects[2].file(), redirects[2].append()); std_fds[2] = fdAccess.get(f2.getFD()); @@ -263,16 +298,36 @@ envBlock, envc[0], toCString(dir), std_fds, + new Pipe[] { p0, p1, p2 }, redirectErrorStream); + } catch (Exception e) { + // close unused pipe ends + if (p0 != null) close(p0.sink()); + if (p1 != null) close(p1.source()); + if (p2 != null) close(p2.source()); + // re-throw + throw e; } finally { - // In theory, close() can throw IOException - // (although it is rather unlikely to happen here) - try { if (f0 != null) f0.close(); } - finally { - try { if (f1 != null) f1.close(); } - finally { if (f2 != null) f2.close(); } + // close dup-ed file handles + close(f0); + close(f1); + close(f2); + // close dup-ed pipe ends + if (p0 != null) close(p0.source()); + if (p1 != null) close(p1.sink()); + if (p2 != null) close(p2.sink()); + } + } + + private static IOException close(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + return e; } } + return null; } @@ -309,6 +364,7 @@ final byte[] envBlock, final int envc, final byte[] dir, final int[] fds, + final Pipe[] pipes, final boolean redirectErrorStream) throws IOException { @@ -330,6 +386,10 @@ } catch (PrivilegedActionException ex) { throw (IOException) ex.getException(); } + + stdinChannel = (pipes[0] == null) ? null : pipes[0].sink(); + stdoutChannel = (pipes[1] == null) ? null : pipes[1].source(); + stderrChannel = (pipes[2] == null) ? null : pipes[2].source(); } static FileDescriptor newFileDescriptor(int fd) { @@ -458,6 +518,18 @@ return stderr; } + public Pipe.SinkChannel getOutputChannel() { + return stdinChannel; + } + + public Pipe.SourceChannel getInputChannel() { + return stdoutChannel; + } + + public Pipe.SourceChannel getErrorChannel() { + return stderrChannel; + } + public synchronized int waitFor() throws InterruptedException { while (!hasExited) { wait();