--- jsr166/src/test/tck/JSR166TestCase.java 2015/09/25 23:32:15 1.146 +++ jsr166/src/test/tck/JSR166TestCase.java 2015/10/03 23:17:03 1.158 @@ -7,6 +7,7 @@ */ import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.NANOSECONDS; import java.io.ByteArrayInputStream; @@ -15,6 +16,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -186,15 +188,40 @@ public class JSR166TestCase extends Test return (regex == null) ? null : Pattern.compile(regex); } - protected void runTest() throws Throwable { + static volatile TestCase currentTestCase; + static { + Runnable checkForWedgedTest = new Runnable() { public void run() { + // avoid spurious reports with enormous runsPerTest + final int timeoutMinutes = Math.max(runsPerTest / 10, 1); + for (TestCase lastTestCase = currentTestCase;;) { + try { MINUTES.sleep(timeoutMinutes); } + catch (InterruptedException unexpected) { break; } + if (lastTestCase == currentTestCase) { + System.err.println + ("Looks like we're stuck running test: " + + lastTestCase); + dumpTestThreads(); + } + lastTestCase = currentTestCase; + }}}; + Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest"); + thread.setDaemon(true); + thread.start(); + } + + public void runBare() throws Throwable { + currentTestCase = this; if (methodFilter == null - || methodFilter.matcher(toString()).find()) { - for (int i = 0; i < runsPerTest; i++) { - if (profileTests) - runTestProfiled(); - else - super.runTest(); - } + || methodFilter.matcher(toString()).find()) + super.runBare(); + } + + protected void runTest() throws Throwable { + for (int i = 0; i < runsPerTest; i++) { + if (profileTests) + runTestProfiled(); + else + super.runTest(); } } @@ -457,7 +484,6 @@ public class JSR166TestCase extends Test } else { return new TestSuite(); } - } // Delays for timing-dependent tests, in milliseconds. @@ -515,6 +541,8 @@ public class JSR166TestCase extends Test * the same test have no effect. */ public void threadRecordFailure(Throwable t) { + System.err.println(t); + dumpTestThreads(); threadFailure.compareAndSet(null, t); } @@ -525,7 +553,7 @@ public class JSR166TestCase extends Test void tearDownFail(String format, Object... args) { String msg = toString() + ": " + String.format(format, args); System.err.println(msg); - printAllStackTraces(); + dumpTestThreads(); throw new AssertionFailedError(msg); } @@ -594,7 +622,7 @@ public class JSR166TestCase extends Test fail(reason); } catch (AssertionFailedError t) { threadRecordFailure(t); - fail(reason); + throw t; } } @@ -740,18 +768,35 @@ public class JSR166TestCase extends Test } /** + * Allows use of try-with-resources with per-test thread pools. + */ + class PoolCloser + implements AutoCloseable { + public final T pool; + public PoolCloser(T pool) { this.pool = pool; } + public void close() { joinPool(pool); } + } + + /** * Waits out termination of a thread pool or fails doing so. */ void joinPool(ExecutorService pool) { try { pool.shutdown(); - if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)) - fail("ExecutorService " + pool + - " did not terminate in a timely manner"); + if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)) { + try { + threadFail("ExecutorService " + pool + + " did not terminate in a timely manner"); + } finally { + // last resort, for the benefit of subsequent tests + pool.shutdownNow(); + pool.awaitTermination(SMALL_DELAY_MS, MILLISECONDS); + } + } } catch (SecurityException ok) { // Allowed in case test doesn't have privs } catch (InterruptedException fail) { - fail("Unexpected InterruptedException"); + threadFail("Unexpected InterruptedException"); } } @@ -764,8 +809,9 @@ public class JSR166TestCase extends Test * necessarily individually slow because they must block. */ void testInParallel(Action ... actions) { - ExecutorService pool = Executors.newCachedThreadPool(); - try { + try (PoolCloser poolCloser + = new PoolCloser<>(Executors.newCachedThreadPool())) { + ExecutorService pool = poolCloser.pool; ArrayList> futures = new ArrayList<>(actions.length); for (final Action action : actions) futures.add(pool.submit(new CheckedRunnable() { @@ -778,19 +824,31 @@ public class JSR166TestCase extends Test } catch (Exception ex) { threadUnexpectedException(ex); } - } finally { - joinPool(pool); } } /** - * A debugging tool to print all stack traces, as jstack does. + * A debugging tool to print stack traces of most threads, as jstack does. + * Uninteresting threads are filtered out. */ - static void printAllStackTraces() { - for (ThreadInfo info : - ManagementFactory.getThreadMXBean() - .dumpAllThreads(true, true)) + static void dumpTestThreads() { + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + System.err.println("------ stacktrace dump start ------"); + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + String name = info.getThreadName(); + if ("Signal Dispatcher".equals(name)) + continue; + if ("Reference Handler".equals(name) + && info.getLockName().startsWith("java.lang.ref.Reference$Lock")) + continue; + if ("Finalizer".equals(name) + && info.getLockName().startsWith("java.lang.ref.ReferenceQueue$Lock")) + continue; + if ("checkForWedgedTest".equals(name)) + continue; System.err.print(info); + } + System.err.println("------ stacktrace dump end ------"); } /** @@ -810,7 +868,7 @@ public class JSR166TestCase extends Test delay(millis); assertTrue(thread.isAlive()); } catch (InterruptedException fail) { - fail("Unexpected InterruptedException"); + threadFail("Unexpected InterruptedException"); } } @@ -832,7 +890,7 @@ public class JSR166TestCase extends Test for (Thread thread : threads) assertTrue(thread.isAlive()); } catch (InterruptedException fail) { - fail("Unexpected InterruptedException"); + threadFail("Unexpected InterruptedException"); } } @@ -1251,6 +1309,13 @@ public class JSR166TestCase extends Test }}; } + public Runnable countDowner(final CountDownLatch latch) { + return new CheckedRunnable() { + public void realRun() throws InterruptedException { + latch.countDown(); + }}; + } + public Runnable awaiter(final CountDownLatch latch) { return new CheckedRunnable() { public void realRun() throws InterruptedException {