< prev index next >

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

Print this page
*** 44,10 ***
--- 44,13 ---
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.security.PrivilegedActionException;
  import java.security.PrivilegedExceptionAction;
  import java.util.Properties;
+ import java.util.concurrent.locks.Condition;
+ import java.util.concurrent.locks.ReentrantLock;
+ 
  import jdk.internal.access.JavaIOFileDescriptorAccess;
  import jdk.internal.access.SharedSecrets;
  import jdk.internal.util.StaticProperty;
  import sun.security.action.GetPropertyAction;
  

*** 70,10 ***
--- 73,13 ---
      private final int pid;
      private final ProcessHandleImpl processHandle;
      private int exitcode;
      private boolean hasExited;
  
+     private final ReentrantLock lock = new ReentrantLock();
+     private final Condition condition = lock.newCondition();
+ 
      private /* final */ OutputStream stdin;
      private /* final */ InputStream  stdout;
      private /* final */ InputStream  stderr;
  
      private static enum LaunchMechanism {

*** 359,14 ***
                  stderr = (fds[2] == -1) ?
                           ProcessBuilder.NullInputStream.INSTANCE :
                           new ProcessPipeInputStream(fds[2]);
  
                  ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
!                     synchronized (this) {
                          this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                          this.hasExited = true;
!                         this.notifyAll();
                      }
  
                      if (stdout instanceof ProcessPipeInputStream)
                          ((ProcessPipeInputStream) stdout).processExited();
  
--- 365,17 ---
                  stderr = (fds[2] == -1) ?
                           ProcessBuilder.NullInputStream.INSTANCE :
                           new ProcessPipeInputStream(fds[2]);
  
                  ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
!                     lock.lock();
+                     try {
                          this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                          this.hasExited = true;
!                         condition.signalAll();
+                     } finally {
+                         lock.unlock();
                      }
  
                      if (stdout instanceof ProcessPipeInputStream)
                          ((ProcessPipeInputStream) stdout).processExited();
  

*** 392,14 ***
                  stderr = (fds[2] == -1) ?
                           ProcessBuilder.NullInputStream.INSTANCE :
                           new DeferredCloseProcessPipeInputStream(fds[2]);
  
                  ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
!                     synchronized (this) {
                          this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                          this.hasExited = true;
!                         this.notifyAll();
                      }
  
                      if (stdout instanceof DeferredCloseProcessPipeInputStream)
                          ((DeferredCloseProcessPipeInputStream) stdout).processExited();
  
--- 401,17 ---
                  stderr = (fds[2] == -1) ?
                           ProcessBuilder.NullInputStream.INSTANCE :
                           new DeferredCloseProcessPipeInputStream(fds[2]);
  
                  ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
!                     lock.lock();
+                     try {
                          this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                          this.hasExited = true;
!                         condition.signalAll();
+                     } finally {
+                         lock.unlock();
                      }
  
                      if (stdout instanceof DeferredCloseProcessPipeInputStream)
                          ((DeferredCloseProcessPipeInputStream) stdout).processExited();
  

*** 427,41 ***
  
      public InputStream getErrorStream() {
          return stderr;
      }
  
!     public synchronized int waitFor() throws InterruptedException {
!         while (!hasExited) {
!             wait();
          }
-         return exitcode;
      }
  
!     @Override
-     public synchronized boolean waitFor(long timeout, TimeUnit unit)
          throws InterruptedException
      {
!         long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
!         if (hasExited) return true;
!         if (timeout <= 0) return false;
! 
!         long deadline = System.nanoTime() + remainingNanos;
-         do {
-             TimeUnit.NANOSECONDS.timedWait(this, remainingNanos);
-             if (hasExited) {
-                 return true;
              }
!             remainingNanos = deadline - System.nanoTime();
!         } while (remainingNanos > 0);
!         return hasExited;
      }
  
!     public synchronized int exitValue() {
!         if (!hasExited) {
!             throw new IllegalThreadStateException("process hasn't exited");
          }
-         return exitcode;
      }
  
      private void destroy(boolean force) {
          switch (platform) {
              case LINUX:
--- 439,47 ---
  
      public InputStream getErrorStream() {
          return stderr;
      }
  
!     public int waitFor() throws InterruptedException {
!         lock.lock();
!         try {
+             while (!hasExited) {
+                 condition.await();
+             }
+             return exitcode;
+         } finally {
+             lock.unlock();
          }
      }
  
!     public boolean waitFor(long timeout, TimeUnit unit)
          throws InterruptedException
      {
!         lock.lock();
!         try {
!             long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
!             while (remainingNanos > 0 && !hasExited) {
!                 remainingNanos = condition.awaitNanos(remainingNanos);
              }
!             return hasExited;
!         } finally {
!             lock.unlock();
+         }
      }
  
!     public int exitValue() {
!         lock.lock();
!         try {
+             if (!hasExited) {
+                 throw new IllegalThreadStateException("process hasn't exited");
+             }
+             return exitcode;
+         } finally {
+             lock.unlock();
          }
      }
  
      private void destroy(boolean force) {
          switch (platform) {
              case LINUX:

*** 471,13 ***
                  // kill the wrong process!  So we only terminate processes
                  // that appear to still be running.  Even with this check,
                  // there is an unavoidable race condition here, but the window
                  // is very small, and OSes try hard to not recycle pids too
                  // soon, so this is quite safe.
!                 synchronized (this) {
                      if (!hasExited)
                          processHandle.destroyProcess(force);
                  }
                  try { stdin.close();  } catch (IOException ignored) {}
                  try { stdout.close(); } catch (IOException ignored) {}
                  try { stderr.close(); } catch (IOException ignored) {}
                  break;
--- 489,16 ---
                  // kill the wrong process!  So we only terminate processes
                  // that appear to still be running.  Even with this check,
                  // there is an unavoidable race condition here, but the window
                  // is very small, and OSes try hard to not recycle pids too
                  // soon, so this is quite safe.
!                 lock.lock();
+                 try {
                      if (!hasExited)
                          processHandle.destroyProcess(force);
+                 } finally {
+                     lock.unlock();
                  }
                  try { stdin.close();  } catch (IOException ignored) {}
                  try { stdout.close(); } catch (IOException ignored) {}
                  try { stderr.close(); } catch (IOException ignored) {}
                  break;

*** 537,12 ***
      public long pid() {
          return pid;
      }
  
      @Override
!     public synchronized boolean isAlive() {
!         return !hasExited;
      }
  
      /**
       * The {@code toString} method returns a string consisting of
       * the native process ID of the process and the exit value of the process.
--- 558,17 ---
      public long pid() {
          return pid;
      }
  
      @Override
!     public boolean isAlive() {
!         lock.lock();
+         try {
+             return !hasExited;
+         } finally {
+             lock.unlock();
+         }
      }
  
      /**
       * The {@code toString} method returns a string consisting of
       * the native process ID of the process and the exit value of the process.
< prev index next >