--- jsr166/src/test/tck/JSR166TestCase.java 2015/10/04 00:59:09 1.160 +++ jsr166/src/test/tck/JSR166TestCase.java 2015/10/08 22:39:57 1.170 @@ -188,7 +188,9 @@ public class JSR166TestCase extends Test return (regex == null) ? null : Pattern.compile(regex); } + // 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() { // avoid spurious reports with enormous runsPerTest @@ -197,10 +199,17 @@ public class JSR166TestCase extends Test try { MINUTES.sleep(timeoutMinutes); } catch (InterruptedException unexpected) { break; } if (lastTestCase == currentTestCase) { + System.err.printf( + "Looks like we're stuck running test: %s (%d/%d)%n", + lastTestCase, currentRun, runsPerTest); System.err.println ("Looks like we're stuck running test: " - + lastTestCase); + + lastTestCase + " (" + currentRun + "/" + runsPerTest + ")"); + System.err.println("availableProcessors=" + + Runtime.getRuntime().availableProcessors()); dumpTestThreads(); + // one stack dump is probably enough; more would be spam + break; } lastTestCase = currentTestCase; }}}; @@ -218,6 +227,7 @@ public class JSR166TestCase extends Test protected void runTest() throws Throwable { for (int i = 0; i < runsPerTest; i++) { + currentRun = i; if (profileTests) runTestProfiled(); else @@ -590,7 +600,7 @@ public class JSR166TestCase extends Test } /** - * Finds missing try { ... } finally { joinPool(e); } + * Finds missing PoolCleaners */ void checkForkJoinPoolThreadLeaks() throws InterruptedException { Thread[] survivors = new Thread[7]; @@ -749,22 +759,20 @@ public class JSR166TestCase extends Test /** * Delays, via Thread.sleep, for the given millisecond delay, but * if the sleep is shorter than specified, may re-sleep or yield - * until time elapses. + * until time elapses. Ensures that the given time, as measured + * by System.nanoTime(), has elapsed. */ static void delay(long millis) throws InterruptedException { - long startTime = System.nanoTime(); - long ns = millis * 1000 * 1000; - for (;;) { + long nanos = millis * (1000 * 1000); + final long wakeupTime = System.nanoTime() + nanos; + do { if (millis > 0L) Thread.sleep(millis); else // too short to sleep Thread.yield(); - long d = ns - (System.nanoTime() - startTime); - if (d > 0L) - millis = d / (1000 * 1000); - else - break; - } + nanos = wakeupTime - System.nanoTime(); + millis = nanos / (1000 * 1000); + } while (nanos >= 0L); } /** @@ -776,10 +784,43 @@ public class JSR166TestCase extends Test public void close() { joinPool(pool); } } + /** + * An extension of PoolCleaner that has an action to release the pool. + */ + class PoolCleanerWithReleaser extends PoolCleaner { + private final Runnable releaser; + public PoolCleanerWithReleaser(ExecutorService pool, Runnable releaser) { + super(pool); + this.releaser = releaser; + } + public void close() { + try { + releaser.run(); + } finally { + super.close(); + } + } + } + PoolCleaner cleaner(ExecutorService pool) { return new PoolCleaner(pool); } + PoolCleaner cleaner(ExecutorService pool, Runnable releaser) { + return new PoolCleanerWithReleaser(pool, releaser); + } + + PoolCleaner cleaner(ExecutorService pool, CountDownLatch latch) { + return new PoolCleanerWithReleaser(pool, releaser(latch)); + } + + Runnable releaser(final CountDownLatch latch) { + return new Runnable() { public void run() { + do { latch.countDown(); } + while (latch.getCount() > 0); + }}; + } + /** * Waits out termination of a thread pool or fails doing so. */ @@ -793,7 +834,7 @@ public class JSR166TestCase extends Test } finally { // last resort, for the benefit of subsequent tests pool.shutdownNow(); - pool.awaitTermination(SMALL_DELAY_MS, MILLISECONDS); + pool.awaitTermination(MEDIUM_DELAY_MS, MILLISECONDS); } } } catch (SecurityException ok) { @@ -1170,7 +1211,7 @@ public class JSR166TestCase extends Test } finally { if (t.getState() != Thread.State.TERMINATED) { t.interrupt(); - fail("Test timed out"); + threadFail("Test timed out"); } } } @@ -1318,11 +1359,22 @@ public class JSR166TestCase extends Test }}; } - public Runnable awaiter(final CountDownLatch latch) { - return new CheckedRunnable() { - public void realRun() throws InterruptedException { - await(latch); - }}; + class LatchAwaiter extends CheckedRunnable { + static final int NEW = 0; + static final int RUNNING = 1; + static final int DONE = 2; + final CountDownLatch latch; + int state = NEW; + LatchAwaiter(CountDownLatch latch) { this.latch = latch; } + public void realRun() throws InterruptedException { + state = 1; + await(latch); + state = 2; + } + } + + public LatchAwaiter awaiter(CountDownLatch latch) { + return new LatchAwaiter(latch); } public void await(CountDownLatch latch) {