--- jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java 2019/08/15 14:56:32 1.70 +++ jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java 2019/08/16 02:32:26 1.73 @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; @@ -1312,17 +1313,28 @@ public class AbstractQueuedSynchronizerT * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck */ public void testInterruptedFailingAcquire() throws Throwable { - final RuntimeException ex = new RuntimeException(); + class PleaseThrow extends RuntimeException {} + final PleaseThrow ex = new PleaseThrow(); + final AtomicBoolean thrown = new AtomicBoolean(); // A synchronizer only offering a choice of failure modes class Sync extends AbstractQueuedSynchronizer { volatile boolean pleaseThrow; + void maybeThrow() { + if (pleaseThrow) { + // assert: tryAcquire methods can throw at most once + if (! thrown.compareAndSet(false, true)) + throw new AssertionError(); + throw ex; + } + } + @Override protected boolean tryAcquire(int ignored) { - if (pleaseThrow) throw ex; + maybeThrow(); return false; } @Override protected int tryAcquireShared(int ignored) { - if (pleaseThrow) throw ex; + maybeThrow(); return -1; } @Override protected boolean tryRelease(int ignored) { @@ -1334,19 +1346,27 @@ public class AbstractQueuedSynchronizerT } final Sync s = new Sync(); - final Action[] uninterruptibleAcquireMethods = { + final boolean acquireInterruptibly = randomBoolean(); + final Action[] uninterruptibleAcquireActions = { () -> s.acquire(1), () -> s.acquireShared(1), - // TODO: test interruptible acquire methods }; - final Action[] releaseMethods = { + final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + final Action[] interruptibleAcquireActions = { + () -> s.acquireInterruptibly(1), + () -> s.acquireSharedInterruptibly(1), + () -> s.tryAcquireNanos(1, nanosTimeout), + () -> s.tryAcquireSharedNanos(1, nanosTimeout), + }; + final Action[] releaseActions = { () -> s.release(1), () -> s.releaseShared(1), }; - final Action acquireMethod - = chooseRandomly(uninterruptibleAcquireMethods); - final Action releaseMethod - = chooseRandomly(releaseMethods); + final Action acquireAction = acquireInterruptibly + ? chooseRandomly(interruptibleAcquireActions) + : chooseRandomly(uninterruptibleAcquireActions); + final Action releaseAction + = chooseRandomly(releaseActions); // From os_posix.cpp: // @@ -1359,12 +1379,14 @@ public class AbstractQueuedSynchronizerT // is allowed and not harmful, and the possibility is so rare that // it is not worth the added complexity to add yet another lock. final Thread thread = newStartedThread(new CheckedRunnable() { - public void realRun() { + public void realRun() throws Throwable { try { - acquireMethod.run(); + acquireAction.run(); shouldThrow(); - } catch (Throwable t) { - assertSame(ex, t); + } catch (InterruptedException possible) { + assertTrue(acquireInterruptibly); + assertFalse(Thread.interrupted()); + } catch (PleaseThrow possible) { awaitInterrupted(); } }}); @@ -1373,7 +1395,8 @@ public class AbstractQueuedSynchronizerT if (s.getFirstQueuedThread() == thread && s.hasQueuedPredecessors() && s.hasQueuedThreads() - && s.getQueueLength() == 1) + && s.getQueueLength() == 1 + && s.hasContended()) break; if (startTime == 0L) startTime = System.nanoTime(); @@ -1388,18 +1411,22 @@ public class AbstractQueuedSynchronizerT // release and interrupt, in random order if (randomBoolean()) { thread.interrupt(); - releaseMethod.run(); + releaseAction.run(); } else { - releaseMethod.run(); + releaseAction.run(); thread.interrupt(); } awaitTermination(thread); + if (! acquireInterruptibly) + assertTrue(thrown.get()); + assertNull(s.getFirstQueuedThread()); assertFalse(s.hasQueuedPredecessors()); assertFalse(s.hasQueuedThreads()); assertEquals(0, s.getQueueLength()); assertTrue(s.getQueuedThreads().isEmpty()); + assertTrue(s.hasContended()); } }