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