--- old/src/solaris/classes/java/lang/UNIXProcess.java.solaris 2014-05-07 09:24:15.202576467 +0200 +++ /dev/null 2014-05-05 08:19:59.438648143 +0200 @@ -1,395 +0,0 @@ -/* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang; - -import java.io.*; -import java.util.concurrent.TimeUnit; -import java.security.AccessController; -import java.security.PrivilegedAction; - -/* java.lang.Process subclass in the UNIX environment. - * - * @author Mario Wolczko and Ross Knippel. - */ - -final class UNIXProcess extends Process { - private static final sun.misc.JavaIOFileDescriptorAccess fdAccess - = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); - - private final int pid; - private int exitcode; - private boolean hasExited; - - private OutputStream stdin_stream; - private InputStream stdout_stream; - private DeferredCloseInputStream stdout_inner_stream; - private InputStream stderr_stream; - - private static enum LaunchMechanism { - FORK(1), - POSIX_SPAWN(2); - - private int value; - LaunchMechanism(int x) {value = x;} - }; - - /* On Solaris, the default is to spawn */ - private static final LaunchMechanism launchMechanism; - private static byte[] helperpath; - - private static byte[] toCString(String s) { - if (s == null) - return null; - byte[] bytes = s.getBytes(); - byte[] result = new byte[bytes.length + 1]; - System.arraycopy(bytes, 0, - result, 0, - bytes.length); - result[result.length-1] = (byte)0; - return result; - } - - static { - launchMechanism = AccessController.doPrivileged( - new PrivilegedAction() - { - public LaunchMechanism run() { - String javahome = System.getProperty("java.home"); - String osArch = System.getProperty("os.arch"); - if (osArch.equals("x86")) { - osArch = "i386"; - } else if (osArch.equals("x86_64")) { - osArch = "amd64"; - } - - helperpath = toCString(javahome + "/lib/" + osArch + "/jspawnhelper"); - String s = System.getProperty( - "jdk.lang.Process.launchMechanism", "posix_spawn"); - - try { - return LaunchMechanism.valueOf(s.toUpperCase()); - } catch (IllegalArgumentException e) { - throw new Error(s + " is not a supported " + - "process launch mechanism on this platform."); - } - } - }); - } - - /* this is for the reaping thread */ - private native int waitForProcessExit(int pid); - - /** - * 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 not -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, - boolean redirectErrorStream) - throws IOException; - - UNIXProcess(final byte[] prog, - final byte[] argBlock, int argc, - final byte[] envBlock, int envc, - final byte[] dir, - final int[] std_fds, - final boolean redirectErrorStream) - throws IOException { - pid = forkAndExec(launchMechanism.value, - helperpath, - prog, - argBlock, argc, - envBlock, envc, - dir, - std_fds, - redirectErrorStream); - - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { public Void run() { - if (std_fds[0] == -1) - stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE; - else { - FileDescriptor stdin_fd = new FileDescriptor(); - fdAccess.set(stdin_fd, std_fds[0]); - stdin_stream = new BufferedOutputStream( - new FileOutputStream(stdin_fd)); - } - - if (std_fds[1] == -1) - stdout_stream = ProcessBuilder.NullInputStream.INSTANCE; - else { - FileDescriptor stdout_fd = new FileDescriptor(); - fdAccess.set(stdout_fd, std_fds[1]); - stdout_inner_stream = new DeferredCloseInputStream(stdout_fd); - stdout_stream = new BufferedInputStream(stdout_inner_stream); - } - - if (std_fds[2] == -1) - stderr_stream = ProcessBuilder.NullInputStream.INSTANCE; - else { - FileDescriptor stderr_fd = new FileDescriptor(); - fdAccess.set(stderr_fd, std_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() { public Void run() { - Thread t = new Thread("process reaper") { - public void run() { - int res = waitForProcessExit(pid); - synchronized (UNIXProcess.this) { - hasExited = true; - exitcode = res; - UNIXProcess.this.notifyAll(); - } - } - }; - t.setDaemon(true); - t.start(); - return null; }}); - } - - public OutputStream getOutputStream() { - return stdin_stream; - } - - public InputStream getInputStream() { - return stdout_stream; - } - - public InputStream getErrorStream() { - return stderr_stream; - } - - public synchronized int waitFor() throws InterruptedException { - while (!hasExited) { - wait(); - } - return exitcode; - } - - @Override - public synchronized boolean waitFor(long timeout, TimeUnit unit) - throws InterruptedException - { - if (hasExited) return true; - if (timeout <= 0) return false; - - long timeoutAsNanos = unit.toNanos(timeout); - long startTime = System.nanoTime(); - long rem = timeoutAsNanos; - - while (!hasExited && (rem > 0)) { - wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1)); - rem = timeoutAsNanos - (System.nanoTime() - startTime); - } - return hasExited; - } - - public synchronized int exitValue() { - if (!hasExited) { - throw new IllegalThreadStateException("process hasn't exited"); - } - return exitcode; - } - - private static native void destroyProcess(int pid, boolean force); - private synchronized void destroy(boolean force) { - // There is a risk that pid will be recycled, causing us to - // kill the wrong process! So we only terminate processes - // that appear to still be running. Even with this check, - // there is an unavoidable race condition here, but the window - // is very small, and OSes try hard to not recycle pids too - // soon, so this is quite safe. - if (!hasExited) - destroyProcess(pid, force); - try { - stdin_stream.close(); - if (stdout_inner_stream != null) - stdout_inner_stream.closeDeferred(stdout_stream); - if (stderr_stream instanceof DeferredCloseInputStream) - ((DeferredCloseInputStream) stderr_stream) - .closeDeferred(stderr_stream); - } catch (IOException e) { - // ignore - } - } - - public void destroy() { - destroy(false); - } - - @Override - public Process destroyForcibly() { - destroy(true); - return this; - } - - @Override - public synchronized boolean isAlive() { - return !hasExited; - } - - // A FileInputStream that supports the deferment of the actual close - // operation until the last pending I/O operation on the stream has - // finished. This is required on Solaris because we must close the stdin - // and stdout streams in the destroy method in order to reclaim the - // underlying file descriptors. Doing so, however, causes any thread - // currently blocked in a read on one of those streams to receive an - // IOException("Bad file number"), which is incompatible with historical - // behavior. By deferring the close we allow any pending reads to see -1 - // (EOF) as they did before. - // - private static class DeferredCloseInputStream - extends FileInputStream - { - - private DeferredCloseInputStream(FileDescriptor fd) { - super(fd); - } - - private Object lock = new Object(); // For the following fields - private boolean closePending = false; - private int useCount = 0; - private InputStream streamToClose; - - private void raise() { - synchronized (lock) { - useCount++; - } - } - - private void lower() throws IOException { - synchronized (lock) { - useCount--; - if (useCount == 0 && closePending) { - streamToClose.close(); - } - } - } - - // stc is the actual stream to be closed; it might be this object, or - // it might be an upstream object for which this object is downstream. - // - private void closeDeferred(InputStream stc) throws IOException { - synchronized (lock) { - if (useCount == 0) { - stc.close(); - } else { - closePending = true; - streamToClose = stc; - } - } - } - - public void close() throws IOException { - synchronized (lock) { - useCount = 0; - closePending = false; - } - super.close(); - } - - public int read() throws IOException { - raise(); - try { - return super.read(); - } finally { - lower(); - } - } - - public int read(byte[] b) throws IOException { - raise(); - try { - return super.read(b); - } finally { - lower(); - } - } - - public int read(byte[] b, int off, int len) throws IOException { - raise(); - try { - return super.read(b, off, len); - } finally { - lower(); - } - } - - public long skip(long n) throws IOException { - raise(); - try { - return super.skip(n); - } finally { - lower(); - } - } - - public int available() throws IOException { - raise(); - try { - return super.available(); - } finally { - lower(); - } - } - - } - - private static native void init(); - - static { - init(); - } -}