1 /* 2 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.io.*; 29 30 /* java.lang.Process subclass in the UNIX environment. 31 * 32 * @author Mario Wolczko and Ross Knippel. 33 */ 34 35 final class UNIXProcess extends Process { 36 private static final sun.misc.JavaIOFileDescriptorAccess fdAccess 37 = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); 38 39 private final int pid; 40 private int exitcode; 41 private boolean hasExited; 42 43 private OutputStream stdin_stream; 44 private InputStream stdout_stream; 45 private DeferredCloseInputStream stdout_inner_stream; 46 private InputStream stderr_stream; 47 48 /* this is for the reaping thread */ 49 private native int waitForProcessExit(int pid); 50 51 /** 52 * Create a process using fork(2) and exec(2). 53 * 54 * @param std_fds array of file descriptors. Indexes 0, 1, and 55 * 2 correspond to standard input, standard output and 56 * standard error, respectively. On input, a value of -1 57 * means to create a pipe to connect child and parent 58 * processes. On output, a value which is not -1 is the 59 * parent pipe fd corresponding to the pipe which has 60 * been created. An element of this array is -1 on input 61 * if and only if it is <em>not</em> -1 on output. 62 * @return the pid of the subprocess 63 */ 64 private native int forkAndExec(byte[] prog, 65 byte[] argBlock, int argc, 66 byte[] envBlock, int envc, 67 byte[] dir, 68 int[] std_fds, 69 boolean redirectErrorStream) 70 throws IOException; 71 72 UNIXProcess(final byte[] prog, 73 final byte[] argBlock, int argc, 74 final byte[] envBlock, int envc, 75 final byte[] dir, 76 final int[] std_fds, 77 final boolean redirectErrorStream) 78 throws IOException { 79 pid = forkAndExec(prog, 80 argBlock, argc, 81 envBlock, envc, 82 dir, 83 std_fds, 84 redirectErrorStream); 85 86 java.security.AccessController.doPrivileged( 87 new java.security.PrivilegedAction<Void>() { public Void run() { 88 if (std_fds[0] == -1) 89 stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE; 90 else { 91 FileDescriptor stdin_fd = new FileDescriptor(); 92 fdAccess.set(stdin_fd, std_fds[0]); 93 stdin_stream = new BufferedOutputStream( 94 new FileOutputStream(stdin_fd)); 95 } 96 97 if (std_fds[1] == -1) 98 stdout_stream = ProcessBuilder.NullInputStream.INSTANCE; 99 else { 100 FileDescriptor stdout_fd = new FileDescriptor(); 101 fdAccess.set(stdout_fd, std_fds[1]); 102 stdout_inner_stream = new DeferredCloseInputStream(stdout_fd); 103 stdout_stream = new BufferedInputStream(stdout_inner_stream); 104 } 105 106 if (std_fds[2] == -1) 107 stderr_stream = ProcessBuilder.NullInputStream.INSTANCE; 108 else { 109 FileDescriptor stderr_fd = new FileDescriptor(); 110 fdAccess.set(stderr_fd, std_fds[2]); 111 stderr_stream = new DeferredCloseInputStream(stderr_fd); 112 } 113 114 return null; }}); 115 116 /* 117 * For each subprocess forked a corresponding reaper thread 118 * is started. That thread is the only thread which waits 119 * for the subprocess to terminate and it doesn't hold any 120 * locks while doing so. This design allows waitFor() and 121 * exitStatus() to be safely executed in parallel (and they 122 * need no native code). 123 */ 124 125 java.security.AccessController.doPrivileged( 126 new java.security.PrivilegedAction<Void>() { public Void run() { 127 Thread t = new Thread("process reaper") { 128 public void run() { 129 int res = waitForProcessExit(pid); 130 synchronized (UNIXProcess.this) { 131 hasExited = true; 132 exitcode = res; 133 UNIXProcess.this.notifyAll(); 134 } 135 } 136 }; 137 t.setDaemon(true); 138 t.start(); 139 return null; }}); 140 } 141 142 public OutputStream getOutputStream() { 143 return stdin_stream; 144 } 145 146 public InputStream getInputStream() { 147 return stdout_stream; 148 } 149 150 public InputStream getErrorStream() { 151 return stderr_stream; 152 } 153 154 public synchronized int waitFor() throws InterruptedException { 155 while (!hasExited) { 156 wait(); 157 } 158 return exitcode; 159 } 160 161 public synchronized int exitValue() { 162 if (!hasExited) { 163 throw new IllegalThreadStateException("process hasn't exited"); 164 } 165 return exitcode; 166 } 167 168 private static native void destroyProcess(int pid); 169 public synchronized void destroy() { 170 // There is a risk that pid will be recycled, causing us to 171 // kill the wrong process! So we only terminate processes 172 // that appear to still be running. Even with this check, 173 // there is an unavoidable race condition here, but the window 174 // is very small, and OSes try hard to not recycle pids too 175 // soon, so this is quite safe. 176 if (!hasExited) 177 destroyProcess(pid); 178 try { 179 stdin_stream.close(); 180 if (stdout_inner_stream != null) 181 stdout_inner_stream.closeDeferred(stdout_stream); 182 if (stderr_stream instanceof DeferredCloseInputStream) 183 ((DeferredCloseInputStream) stderr_stream) 184 .closeDeferred(stderr_stream); 185 } catch (IOException e) { 186 // ignore 187 } 188 } 189 190 // A FileInputStream that supports the deferment of the actual close 191 // operation until the last pending I/O operation on the stream has 192 // finished. This is required on Solaris because we must close the stdin 193 // and stdout streams in the destroy method in order to reclaim the 194 // underlying file descriptors. Doing so, however, causes any thread 195 // currently blocked in a read on one of those streams to receive an 196 // IOException("Bad file number"), which is incompatible with historical 197 // behavior. By deferring the close we allow any pending reads to see -1 198 // (EOF) as they did before. 199 // 200 private static class DeferredCloseInputStream 201 extends FileInputStream 202 { 203 204 private DeferredCloseInputStream(FileDescriptor fd) { 205 super(fd); 206 } 207 208 private Object lock = new Object(); // For the following fields 209 private boolean closePending = false; 210 private int useCount = 0; 211 private InputStream streamToClose; 212 213 private void raise() { 214 synchronized (lock) { 215 useCount++; 216 } 217 } 218 219 private void lower() throws IOException { 220 synchronized (lock) { 221 useCount--; 222 if (useCount == 0 && closePending) { 223 streamToClose.close(); 224 } 225 } 226 } 227 228 // stc is the actual stream to be closed; it might be this object, or 229 // it might be an upstream object for which this object is downstream. 230 // 231 private void closeDeferred(InputStream stc) throws IOException { 232 synchronized (lock) { 233 if (useCount == 0) { 234 stc.close(); 235 } else { 236 closePending = true; 237 streamToClose = stc; 238 } 239 } 240 } 241 242 public void close() throws IOException { 243 synchronized (lock) { 244 useCount = 0; 245 closePending = false; 246 } 247 super.close(); 248 } 249 250 public int read() throws IOException { 251 raise(); 252 try { 253 return super.read(); 254 } finally { 255 lower(); 256 } 257 } 258 259 public int read(byte[] b) throws IOException { 260 raise(); 261 try { 262 return super.read(b); 263 } finally { 264 lower(); 265 } 266 } 267 268 public int read(byte[] b, int off, int len) throws IOException { 269 raise(); 270 try { 271 return super.read(b, off, len); 272 } finally { 273 lower(); 274 } 275 } 276 277 public long skip(long n) throws IOException { 278 raise(); 279 try { 280 return super.skip(n); 281 } finally { 282 lower(); 283 } 284 } 285 286 public int available() throws IOException { 287 raise(); 288 try { 289 return super.available(); 290 } finally { 291 lower(); 292 } 293 } 294 295 } 296 297 /* This routine initializes JNI field offsets for the class */ 298 private static native void initIDs(); 299 300 static { 301 initIDs(); 302 } 303 }