< prev index next >

test/jdk/java/util/concurrent/tck/JSR166TestCase.java

Print this page
8225490: Miscellaneous changes imported from jsr166 CVS 2019-09
Reviewed-by: martin, alanb

@@ -309,16 +309,17 @@
 
     // Instrumentation to debug very rare, but very annoying hung test runs.
     static volatile TestCase currentTestCase;
     // static volatile int currentRun = 0;
     static {
-        Runnable checkForWedgedTest = new Runnable() { public void run() {
+        Runnable wedgedTestDetector = new Runnable() { public void run() {
             // Avoid spurious reports with enormous runsPerTest.
             // A single test case run should never take more than 1 second.
             // But let's cap it at the high end too ...
-            final int timeoutMinutes =
-                Math.min(15, Math.max(runsPerTest / 60, 1));
+            final int timeoutMinutesMin = Math.max(runsPerTest / 60, 1)
+                * Math.max((int) delayFactor, 1);
+            final int timeoutMinutes = Math.min(15, timeoutMinutesMin);
             for (TestCase lastTestCase = currentTestCase;;) {
                 try { MINUTES.sleep(timeoutMinutes); }
                 catch (InterruptedException unexpected) { break; }
                 if (lastTestCase == currentTestCase) {
                     System.err.printf(

@@ -334,11 +335,11 @@
                     // one stack dump is probably enough; more would be spam
                     break;
                 }
                 lastTestCase = currentTestCase;
             }}};
-        Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest");
+        Thread thread = new Thread(wedgedTestDetector, "WedgedTestDetector");
         thread.setDaemon(true);
         thread.start();
     }
 
 //     public static String cpuModel() {

@@ -378,11 +379,11 @@
             if (elapsedMillis < profileThreshold)
                 break;
             // Never report first run of any test; treat it as a
             // warmup run, notably to trigger all needed classloading,
             if (i > 0)
-                System.out.printf("%n%s: %d%n", toString(), elapsedMillis);
+                System.out.printf("%s: %d%n", toString(), elapsedMillis);
         }
     }
 
     /**
      * Runs all JSR166 unit tests using junit.textui.TestRunner.

@@ -681,10 +682,16 @@
     public static long SHORT_DELAY_MS;
     public static long SMALL_DELAY_MS;
     public static long MEDIUM_DELAY_MS;
     public static long LONG_DELAY_MS;
 
+    /**
+     * A delay significantly longer than LONG_DELAY_MS.
+     * Use this in a thread that is waited for via awaitTermination(Thread).
+     */
+    public static long LONGER_DELAY_MS;
+
     private static final long RANDOM_TIMEOUT;
     private static final long RANDOM_EXPIRED_TIMEOUT;
     private static final TimeUnit RANDOM_TIMEUNIT;
     static {
         ThreadLocalRandom rnd = ThreadLocalRandom.current();

@@ -709,10 +716,24 @@
      * Returns a random non-null TimeUnit.
      */
     static TimeUnit randomTimeUnit() { return RANDOM_TIMEUNIT; }
 
     /**
+     * Returns a random boolean; a "coin flip".
+     */
+    static boolean randomBoolean() {
+        return ThreadLocalRandom.current().nextBoolean();
+    }
+
+    /**
+     * Returns a random element from given choices.
+     */
+    <T> T chooseRandomly(T... choices) {
+        return choices[ThreadLocalRandom.current().nextInt(choices.length)];
+    }
+
+    /**
      * Returns the shortest timed delay. This can be scaled up for
      * slow machines using the jsr166.delay.factor system property,
      * or via jtreg's -timeoutFactor: flag.
      * http://openjdk.java.net/jtreg/command-help.html
      */

@@ -726,10 +747,11 @@
     protected void setDelays() {
         SHORT_DELAY_MS = getShortDelay();
         SMALL_DELAY_MS  = SHORT_DELAY_MS * 5;
         MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10;
         LONG_DELAY_MS   = SHORT_DELAY_MS * 200;
+        LONGER_DELAY_MS = 2 * LONG_DELAY_MS;
     }
 
     private static final long TIMEOUT_DELAY_MS
         = (long) (12.0 * Math.cbrt(delayFactor));
 

@@ -764,12 +786,12 @@
      * failure is recorded; subsequent calls to this method from within
      * the same test have no effect.
      */
     public void threadRecordFailure(Throwable t) {
         System.err.println(t);
+        if (threadFailure.compareAndSet(null, t))
         dumpTestThreads();
-        threadFailure.compareAndSet(null, t);
     }
 
     public void setUp() {
         setDelays();
     }

@@ -1086,10 +1108,43 @@
                     threadUnexpectedException(ex);
                 }
         }
     }
 
