< prev index next >

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

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

*** 38,48 **** import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; ! import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; import junit.framework.Test; import junit.framework.TestSuite; --- 38,48 ---- 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; import junit.framework.Test; import junit.framework.TestSuite;
*** 1335,1357 **** } /** * Tests scenario for * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw */ ! public void testInterruptedFailingAcquire() throws InterruptedException { ! final RuntimeException ex = new RuntimeException(); // A synchronizer only offering a choice of failure modes class Sync extends AbstractQueuedSynchronizer { ! boolean pleaseThrow; @Override protected boolean tryAcquire(int ignored) { ! if (pleaseThrow) throw ex; return false; } @Override protected int tryAcquireShared(int ignored) { ! if (pleaseThrow) throw ex; return -1; } @Override protected boolean tryRelease(int ignored) { return true; } --- 1335,1369 ---- } /** * Tests scenario for * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw + * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck */ ! public void testInterruptedFailingAcquire() throws Throwable { ! 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) { ! maybeThrow(); return false; } @Override protected int tryAcquireShared(int ignored) { ! maybeThrow(); return -1; } @Override protected boolean tryRelease(int ignored) { return true; }
*** 1359,1390 **** return true; } } final Sync s = new Sync(); ! final Thread thread = newStartedThread(new CheckedRunnable() { ! public void realRun() { try { ! if (ThreadLocalRandom.current().nextBoolean()) ! s.acquire(1); ! else ! s.acquireShared(1); shouldThrow(); ! } catch (Throwable t) { ! assertSame(ex, t); ! assertTrue(Thread.interrupted()); } }}); waitForThreadToEnterWaitState(thread); ! assertSame(thread, s.getFirstQueuedThread()); ! assertTrue(s.hasQueuedPredecessors()); ! assertTrue(s.hasQueuedThreads()); ! assertEquals(1, s.getQueueLength()); s.pleaseThrow = true; thread.interrupt(); ! s.release(1); awaitTermination(thread); } } --- 1371,1459 ---- return true; } } final Sync s = new Sync(); ! final boolean acquireInterruptibly = randomBoolean(); ! final Action[] uninterruptibleAcquireActions = { ! () -> s.acquire(1), ! () -> s.acquireShared(1), ! }; ! 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 acquireAction = acquireInterruptibly ! ? chooseRandomly(interruptibleAcquireActions) ! : chooseRandomly(uninterruptibleAcquireActions); ! final Action releaseAction ! = chooseRandomly(releaseActions); ! ! // From os_posix.cpp: ! // ! // NOTE that since there is no "lock" around the interrupt and ! // is_interrupted operations, there is the possibility that the ! // interrupted flag (in osThread) will be "false" but that the ! // low-level events will be in the signaled state. This is ! // intentional. The effect of this is that Object.wait() and ! // LockSupport.park() will appear to have a spurious wakeup, which ! // 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() throws Throwable { try { ! acquireAction.run(); shouldThrow(); ! } catch (InterruptedException possible) { ! assertTrue(acquireInterruptibly); ! assertFalse(Thread.interrupted()); ! } catch (PleaseThrow possible) { ! awaitInterrupted(); } }}); + for (long startTime = 0L;; ) { waitForThreadToEnterWaitState(thread); ! if (s.getFirstQueuedThread() == thread ! && s.hasQueuedPredecessors() ! && s.hasQueuedThreads() ! && s.getQueueLength() == 1 ! && s.hasContended()) ! break; ! if (startTime == 0L) ! startTime = System.nanoTime(); ! else if (millisElapsedSince(startTime) > LONG_DELAY_MS) ! fail("timed out waiting for AQS state: " ! + "thread state=" + thread.getState() ! + ", queued threads=" + s.getQueuedThreads()); ! Thread.yield(); ! } s.pleaseThrow = true; + // release and interrupt, in random order + if (randomBoolean()) { thread.interrupt(); ! releaseAction.run(); ! } else { ! 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()); } }
< prev index next >