< prev index next >

src/java.base/unix/classes/java/lang/ProcessImpl.java

Print this page

 29 import java.io.BufferedInputStream;
 30 import java.io.BufferedOutputStream;
 31 import java.io.ByteArrayInputStream;
 32 import java.io.FileDescriptor;
 33 import java.io.FileInputStream;
 34 import java.io.FileOutputStream;
 35 import java.io.IOException;
 36 import java.io.InputStream;
 37 import java.io.OutputStream;
 38 import java.util.Arrays;
 39 import java.util.EnumSet;
 40 import java.util.Locale;
 41 import java.util.Set;
 42 import java.util.concurrent.CompletableFuture;
 43 import java.util.concurrent.TimeUnit;
 44 import java.security.AccessController;
 45 import java.security.PrivilegedAction;
 46 import java.security.PrivilegedActionException;
 47 import java.security.PrivilegedExceptionAction;
 48 import java.util.Properties;



 49 import jdk.internal.access.JavaIOFileDescriptorAccess;
 50 import jdk.internal.access.SharedSecrets;
 51 import jdk.internal.util.StaticProperty;
 52 import sun.security.action.GetPropertyAction;
 53 
 54 /**
 55  * java.lang.Process subclass in the UNIX environment.
 56  *
 57  * @author Mario Wolczko and Ross Knippel.
 58  * @author Konstantin Kladko (ported to Linux and Bsd)
 59  * @author Martin Buchholz
 60  * @author Volker Simonis (ported to AIX)
 61  * @since   1.5
 62  */
 63 final class ProcessImpl extends Process {
 64     private static final JavaIOFileDescriptorAccess fdAccess
 65         = SharedSecrets.getJavaIOFileDescriptorAccess();
 66 
 67     // Linux platforms support a normal (non-forcible) kill signal.
 68     static final boolean SUPPORTS_NORMAL_TERMINATION = true;
 69 
 70     private final int pid;
 71     private final ProcessHandleImpl processHandle;
 72     private int exitcode;
 73     private boolean hasExited;
 74 



 75     private /* final */ OutputStream stdin;
 76     private /* final */ InputStream  stdout;
 77     private /* final */ InputStream  stderr;
 78 
 79     private static enum LaunchMechanism {
 80         // order IS important!
 81         FORK,
 82         POSIX_SPAWN,
 83         VFORK
 84     }
 85 
 86     private static enum Platform {
 87 
 88         LINUX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.VFORK, LaunchMechanism.FORK),
 89 
 90         BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
 91 
 92         AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
 93 
 94         final LaunchMechanism defaultLaunchMechanism;

344      *        a subsequent process. The stdout stream should be a null output stream .
345      * @throws IOException
346      */
347     void initStreams(int[] fds, boolean forceNullOutputStream) throws IOException {
348         switch (platform) {
349             case LINUX:
350             case BSD:
351                 stdin = (fds[0] == -1) ?
352                         ProcessBuilder.NullOutputStream.INSTANCE :
353                         new ProcessPipeOutputStream(fds[0]);
354 
355                 stdout = (fds[1] == -1 || forceNullOutputStream) ?
356                          ProcessBuilder.NullInputStream.INSTANCE :
357                          new ProcessPipeInputStream(fds[1]);
358 
359                 stderr = (fds[2] == -1) ?
360                          ProcessBuilder.NullInputStream.INSTANCE :
361                          new ProcessPipeInputStream(fds[2]);
362 
363                 ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
364                     synchronized (this) {

365                         this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
366                         this.hasExited = true;
367                         this.notifyAll();


368                     }
369 
370                     if (stdout instanceof ProcessPipeInputStream)
371                         ((ProcessPipeInputStream) stdout).processExited();
372 
373                     if (stderr instanceof ProcessPipeInputStream)
374                         ((ProcessPipeInputStream) stderr).processExited();
375 
376                     if (stdin instanceof ProcessPipeOutputStream)
377                         ((ProcessPipeOutputStream) stdin).processExited();
378 
379                     return null;
380                 });
381                 break;
382 
383             case AIX:
384                 stdin = (fds[0] == -1) ?
385                         ProcessBuilder.NullOutputStream.INSTANCE :
386                         new ProcessPipeOutputStream(fds[0]);
387 
388                 stdout = (fds[1] == -1 || forceNullOutputStream) ?
389                          ProcessBuilder.NullInputStream.INSTANCE :
390                          new DeferredCloseProcessPipeInputStream(fds[1]);
391 
392                 stderr = (fds[2] == -1) ?
393                          ProcessBuilder.NullInputStream.INSTANCE :
394                          new DeferredCloseProcessPipeInputStream(fds[2]);
395 
396                 ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
397                     synchronized (this) {

398                         this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
399                         this.hasExited = true;
400                         this.notifyAll();


401                     }
402 
403                     if (stdout instanceof DeferredCloseProcessPipeInputStream)
404                         ((DeferredCloseProcessPipeInputStream) stdout).processExited();
405 
406                     if (stderr instanceof DeferredCloseProcessPipeInputStream)
407                         ((DeferredCloseProcessPipeInputStream) stderr).processExited();
408 
409                     if (stdin instanceof ProcessPipeOutputStream)
410                         ((ProcessPipeOutputStream) stdin).processExited();
411 
412                     return null;
413                 });
414                 break;
415 
416             default: throw new AssertionError("Unsupported platform: " + platform);
417         }
418     }
419 
420     public OutputStream getOutputStream() {
421         return stdin;
422     }
423 
424     public InputStream getInputStream() {
425         return stdout;
426     }
427 
428     public InputStream getErrorStream() {
429         return stderr;
430     }
431 
432     public synchronized int waitFor() throws InterruptedException {
433         while (!hasExited) {
434             wait();






435         }
436         return exitcode;
437     }
438 
439     @Override
440     public synchronized boolean waitFor(long timeout, TimeUnit unit)
441         throws InterruptedException
442     {
443         long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
444         if (hasExited) return true;
445         if (timeout <= 0) return false;
446 
447         long deadline = System.nanoTime() + remainingNanos;
448         do {
449             TimeUnit.NANOSECONDS.timedWait(this, remainingNanos);
450             if (hasExited) {
451                 return true;
452             }
453             remainingNanos = deadline - System.nanoTime();
454         } while (remainingNanos > 0);
455         return hasExited;

456     }
457 
458     public synchronized int exitValue() {
459         if (!hasExited) {
460             throw new IllegalThreadStateException("process hasn't exited");






461         }
462         return exitcode;
463     }
464 
465     private void destroy(boolean force) {
466         switch (platform) {
467             case LINUX:
468             case BSD:
469             case AIX:
470                 // There is a risk that pid will be recycled, causing us to
471                 // kill the wrong process!  So we only terminate processes
472                 // that appear to still be running.  Even with this check,
473                 // there is an unavoidable race condition here, but the window
474                 // is very small, and OSes try hard to not recycle pids too
475                 // soon, so this is quite safe.
476                 synchronized (this) {

477                     if (!hasExited)
478                         processHandle.destroyProcess(force);


479                 }
480                 try { stdin.close();  } catch (IOException ignored) {}
481                 try { stdout.close(); } catch (IOException ignored) {}
482                 try { stderr.close(); } catch (IOException ignored) {}
483                 break;
484 
485             default: throw new AssertionError("Unsupported platform: " + platform);
486         }
487     }
488 
489     @Override
490     public CompletableFuture<Process> onExit() {
491         return ProcessHandleImpl.completion(pid, false)
492                 .handleAsync((unusedExitStatus, unusedThrowable) -> {
493                     boolean interrupted = false;
494                     while (true) {
495                         // Ensure that the concurrent task setting the exit status has completed
496                         try {
497                             waitFor();
498                             break;

522         return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
523     }
524 
525     @Override
526     public void destroy() {
527         destroy(false);
528     }
529 
530     @Override
531     public Process destroyForcibly() {
532         destroy(true);
533         return this;
534     }
535 
536     @Override
537     public long pid() {
538         return pid;
539     }
540 
541     @Override
542     public synchronized boolean isAlive() {
543         return !hasExited;





544     }
545 
546     /**
547      * The {@code toString} method returns a string consisting of
548      * the native process ID of the process and the exit value of the process.
549      *
550      * @return a string representation of the object.
551      */
552     @Override
553     public String toString() {
554         return new StringBuilder("Process[pid=").append(pid)
555                 .append(", exitValue=").append(hasExited ? exitcode : "\"not exited\"")
556                 .append("]").toString();
557     }
558 
559     private static native void init();
560 
561     static {
562         init();
563     }

 29 import java.io.BufferedInputStream;
 30 import java.io.BufferedOutputStream;
 31 import java.io.ByteArrayInputStream;
 32 import java.io.FileDescriptor;
 33 import java.io.FileInputStream;
 34 import java.io.FileOutputStream;
 35 import java.io.IOException;
 36 import java.io.InputStream;
 37 import java.io.OutputStream;
 38 import java.util.Arrays;
 39 import java.util.EnumSet;
 40 import java.util.Locale;
 41 import java.util.Set;
 42 import java.util.concurrent.CompletableFuture;
 43 import java.util.concurrent.TimeUnit;
 44 import java.security.AccessController;
 45 import java.security.PrivilegedAction;
 46 import java.security.PrivilegedActionException;
 47 import java.security.PrivilegedExceptionAction;
 48 import java.util.Properties;
 49 import java.util.concurrent.locks.Condition;
 50 import java.util.concurrent.locks.ReentrantLock;
 51 
 52 import jdk.internal.access.JavaIOFileDescriptorAccess;
 53 import jdk.internal.access.SharedSecrets;
 54 import jdk.internal.util.StaticProperty;
 55 import sun.security.action.GetPropertyAction;
 56 
 57 /**
 58  * java.lang.Process subclass in the UNIX environment.
 59  *
 60  * @author Mario Wolczko and Ross Knippel.
 61  * @author Konstantin Kladko (ported to Linux and Bsd)
 62  * @author Martin Buchholz
 63  * @author Volker Simonis (ported to AIX)
 64  * @since   1.5
 65  */
 66 final class ProcessImpl extends Process {
 67     private static final JavaIOFileDescriptorAccess fdAccess
 68         = SharedSecrets.getJavaIOFileDescriptorAccess();
 69 
 70     // Linux platforms support a normal (non-forcible) kill signal.
 71     static final boolean SUPPORTS_NORMAL_TERMINATION = true;
 72 
 73     private final int pid;
 74     private final ProcessHandleImpl processHandle;
 75     private int exitcode;
 76     private boolean hasExited;
 77 
 78     private final ReentrantLock lock = new ReentrantLock();
 79     private final Condition condition = lock.newCondition();
 80 
 81     private /* final */ OutputStream stdin;
 82     private /* final */ InputStream  stdout;
 83     private /* final */ InputStream  stderr;
 84 
 85     private static enum LaunchMechanism {
 86         // order IS important!
 87         FORK,
 88         POSIX_SPAWN,
 89         VFORK
 90     }
 91 
 92     private static enum Platform {
 93 
 94         LINUX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.VFORK, LaunchMechanism.FORK),
 95 
 96         BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
 97 
 98         AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
 99 
100         final LaunchMechanism defaultLaunchMechanism;

350      *        a subsequent process. The stdout stream should be a null output stream .
351      * @throws IOException
352      */
353     void initStreams(int[] fds, boolean forceNullOutputStream) throws IOException {
354         switch (platform) {
355             case LINUX:
356             case BSD:
357                 stdin = (fds[0] == -1) ?
358                         ProcessBuilder.NullOutputStream.INSTANCE :
359                         new ProcessPipeOutputStream(fds[0]);
360 
361                 stdout = (fds[1] == -1 || forceNullOutputStream) ?
362                          ProcessBuilder.NullInputStream.INSTANCE :
363                          new ProcessPipeInputStream(fds[1]);
364 
365                 stderr = (fds[2] == -1) ?
366                          ProcessBuilder.NullInputStream.INSTANCE :
367                          new ProcessPipeInputStream(fds[2]);
368 
369                 ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
370                     lock.lock();
371                     try {
372                         this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
373                         this.hasExited = true;
374                         condition.signalAll();
375                     } finally {
376                         lock.unlock();
377                     }
378 
379                     if (stdout instanceof ProcessPipeInputStream)
380                         ((ProcessPipeInputStream) stdout).processExited();
381 
382                     if (stderr instanceof ProcessPipeInputStream)
383                         ((ProcessPipeInputStream) stderr).processExited();
384 
385                     if (stdin instanceof ProcessPipeOutputStream)
386                         ((ProcessPipeOutputStream) stdin).processExited();
387 
388                     return null;
389                 });
390                 break;
391 
392             case AIX:
393                 stdin = (fds[0] == -1) ?
394                         ProcessBuilder.NullOutputStream.INSTANCE :
395                         new ProcessPipeOutputStream(fds[0]);
396 
397                 stdout = (fds[1] == -1 || forceNullOutputStream) ?
398                          ProcessBuilder.NullInputStream.INSTANCE :
399                          new DeferredCloseProcessPipeInputStream(fds[1]);
400 
401                 stderr = (fds[2] == -1) ?
402                          ProcessBuilder.NullInputStream.INSTANCE :
403                          new DeferredCloseProcessPipeInputStream(fds[2]);
404 
405                 ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
406                     lock.lock();
407                     try {
408                         this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
409                         this.hasExited = true;
410                         condition.signalAll();
411                     } finally {
412                         lock.unlock();
413                     }
414 
415                     if (stdout instanceof DeferredCloseProcessPipeInputStream)
416                         ((DeferredCloseProcessPipeInputStream) stdout).processExited();
417 
418                     if (stderr instanceof DeferredCloseProcessPipeInputStream)
419                         ((DeferredCloseProcessPipeInputStream) stderr).processExited();
420 
421                     if (stdin instanceof ProcessPipeOutputStream)
422                         ((ProcessPipeOutputStream) stdin).processExited();
423 
424                     return null;
425                 });
426                 break;
427 
428             default: throw new AssertionError("Unsupported platform: " + platform);
429         }
430     }
431 
432     public OutputStream getOutputStream() {
433         return stdin;
434     }
435 
436     public InputStream getInputStream() {
437         return stdout;
438     }
439 
440     public InputStream getErrorStream() {
441         return stderr;
442     }
443 
444     public int waitFor() throws InterruptedException {
445         lock.lock();
446         try {
447             while (!hasExited) {
448                 condition.await();
449             }
450             return exitcode;
451         } finally {
452             lock.unlock();
453         }

454     }
455 
456     public boolean waitFor(long timeout, TimeUnit unit)

457         throws InterruptedException
458     {
459         lock.lock();
460         try {
461             long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
462             while (remainingNanos > 0 && !hasExited) {
463                 remainingNanos = condition.awaitNanos(remainingNanos);




464             }
465             return hasExited;
466         } finally {
467             lock.unlock();
468         }
469     }
470 
471     public int exitValue() {
472         lock.lock();
473         try {
474             if (!hasExited) {
475                 throw new IllegalThreadStateException("process hasn't exited");
476             }
477             return exitcode;
478         } finally {
479             lock.unlock();
480         }

481     }
482 
483     private void destroy(boolean force) {
484         switch (platform) {
485             case LINUX:
486             case BSD:
487             case AIX:
488                 // There is a risk that pid will be recycled, causing us to
489                 // kill the wrong process!  So we only terminate processes
490                 // that appear to still be running.  Even with this check,
491                 // there is an unavoidable race condition here, but the window
492                 // is very small, and OSes try hard to not recycle pids too
493                 // soon, so this is quite safe.
494                 lock.lock();
495                 try {
496                     if (!hasExited)
497                         processHandle.destroyProcess(force);
498                 } finally {
499                     lock.unlock();
500                 }
501                 try { stdin.close();  } catch (IOException ignored) {}
502                 try { stdout.close(); } catch (IOException ignored) {}
503                 try { stderr.close(); } catch (IOException ignored) {}
504                 break;
505 
506             default: throw new AssertionError("Unsupported platform: " + platform);
507         }
508     }
509 
510     @Override
511     public CompletableFuture<Process> onExit() {
512         return ProcessHandleImpl.completion(pid, false)
513                 .handleAsync((unusedExitStatus, unusedThrowable) -> {
514                     boolean interrupted = false;
515                     while (true) {
516                         // Ensure that the concurrent task setting the exit status has completed
517                         try {
518                             waitFor();
519                             break;

543         return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
544     }
545 
546     @Override
547     public void destroy() {
548         destroy(false);
549     }
550 
551     @Override
552     public Process destroyForcibly() {
553         destroy(true);
554         return this;
555     }
556 
557     @Override
558     public long pid() {
559         return pid;
560     }
561 
562     @Override
563     public boolean isAlive() {
564         lock.lock();
565         try {
566             return !hasExited;
567         } finally {
568             lock.unlock();
569         }
570     }
571 
572     /**
573      * The {@code toString} method returns a string consisting of
574      * the native process ID of the process and the exit value of the process.
575      *
576      * @return a string representation of the object.
577      */
578     @Override
579     public String toString() {
580         return new StringBuilder("Process[pid=").append(pid)
581                 .append(", exitValue=").append(hasExited ? exitcode : "\"not exited\"")
582                 .append("]").toString();
583     }
584 
585     private static native void init();
586 
587     static {
588         init();
589     }
< prev index next >