+    /** Returns true if thread info might be useful in a thread dump. */
+    static boolean threadOfInterest(ThreadInfo info) {
+        final String name = info.getThreadName();
+        String lockName;
+        if (name == null)
+            return true;
+        if (name.equals("Signal Dispatcher")
+            || name.equals("WedgedTestDetector"))
+            return false;
+        if (name.equals("Reference Handler")) {
+            // Reference Handler stacktrace changed in JDK-8156500
+            StackTraceElement[] stackTrace; String methodName;
+            if ((stackTrace = info.getStackTrace()) != null
+                && stackTrace.length > 0
+                && (methodName = stackTrace[0].getMethodName()) != null
+                && methodName.equals("waitForReferencePendingList"))
+                return false;
+            // jdk8 Reference Handler stacktrace
+            if ((lockName = info.getLockName()) != null
+                && lockName.startsWith("java.lang.ref"))
+                return false;
+        }
+        if ((name.equals("Finalizer") || name.equals("Common-Cleaner"))
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.lang.ref"))
+            return false;
+        if (name.startsWith("ForkJoinPool.commonPool-worker")
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.util.concurrent.ForkJoinPool"))
+            return false;
+        return true;
+    }
+
     /**
      * A debugging tool to print stack traces of most threads, as jstack does.
      * Uninteresting threads are filtered out.
      */
     static void dumpTestThreads() {

@@ -1102,27 +1157,13 @@
             }
         }
 
         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
         System.err.println("------ stacktrace dump start ------");
-        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
-            final String name = info.getThreadName();
-            String lockName;
-            if ("Signal Dispatcher".equals(name))
-                continue;
-            if ("Reference Handler".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.Reference$Lock"))
-                continue;
-            if ("Finalizer".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.ReferenceQueue$Lock"))
-                continue;
-            if ("checkForWedgedTest".equals(name))
-                continue;
+        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true))
+            if (threadOfInterest(info))
             System.err.print(info);
-        }
         System.err.println("------ stacktrace dump end ------");
 
         if (sm != null) System.setSecurityManager(sm);
     }
 

@@ -1391,31 +1432,32 @@
                                        Callable<Boolean> waitingForGodot) {
         waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot);
     }
 
     /**
+     * Spin-waits up to LONG_DELAY_MS milliseconds for the current thread to
+     * be interrupted.  Clears the interrupt status before returning.
+     */
+    void awaitInterrupted() {
+        for (long startTime = 0L; !Thread.interrupted(); ) {
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for thread interrupt");
+            Thread.yield();
+        }
+    }
+
+    /**
      * Returns the number of milliseconds since time given by
      * startNanoTime, which must have been previously returned from a
      * call to {@link System#nanoTime()}.
      */
     static long millisElapsedSince(long startNanoTime) {
         return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
     }
 
-//     void assertTerminatesPromptly(long timeoutMillis, Runnable r) {
-//         long startTime = System.nanoTime();
-//         try {
-//             r.run();
-//         } catch (Throwable fail) { threadUnexpectedException(fail); }
-//         if (millisElapsedSince(startTime) > timeoutMillis/2)
-//             throw new AssertionError("did not return promptly");
-//     }
-
-//     void assertTerminatesPromptly(Runnable r) {
-//         assertTerminatesPromptly(LONG_DELAY_MS/2, r);
-//     }
-
     /**
      * Checks that timed f.get() returns the expected value, and does not
      * wait for the timeout to elapse before returning.
      */
     <T> void checkTimedGet(Future<T> f, T expectedValue, long timeoutMillis) {

@@ -1446,19 +1488,25 @@
     /**
      * Waits for the specified time (in milliseconds) for the thread
      * to terminate (using {@link Thread#join(long)}), else interrupts
      * the thread (in the hope that it may terminate later) and fails.
      */
-    void awaitTermination(Thread t, long timeoutMillis) {
+    void awaitTermination(Thread thread, long timeoutMillis) {
         try {
-            t.join(timeoutMillis);
+            thread.join(timeoutMillis);
         } catch (InterruptedException fail) {
             threadUnexpectedException(fail);
+        }
+        if (thread.getState() != Thread.State.TERMINATED) {
+            String detail = String.format(
+                    "timed out waiting for thread to terminate, thread=%s, state=%s" ,
+                    thread, thread.getState());
+            try {
+                threadFail(detail);
         } finally {
-            if (t.getState() != Thread.State.TERMINATED) {
-                t.interrupt();
-                threadFail("timed out waiting for thread to terminate");
+                // Interrupt thread __after__ having reported its stack trace
+                thread.interrupt();
             }
         }
     }
 
     /**
< prev index next >