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

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

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

@@ -471,13 +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.
-                 synchronized (this) {
+                 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 +558,17 @@
      public long pid() {
          return pid;
      }
  
      @Override
-     public synchronized boolean isAlive() {
-         return !hasExited;
+     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 >