--- jsr166/src/test/tck/JSR166TestCase.java 2017/01/29 20:19:00 1.218 +++ jsr166/src/test/tck/JSR166TestCase.java 2017/05/29 19:15:02 1.232 @@ -1,6 +1,7 @@ /* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ * Other contributors include Andrew Wright, Jeffrey Hayes, * Pat Fisher, Mike Judd. @@ -8,32 +9,33 @@ /* * @test - * @summary JSR-166 tck tests (conformance testing mode) + * @summary JSR-166 tck tests, in a number of variations. + * The first is the conformance testing variant, + * while others also test implementation details. * @build * * @modules java.management * @run junit/othervm/timeout=1000 JSR166TestCase - */ - -/* - * @test - * @summary JSR-166 tck tests (whitebox tests allowed) - * @build * - * @modules java.base/java.util.concurrent:open - * java.base/java.lang:open - * java.management * @run junit/othervm/timeout=1000 + * --add-opens java.base/java.util.concurrent=ALL-UNNAMED + * --add-opens java.base/java.lang=ALL-UNNAMED * -Djsr166.testImplementationDetails=true * JSR166TestCase * @run junit/othervm/timeout=1000 + * --add-opens java.base/java.util.concurrent=ALL-UNNAMED + * --add-opens java.base/java.lang=ALL-UNNAMED * -Djsr166.testImplementationDetails=true * -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 * JSR166TestCase * @run junit/othervm/timeout=1000 + * --add-opens java.base/java.util.concurrent=ALL-UNNAMED + * --add-opens java.base/java.lang=ALL-UNNAMED * -Djsr166.testImplementationDetails=true * -Djava.util.concurrent.ForkJoinPool.common.parallelism=1 * -Djava.util.secureRandomSeed=true * JSR166TestCase * @run junit/othervm/timeout=1000/policy=tck.policy + * --add-opens java.base/java.util.concurrent=ALL-UNNAMED + * --add-opens java.base/java.lang=ALL-UNNAMED * -Djsr166.testImplementationDetails=true * JSR166TestCase */ @@ -52,8 +54,6 @@ import java.lang.management.ThreadMXBean import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.nio.file.Files; -import java.nio.file.Paths; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; @@ -88,10 +88,10 @@ import java.util.concurrent.SynchronousQ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.AssertionFailedError; @@ -301,9 +301,11 @@ public class JSR166TestCase extends Test // public static String cpuModel() { // try { -// Matcher matcher = Pattern.compile("model name\\s*: (.*)") +// java.util.regex.Matcher matcher +// = Pattern.compile("model name\\s*: (.*)") // .matcher(new String( -// Files.readAllBytes(Paths.get("/proc/cpuinfo")), "UTF-8")); +// java.nio.file.Files.readAllBytes( +// java.nio.file.Paths.get("/proc/cpuinfo")), "UTF-8")); // matcher.find(); // return matcher.group(1); // } catch (Exception ex) { return null; } @@ -637,6 +639,33 @@ public class JSR166TestCase extends Test public static long MEDIUM_DELAY_MS; public static long LONG_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(); + long[] timeouts = { Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE }; + RANDOM_TIMEOUT = timeouts[rnd.nextInt(timeouts.length)]; + RANDOM_EXPIRED_TIMEOUT = timeouts[rnd.nextInt(3)]; + TimeUnit[] timeUnits = TimeUnit.values(); + RANDOM_TIMEUNIT = timeUnits[rnd.nextInt(timeUnits.length)]; + } + + /** + * Returns a timeout for use when any value at all will do. + */ + static long randomTimeout() { return RANDOM_TIMEOUT; } + + /** + * Returns a timeout that means "no waiting", i.e. not positive. + */ + static long randomExpiredTimeout() { return RANDOM_EXPIRED_TIMEOUT; } + + /** + * Returns a random non-null TimeUnit. + */ + static TimeUnit randomTimeUnit() { return RANDOM_TIMEUNIT; } + /** * Returns the shortest timed delay. This can be scaled up for * slow machines using the jsr166.delay.factor system property, @@ -657,12 +686,17 @@ public class JSR166TestCase extends Test LONG_DELAY_MS = SHORT_DELAY_MS * 200; } + private static final long TIMEOUT_DELAY_MS + = (long) (12.0 * Math.cbrt(delayFactor)); + /** - * Returns a timeout in milliseconds to be used in tests that - * verify that operations block or time out. + * Returns a timeout in milliseconds to be used in tests that verify + * that operations block or time out. We want this to be longer + * than the OS scheduling quantum, but not too long, so don't scale + * linearly with delayFactor; we use "crazy" cube root instead. */ - long timeoutMillis() { - return SHORT_DELAY_MS / 4; + static long timeoutMillis() { + return TIMEOUT_DELAY_MS; } /** @@ -1057,8 +1091,29 @@ public class JSR166TestCase extends Test } /** + * Checks that thread eventually enters the expected blocked thread state. + */ + void assertThreadBlocks(Thread thread, Thread.State expected) { + // always sleep at least 1 ms, with high probability avoiding + // transitory states + for (long retries = LONG_DELAY_MS * 3 / 4; retries-->0; ) { + try { delay(1); } + catch (InterruptedException fail) { + fail("Unexpected InterruptedException"); + } + Thread.State s = thread.getState(); + if (s == expected) + return; + else if (s == Thread.State.TERMINATED) + fail("Unexpected thread termination"); + } + fail("timed out waiting for thread to enter thread state " + expected); + } + + /** * Checks that thread does not terminate within the default * millisecond delay of {@code timeoutMillis()}. + * TODO: REMOVEME */ void assertThreadStaysAlive(Thread thread) { assertThreadStaysAlive(thread, timeoutMillis()); @@ -1066,6 +1121,7 @@ public class JSR166TestCase extends Test /** * Checks that thread does not terminate within the given millisecond delay. + * TODO: REMOVEME */ void assertThreadStaysAlive(Thread thread, long millis) { try { @@ -1080,6 +1136,7 @@ public class JSR166TestCase extends Test /** * Checks that the threads do not terminate within the default * millisecond delay of {@code timeoutMillis()}. + * TODO: REMOVEME */ void assertThreadsStayAlive(Thread... threads) { assertThreadsStayAlive(timeoutMillis(), threads); @@ -1087,6 +1144,7 @@ public class JSR166TestCase extends Test /** * Checks that the threads do not terminate within the given millisecond delay. + * TODO: REMOVEME */ void assertThreadsStayAlive(long millis, Thread... threads) { try { @@ -1137,6 +1195,12 @@ public class JSR166TestCase extends Test } /** + * The maximum number of consecutive spurious wakeups we should + * tolerate (from APIs like LockSupport.park) before failing a test. + */ + static final int MAX_SPURIOUS_WAKEUPS = 10; + + /** * The number of elements to place in collections, arrays, etc. */ public static final int SIZE = 20; @@ -1299,21 +1363,61 @@ public class JSR166TestCase extends Test startTime = System.nanoTime(); else if (millisElapsedSince(startTime) > timeoutMillis) { threadAssertTrue(thread.isAlive()); - return; + fail("timed out waiting for thread to enter wait state"); } Thread.yield(); } } /** - * Waits up to LONG_DELAY_MS for the given thread to enter a wait - * state: BLOCKED, WAITING, or TIMED_WAITING. + * Spin-waits up to the specified number of milliseconds for the given + * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING, + * and additionally satisfy the given condition. + */ + void waitForThreadToEnterWaitState( + Thread thread, long timeoutMillis, Callable waitingForGodot) { + long startTime = 0L; + for (;;) { + Thread.State s = thread.getState(); + if (s == Thread.State.BLOCKED || + s == Thread.State.WAITING || + s == Thread.State.TIMED_WAITING) { + try { + if (waitingForGodot.call()) + return; + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + else if (s == Thread.State.TERMINATED) + fail("Unexpected thread termination"); + else if (startTime == 0L) + startTime = System.nanoTime(); + else if (millisElapsedSince(startTime) > timeoutMillis) { + threadAssertTrue(thread.isAlive()); + fail("timed out waiting for thread to enter wait state"); + } + Thread.yield(); + } + } + + /** + * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to + * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING. */ void waitForThreadToEnterWaitState(Thread thread) { waitForThreadToEnterWaitState(thread, LONG_DELAY_MS); } /** + * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to + * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING, + * and additionally satisfy the given condition. + */ + void waitForThreadToEnterWaitState( + Thread thread, Callable waitingForGodot) { + waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot); + } + + /** * Returns the number of milliseconds since time given by * startNanoTime, which must have been previously returned from a * call to {@link System#nanoTime()}. @@ -1565,6 +1669,14 @@ public class JSR166TestCase extends Test } } + public void await(CyclicBarrier barrier) { + try { + barrier.await(LONG_DELAY_MS, MILLISECONDS); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + // /** // * Spin-waits up to LONG_DELAY_MS until flag becomes true. // */ @@ -1588,28 +1700,6 @@ public class JSR166TestCase extends Test public String call() { throw new NullPointerException(); } } - public static class CallableOne implements Callable { - public Integer call() { return one; } - } - - public class ShortRunnable extends CheckedRunnable { - protected void realRun() throws Throwable { - delay(SHORT_DELAY_MS); - } - } - - public class ShortInterruptedRunnable extends CheckedInterruptedRunnable { - protected void realRun() throws InterruptedException { - delay(SHORT_DELAY_MS); - } - } - - public class SmallRunnable extends CheckedRunnable { - protected void realRun() throws Throwable { - delay(SMALL_DELAY_MS); - } - } - public class SmallPossiblyInterruptedRunnable extends CheckedRunnable { protected void realRun() { try { @@ -1618,25 +1708,6 @@ public class JSR166TestCase extends Test } } - public class SmallCallable extends CheckedCallable { - protected Object realCall() throws InterruptedException { - delay(SMALL_DELAY_MS); - return Boolean.TRUE; - } - } - - public class MediumRunnable extends CheckedRunnable { - protected void realRun() throws Throwable { - delay(MEDIUM_DELAY_MS); - } - } - - public class MediumInterruptedRunnable extends CheckedInterruptedRunnable { - protected void realRun() throws InterruptedException { - delay(MEDIUM_DELAY_MS); - } - } - public Runnable possiblyInterruptedRunnable(final long timeoutMillis) { return new CheckedRunnable() { protected void realRun() { @@ -1646,22 +1717,6 @@ public class JSR166TestCase extends Test }}; } - public class MediumPossiblyInterruptedRunnable extends CheckedRunnable { - protected void realRun() { - try { - delay(MEDIUM_DELAY_MS); - } catch (InterruptedException ok) {} - } - } - - public class LongPossiblyInterruptedRunnable extends CheckedRunnable { - protected void realRun() { - try { - delay(LONG_DELAY_MS); - } catch (InterruptedException ok) {} - } - } - /** * For use as ThreadFactory in constructors */ @@ -1675,59 +1730,6 @@ public class JSR166TestCase extends Test boolean isDone(); } - public static TrackedRunnable trackedRunnable(final long timeoutMillis) { - return new TrackedRunnable() { - private volatile boolean done = false; - public boolean isDone() { return done; } - public void run() { - try { - delay(timeoutMillis); - done = true; - } catch (InterruptedException ok) {} - } - }; - } - - public static class TrackedShortRunnable implements Runnable { - public volatile boolean done = false; - public void run() { - try { - delay(SHORT_DELAY_MS); - done = true; - } catch (InterruptedException ok) {} - } - } - - public static class TrackedSmallRunnable implements Runnable { - public volatile boolean done = false; - public void run() { - try { - delay(SMALL_DELAY_MS); - done = true; - } catch (InterruptedException ok) {} - } - } - - public static class TrackedMediumRunnable implements Runnable { - public volatile boolean done = false; - public void run() { - try { - delay(MEDIUM_DELAY_MS); - done = true; - } catch (InterruptedException ok) {} - } - } - - public static class TrackedLongRunnable implements Runnable { - public volatile boolean done = false; - public void run() { - try { - delay(LONG_DELAY_MS); - done = true; - } catch (InterruptedException ok) {} - } - } - public static class TrackedNoOpRunnable implements Runnable { public volatile boolean done = false; public void run() { @@ -1735,17 +1737,6 @@ public class JSR166TestCase extends Test } } - public static class TrackedCallable implements Callable { - public volatile boolean done = false; - public Object call() { - try { - delay(SMALL_DELAY_MS); - done = true; - } catch (InterruptedException ok) {} - return Boolean.TRUE; - } - } - /** * Analog of CheckedRunnable for RecursiveAction */ @@ -1812,7 +1803,7 @@ public class JSR166TestCase extends Test assertEquals(0, q.size()); assertNull(q.peek()); assertNull(q.poll()); - assertNull(q.poll(0, MILLISECONDS)); + assertNull(q.poll(randomExpiredTimeout(), randomTimeUnit())); assertEquals(q.toString(), "[]"); assertTrue(Arrays.equals(q.toArray(), new Object[0])); assertFalse(q.iterator().hasNext());