1a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski/* 22c87ad3a45cecf9e344487cad1abfdebe79f2c7cNarayan Kamath * Copyright (C) 2014 The Android Open Source Project 3a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 4a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 6a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 7a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 8a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 9a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 10a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 11a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 12a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 13a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 16a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * accompanied this code). 17a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 18a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 19a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 20a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 22a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 24a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * questions. 25a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 26a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 27a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskipackage java.lang; 28a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 29a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.BufferedInputStream; 30a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.BufferedOutputStream; 31a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.ByteArrayInputStream; 32a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.FileDescriptor; 33a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.FileInputStream; 34a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.FileOutputStream; 35a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.IOException; 36a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.InputStream; 37a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.io.OutputStream; 38a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.util.Arrays; 39a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.util.concurrent.Executors; 40a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.util.concurrent.Executor; 41a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.util.concurrent.ThreadFactory; 42a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.security.AccessController; 43a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport static java.security.AccessController.doPrivileged; 44a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.security.PrivilegedAction; 45a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.security.PrivilegedActionException; 46a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskiimport java.security.PrivilegedExceptionAction; 47a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 48a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski/** 49a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * java.lang.Process subclass in the UNIX environment. 50a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 51a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * @author Mario Wolczko and Ross Knippel. 52a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * @author Konstantin Kladko (ported to Linux) 53a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * @author Martin Buchholz 54a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 55a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebskifinal class UNIXProcess extends Process { 56a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private final int pid; 57a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private int exitcode; 58a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private boolean hasExited; 59a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 60a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private /* final */ OutputStream stdin; 61a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private /* final */ InputStream stdout; 62a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private /* final */ InputStream stderr; 63a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 64a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /* this is for the reaping thread */ 65a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private native int waitForProcessExit(int pid); 66a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 67a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** 68a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * Create a process using fork(2) and exec(2). 69a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 70a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * @param fds an array of three file descriptors. 71a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * Indexes 0, 1, and 2 correspond to standard input, 72a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * standard output and standard error, respectively. On 73a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * input, a value of -1 means to create a pipe to connect 74a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * child and parent processes. On output, a value which 75a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * is not -1 is the parent pipe fd corresponding to the 76a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * pipe which has been created. An element of this array 77a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * is -1 on input if and only if it is <em>not</em> -1 on 78a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * output. 79a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * @return the pid of the subprocess 80a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 81a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private native int forkAndExec(byte[] prog, 82a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski byte[] argBlock, int argc, 83a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski byte[] envBlock, int envc, 84a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski byte[] dir, 85a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski int[] fds, 86a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski boolean redirectErrorStream) 87a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski throws IOException; 88a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 89a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** 90a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * The thread factory used to create "process reaper" daemon threads. 91a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 92a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static class ProcessReaperThreadFactory implements ThreadFactory { 93a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private final static ThreadGroup group = getRootThreadGroup(); 94a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 95a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static ThreadGroup getRootThreadGroup() { 96a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return doPrivileged(new PrivilegedAction<ThreadGroup> () { 97a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public ThreadGroup run() { 98a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ThreadGroup root = Thread.currentThread().getThreadGroup(); 99a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski while (root.getParent() != null) 100a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski root = root.getParent(); 101a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return root; 102a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski }}); 103a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 104a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 105a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public Thread newThread(Runnable grimReaper) { 106a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // Our thread stack requirement is quite modest. 107a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski Thread t = new Thread(group, grimReaper, "process reaper", 32768); 108a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski t.setDaemon(true); 109a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // A small attempt (probably futile) to avoid priority inversion 110a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski t.setPriority(Thread.MAX_PRIORITY); 111a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return t; 112a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 113a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 114a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 115a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** 116a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * The thread pool of "process reaper" daemon threads. 117a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 118a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static final Executor processReaperExecutor = 119a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski doPrivileged(new PrivilegedAction<Executor>() { 120a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public Executor run() { 121a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return Executors.newCachedThreadPool 122a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski (new ProcessReaperThreadFactory()); 123a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski }}); 124a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 125a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski UNIXProcess(final byte[] prog, 126a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski final byte[] argBlock, final int argc, 127a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski final byte[] envBlock, final int envc, 128a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski final byte[] dir, 129a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski final int[] fds, 130a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski final boolean redirectErrorStream) 131a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski throws IOException { 132a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 133a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski pid = forkAndExec(prog, 134a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski argBlock, argc, 135a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski envBlock, envc, 136a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski dir, 137a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski fds, 138a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski redirectErrorStream); 139a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 140a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { 141a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski doPrivileged(new PrivilegedExceptionAction<Void>() { 142a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public Void run() throws IOException { 143a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski initStreams(fds); 144a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return null; 145a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski }}); 146a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } catch (PrivilegedActionException ex) { 147a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski throw (IOException) ex.getException(); 148a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 149a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 150a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 151a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski static FileDescriptor newFileDescriptor(int fd) { 152a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski FileDescriptor fileDescriptor = new FileDescriptor(); 153a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski fileDescriptor.setInt$(fd); 154a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return fileDescriptor; 155a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 156a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 157a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski void initStreams(int[] fds) throws IOException { 158a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski stdin = (fds[0] == -1) ? 159a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessBuilder.NullOutputStream.INSTANCE : 160a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski new ProcessPipeOutputStream(fds[0]); 161a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 162a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski stdout = (fds[1] == -1) ? 163a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessBuilder.NullInputStream.INSTANCE : 164a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski new ProcessPipeInputStream(fds[1]); 165a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 166a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski stderr = (fds[2] == -1) ? 167a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessBuilder.NullInputStream.INSTANCE : 168a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski new ProcessPipeInputStream(fds[2]); 169a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 170a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski processReaperExecutor.execute(new Runnable() { 171a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public void run() { 172a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski int exitcode = waitForProcessExit(pid); 173a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski UNIXProcess.this.processExited(exitcode); 174a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski }}); 175a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 176a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 177a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski void processExited(int exitcode) { 178a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski synchronized (this) { 179a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski this.exitcode = exitcode; 180a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski hasExited = true; 181a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski notifyAll(); 182a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 183a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 184a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (stdout instanceof ProcessPipeInputStream) 185a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ((ProcessPipeInputStream) stdout).processExited(); 186a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 187a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (stderr instanceof ProcessPipeInputStream) 188a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ((ProcessPipeInputStream) stderr).processExited(); 189a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 190a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (stdin instanceof ProcessPipeOutputStream) 191a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ((ProcessPipeOutputStream) stdin).processExited(); 192a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 193a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 194a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public OutputStream getOutputStream() { 195a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return stdin; 196a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 197a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 198a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public InputStream getInputStream() { 199a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return stdout; 200a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 201a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 202a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public InputStream getErrorStream() { 203a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return stderr; 204a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 205a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 206a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public synchronized int waitFor() throws InterruptedException { 207a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski while (!hasExited) { 208a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski wait(); 209a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 210a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return exitcode; 211a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 212a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 213a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public synchronized int exitValue() { 214a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (!hasExited) { 215a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski throw new IllegalThreadStateException("process hasn't exited"); 216a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 217a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return exitcode; 218a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 219a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 220a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static native void destroyProcess(int pid); 221a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski public void destroy() { 222a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // There is a risk that pid will be recycled, causing us to 223a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // kill the wrong process! So we only terminate processes 224a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // that appear to still be running. Even with this check, 225a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // there is an unavoidable race condition here, but the window 226a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // is very small, and OSes try hard to not recycle pids too 227a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // soon, so this is quite safe. 228a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski synchronized (this) { 229a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (!hasExited) 230a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski destroyProcess(pid); 231a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 232a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { stdin.close(); } catch (IOException ignored) {} 233a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { stdout.close(); } catch (IOException ignored) {} 234a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { stderr.close(); } catch (IOException ignored) {} 235a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 236a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 237dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath @Override 238dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath public String toString() { 239dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath StringBuilder sb = new StringBuilder("Process[pid="); 240dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath sb.append(pid); 241dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath if (hasExited) { 242dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath sb.append(" ,hasExited=true, exitcode="); 243dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath sb.append(exitcode); 244dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath sb.append("]"); 245dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath } else { 246dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath sb.append(", hasExited=false]"); 247dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath } 248dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath 249dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath return sb.toString(); 250dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath } 251dfbd40b1bd17f2aca05acd9d6e4902f7ca040256Narayan Kamath 252a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /* This routine initializes JNI field offsets for the class */ 253a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static native void initIDs(); 254a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 255a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski static { 256a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski initIDs(); 257a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 258a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 259a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** 260a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * A buffered input stream for a subprocess pipe file descriptor 261a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * that allows the underlying file descriptor to be reclaimed when 262a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * the process exits, via the processExited hook. 263a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * 264a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * This is tricky because we do not want the user-level InputStream to be 265a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * closed until the user invokes close(), and we need to continue to be 266a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * able to read any buffered data lingering in the OS pipe buffer. 267a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 268a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski static class ProcessPipeInputStream extends BufferedInputStream { 269a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessPipeInputStream(int fd) { 270af991c428d8d59496d7d621e5543b1914e1e363fNarayan Kamath super(new FileInputStream(newFileDescriptor(fd), true /* isFdOwner */)); 271a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 272a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 273a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski private static byte[] drainInputStream(InputStream in) 274a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski throws IOException { 275a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (in == null) return null; 276a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski int n = 0; 277a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski int j; 278a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski byte[] a = null; 279a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski while ((j = in.available()) > 0) { 280a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); 281a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski n += in.read(a, n, j); 282a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 283a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski return (a == null || n == a.length) ? a : Arrays.copyOf(a, n); 284a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 285a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 286a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** Called by the process reaper thread when the process exits. */ 287a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski synchronized void processExited() { 288a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // Most BufferedInputStream methods are synchronized, but close() 289a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // is not, and so we have to handle concurrent racing close(). 290a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { 291a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski InputStream in = this.in; 292a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (in != null) { 293a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski byte[] stragglers = drainInputStream(in); 294a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski in.close(); 295a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski this.in = (stragglers == null) ? 296a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessBuilder.NullInputStream.INSTANCE : 297a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski new ByteArrayInputStream(stragglers); 298a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (buf == null) // asynchronous close()? 299a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski this.in = null; 300a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 301a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } catch (IOException ignored) { 302a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // probably an asynchronous close(). 303a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 304a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 305a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 306a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 307a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** 308a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * A buffered output stream for a subprocess pipe file descriptor 309a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * that allows the underlying file descriptor to be reclaimed when 310a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski * the process exits, via the processExited hook. 311a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski */ 312a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski static class ProcessPipeOutputStream extends BufferedOutputStream { 313a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski ProcessPipeOutputStream(int fd) { 314e9d215bb0811633791ca53199922a8d5512de224Narayan Kamath super(new FileOutputStream(newFileDescriptor(fd), true /* isFdOwner */)); 315a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 316a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski 317a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski /** Called by the process reaper thread when the process exits. */ 318a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski synchronized void processExited() { 319a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski OutputStream out = this.out; 320a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski if (out != null) { 321a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski try { 322a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski out.close(); 323a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } catch (IOException ignored) { 324a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // We know of no reason to get an IOException, but if 325a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski // we do, there's nothing else to do but carry on. 326a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 327a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski this.out = ProcessBuilder.NullOutputStream.INSTANCE; 328a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 329a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 330a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski } 331a80f9aeb7b637fc241c75448eed08275245ec652Piotr Jastrzebski} 332