8208715: Conversion of milliseconds to nanoseconds in UNIXProcess contains bug
authorrriggs
Wed, 15 Aug 2018 10:38:27 -0400
changeset 51422 41257a58a588
parent 51421 ef57958c7c51
child 51423 b2319bbcc867
8208715: Conversion of milliseconds to nanoseconds in UNIXProcess contains bug Reviewed-by: martin
src/java.base/unix/classes/java/lang/ProcessImpl.java
src/java.base/windows/classes/java/lang/ProcessImpl.java
src/java.base/windows/native/libjava/ProcessImpl_md.c
test/jdk/java/lang/ProcessBuilder/Basic.java
--- a/src/java.base/unix/classes/java/lang/ProcessImpl.java	Thu Aug 16 16:06:54 2018 +0530
+++ b/src/java.base/unix/classes/java/lang/ProcessImpl.java	Wed Aug 15 10:38:27 2018 -0400
@@ -507,8 +507,7 @@
 
         long deadline = System.nanoTime() + remainingNanos;
         do {
-            // Round up to next millisecond
-            wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L));
+            TimeUnit.NANOSECONDS.timedWait(this, remainingNanos);
             if (hasExited) {
                 return true;
             }
--- a/src/java.base/windows/classes/java/lang/ProcessImpl.java	Thu Aug 16 16:06:54 2018 +0530
+++ b/src/java.base/windows/classes/java/lang/ProcessImpl.java	Wed Aug 15 10:38:27 2018 -0400
@@ -497,10 +497,14 @@
         if (getExitCodeProcess(handle) != STILL_ACTIVE) return true;
         if (timeout <= 0) return false;
 
-        long deadline = System.nanoTime() + remainingNanos ;
+        long deadline = System.nanoTime() + remainingNanos;
         do {
             // Round up to next millisecond
             long msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L);
+            if (msTimeout < 0) {
+                // if wraps around then wait a long while
+                msTimeout = Integer.MAX_VALUE;
+            }
             waitForTimeoutInterruptibly(handle, msTimeout);
             if (Thread.interrupted())
                 throw new InterruptedException();
@@ -514,7 +518,7 @@
     }
 
     private static native void waitForTimeoutInterruptibly(
-        long handle, long timeout);
+        long handle, long timeoutMillis);
 
     @Override
     public void destroy() {
--- a/src/java.base/windows/native/libjava/ProcessImpl_md.c	Thu Aug 16 16:06:54 2018 +0530
+++ b/src/java.base/windows/native/libjava/ProcessImpl_md.c	Wed Aug 15 10:38:27 2018 -0400
@@ -433,10 +433,10 @@
 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
                                                        jclass ignored,
                                                        jlong handle,
-                                                       jlong timeout)
+                                                       jlong timeoutMillis)
 {
     HANDLE events[2];
-    DWORD dwTimeout = (DWORD)timeout;
+    DWORD dwTimeout = (DWORD)timeoutMillis;
     DWORD result;
     events[0] = (HANDLE) handle;
     events[1] = JVM_GetThreadInterruptEvent();
--- a/test/jdk/java/lang/ProcessBuilder/Basic.java	Thu Aug 16 16:06:54 2018 +0530
+++ b/test/jdk/java/lang/ProcessBuilder/Basic.java	Wed Aug 15 10:38:27 2018 -0400
@@ -2421,6 +2421,7 @@
                 public void run() {
                     try {
                         aboutToWaitFor.countDown();
+                        Thread.currentThread().interrupt();
                         boolean result = p.waitFor(30L * 1000L, TimeUnit.MILLISECONDS);
                         fail("waitFor() wasn't interrupted, its return value was: " + result);
                     } catch (InterruptedException success) {
@@ -2430,7 +2431,38 @@
 
             thread.start();
             aboutToWaitFor.await();
-            Thread.sleep(1000);
+            thread.interrupt();
+            thread.join(10L * 1000L);
+            check(millisElapsedSince(start) < 10L * 1000L);
+            check(!thread.isAlive());
+            p.destroy();
+        } catch (Throwable t) { unexpected(t); }
+
+        //----------------------------------------------------------------
+        // Check that Process.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
+        // interrupt works as expected, if interrupted while waiting.
+        //----------------------------------------------------------------
+        try {
+            List<String> childArgs = new ArrayList<String>(javaChildArgs);
+            childArgs.add("sleep");
+            final Process p = new ProcessBuilder(childArgs).start();
+            final long start = System.nanoTime();
+            final CountDownLatch aboutToWaitFor = new CountDownLatch(1);
+
+            final Thread thread = new Thread() {
+                public void run() {
+                    try {
+                        aboutToWaitFor.countDown();
+                        Thread.currentThread().interrupt();
+                        boolean result = p.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+                        fail("waitFor() wasn't interrupted, its return value was: " + result);
+                    } catch (InterruptedException success) {
+                    } catch (Throwable t) { unexpected(t); }
+                }
+            };
+
+            thread.start();
+            aboutToWaitFor.await();
             thread.interrupt();
             thread.join(10L * 1000L);
             check(millisElapsedSince(start) < 10L * 1000L);