1 /*
   2  * Copyright (c) 1995, 2013, 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 import java.util.concurrent.TimeUnit;
  30 import java.security.AccessController;
  31 import java.security.PrivilegedAction;
  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     private static enum LaunchMechanism {
  52         FORK(1),
  53         POSIX_SPAWN(2);
  54 
  55         private int value;
  56         LaunchMechanism(int x) {value = x;}
  57     };
  58 
  59     /* On Solaris, the default is to spawn */
  60     private static final LaunchMechanism launchMechanism;
  61     private static byte[] helperpath;
  62 
  63     private static byte[] toCString(String s) {
  64         if (s == null)
  65             return null;
  66         byte[] bytes = s.getBytes();
  67         byte[] result = new byte[bytes.length + 1];
  68         System.arraycopy(bytes, 0,
  69                          result, 0,
  70                          bytes.length);
  71         result[result.length-1] = (byte)0;
  72         return result;
  73     }
  74 
  75     static {
  76         launchMechanism = AccessController.doPrivileged(
  77                 new PrivilegedAction<LaunchMechanism>()
  78         {
  79             public LaunchMechanism run() {
  80                 String javahome = System.getProperty("java.home");
  81                 String osArch = System.getProperty("os.arch");
  82                 if (osArch.equals("x86")) {
  83                     osArch = "i386";
  84                 } else if (osArch.equals("x86_64")) {
  85                     osArch = "amd64";
  86                 }
  87 
  88                 helperpath = toCString(javahome + "/lib/" + osArch + "/jspawnhelper");
  89                 String s = System.getProperty(
  90                     "jdk.lang.Process.launchMechanism", "posix_spawn");
  91 
  92                 try {
  93                     return LaunchMechanism.valueOf(s.toUpperCase());
  94                 } catch (IllegalArgumentException e) {
  95                     throw new Error(s + " is not a supported " +
  96                         "process launch mechanism on this platform.");
  97                 }
  98             }
  99         });
 100     }
 101 
 102     /* this is for the reaping thread */
 103     private native int waitForProcessExit(int pid);
 104 
 105     /**
 106      * Create a process. Depending on the mode flag, this is done by
 107      * one of the following mechanisms.
 108      * - fork(2) and exec(2)
 109      * - posix_spawn(2)
 110      *
 111      * @param std_fds array of file descriptors.  Indexes 0, 1, and
 112      *        2 correspond to standard input, standard output and
 113      *        standard error, respectively.  On input, a value of -1
 114      *        means to create a pipe to connect child and parent
 115      *        processes.  On output, a value which is not -1 is the
 116      *        parent pipe fd corresponding to the pipe which has
 117      *        been created.  An element of this array is -1 on input
 118      *        if and only if it is <em>not</em> -1 on output.
 119      * @return the pid of the subprocess
 120      */
 121     private native int forkAndExec(int mode, byte[] helperpath,
 122                                    byte[] prog,
 123                                    byte[] argBlock, int argc,
 124                                    byte[] envBlock, int envc,
 125                                    byte[] dir,
 126                                    int[] std_fds,
 127                                    boolean redirectErrorStream)
 128         throws IOException;
 129 
 130     UNIXProcess(final byte[] prog,
 131                 final byte[] argBlock, int argc,
 132                 final byte[] envBlock, int envc,
 133                 final byte[] dir,
 134                 final int[] std_fds,
 135                 final boolean redirectErrorStream)
 136     throws IOException {
 137         pid = forkAndExec(launchMechanism.value,
 138                           helperpath,
 139                           prog,
 140                           argBlock, argc,
 141                           envBlock, envc,
 142                           dir,
 143                           std_fds,
 144                           redirectErrorStream);
 145 
 146         java.security.AccessController.doPrivileged(
 147         new java.security.PrivilegedAction<Void>() { public Void run() {
 148             if (std_fds[0] == -1)
 149                 stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
 150             else {
 151                 FileDescriptor stdin_fd = new FileDescriptor();
 152                 fdAccess.set(stdin_fd, std_fds[0]);
 153                 stdin_stream = new BufferedOutputStream(
 154                     new FileOutputStream(stdin_fd));
 155             }
 156 
 157             if (std_fds[1] == -1)
 158                 stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
 159             else {
 160                 FileDescriptor stdout_fd = new FileDescriptor();
 161                 fdAccess.set(stdout_fd, std_fds[1]);
 162                 stdout_inner_stream = new DeferredCloseInputStream(stdout_fd);
 163                 stdout_stream = new BufferedInputStream(stdout_inner_stream);
 164             }
 165 
 166             if (std_fds[2] == -1)
 167                 stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
 168             else {
 169                 FileDescriptor stderr_fd = new FileDescriptor();
 170                 fdAccess.set(stderr_fd, std_fds[2]);
 171                 stderr_stream = new DeferredCloseInputStream(stderr_fd);
 172             }
 173 
 174             return null; }});
 175 
 176         /*
 177          * For each subprocess forked a corresponding reaper thread
 178          * is started.  That thread is the only thread which waits
 179          * for the subprocess to terminate and it doesn't hold any
 180          * locks while doing so.  This design allows waitFor() and
 181          * exitStatus() to be safely executed in parallel (and they
 182          * need no native code).
 183          */
 184 
 185         java.security.AccessController.doPrivileged(
 186             new java.security.PrivilegedAction<Void>() { public Void run() {
 187                 Thread t = new Thread("process reaper") {
 188                     public void run() {
 189                         int res = waitForProcessExit(pid);
 190                         synchronized (UNIXProcess.this) {
 191                             hasExited = true;
 192                             exitcode = res;
 193                             UNIXProcess.this.notifyAll();
 194                         }
 195                     }
 196                 };
 197                 t.setDaemon(true);
 198                 t.start();
 199                 return null; }});
 200     }
 201 
 202     public OutputStream getOutputStream() {
 203         return stdin_stream;
 204     }
 205 
 206     public InputStream getInputStream() {
 207         return stdout_stream;
 208     }
 209 
 210     public InputStream getErrorStream() {
 211         return stderr_stream;
 212     }
 213 
 214     public synchronized int waitFor() throws InterruptedException {
 215         while (!hasExited) {
 216             wait();
 217         }
 218         return exitcode;
 219     }
 220 
 221     @Override
 222     public synchronized boolean waitFor(long timeout, TimeUnit unit)
 223         throws InterruptedException
 224     {
 225         if (hasExited) return true;
 226         if (timeout <= 0) return false;
 227 
 228         long timeoutAsNanos = unit.toNanos(timeout);
 229         long startTime = System.nanoTime();
 230         long rem = timeoutAsNanos;
 231 
 232         while (!hasExited && (rem > 0)) {
 233             wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
 234             rem = timeoutAsNanos - (System.nanoTime() - startTime);
 235         }
 236         return hasExited;
 237     }
 238 
 239     public synchronized int exitValue() {
 240         if (!hasExited) {
 241             throw new IllegalThreadStateException("process hasn't exited");
 242         }
 243         return exitcode;
 244     }
 245 
 246     private static native void destroyProcess(int pid, boolean force);
 247     private synchronized void destroy(boolean force) {
 248         // There is a risk that pid will be recycled, causing us to
 249         // kill the wrong process!  So we only terminate processes
 250         // that appear to still be running.  Even with this check,
 251         // there is an unavoidable race condition here, but the window
 252         // is very small, and OSes try hard to not recycle pids too
 253         // soon, so this is quite safe.
 254         if (!hasExited)
 255             destroyProcess(pid, force);
 256         try {
 257             stdin_stream.close();
 258             if (stdout_inner_stream != null)
 259                 stdout_inner_stream.closeDeferred(stdout_stream);
 260             if (stderr_stream instanceof DeferredCloseInputStream)
 261                 ((DeferredCloseInputStream) stderr_stream)
 262                     .closeDeferred(stderr_stream);
 263         } catch (IOException e) {
 264             // ignore
 265         }
 266     }
 267 
 268     public void destroy() {
 269         destroy(false);
 270     }
 271 
 272     @Override
 273     public Process destroyForcibly() {
 274         destroy(true);
 275         return this;
 276     }
 277 
 278     @Override
 279     public synchronized boolean isAlive() {
 280         return !hasExited;
 281     }
 282 
 283     // A FileInputStream that supports the deferment of the actual close
 284     // operation until the last pending I/O operation on the stream has
 285     // finished.  This is required on Solaris because we must close the stdin
 286     // and stdout streams in the destroy method in order to reclaim the
 287     // underlying file descriptors.  Doing so, however, causes any thread
 288     // currently blocked in a read on one of those streams to receive an
 289     // IOException("Bad file number"), which is incompatible with historical
 290     // behavior.  By deferring the close we allow any pending reads to see -1
 291     // (EOF) as they did before.
 292     //
 293     private static class DeferredCloseInputStream
 294         extends FileInputStream
 295     {
 296 
 297         private DeferredCloseInputStream(FileDescriptor fd) {
 298             super(fd);
 299         }
 300 
 301         private Object lock = new Object();     // For the following fields
 302         private boolean closePending = false;
 303         private int useCount = 0;
 304         private InputStream streamToClose;
 305 
 306         private void raise() {
 307             synchronized (lock) {
 308                 useCount++;
 309             }
 310         }
 311 
 312         private void lower() throws IOException {
 313             synchronized (lock) {
 314                 useCount--;
 315                 if (useCount == 0 && closePending) {
 316                     streamToClose.close();
 317                 }
 318             }
 319         }
 320 
 321         // stc is the actual stream to be closed; it might be this object, or
 322         // it might be an upstream object for which this object is downstream.
 323         //
 324         private void closeDeferred(InputStream stc) throws IOException {
 325             synchronized (lock) {
 326                 if (useCount == 0) {
 327                     stc.close();
 328                 } else {
 329                     closePending = true;
 330                     streamToClose = stc;
 331                 }
 332             }
 333         }
 334 
 335         public void close() throws IOException {
 336             synchronized (lock) {
 337                 useCount = 0;
 338                 closePending = false;
 339             }
 340             super.close();
 341         }
 342 
 343         public int read() throws IOException {
 344             raise();
 345             try {
 346                 return super.read();
 347             } finally {
 348                 lower();
 349             }
 350         }
 351 
 352         public int read(byte[] b) throws IOException {
 353             raise();
 354             try {
 355                 return super.read(b);
 356             } finally {
 357                 lower();
 358             }
 359         }
 360 
 361         public int read(byte[] b, int off, int len) throws IOException {
 362             raise();
 363             try {
 364                 return super.read(b, off, len);
 365             } finally {
 366                 lower();
 367             }
 368         }
 369 
 370         public long skip(long n) throws IOException {
 371             raise();
 372             try {
 373                 return super.skip(n);
 374             } finally {
 375                 lower();
 376             }
 377         }
 378 
 379         public int available() throws IOException {
 380             raise();
 381             try {
 382                 return super.available();
 383             } finally {
 384                 lower();
 385             }
 386         }
 387 
 388     }
 389 
 390     private static native void init();
 391 
 392     static {
 393         init();
 394     }
 395 }