--- jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java 2004/01/09 14:45:58 1.12 +++ jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java 2014/12/02 07:23:13 1.45 @@ -1,70 +1,96 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ - import junit.framework.*; import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.*; -import java.io.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; public class AbstractQueuedSynchronizerTest extends JSR166TestCase { public static void main(String[] args) { - junit.textui.TestRunner.run (suite()); + junit.textui.TestRunner.run(suite()); } public static Test suite() { return new TestSuite(AbstractQueuedSynchronizerTest.class); } /** - * A simple mutex class, adapted from the - * AbstractQueuedSynchronizer javadoc. Exclusive acquire tests - * exercise this as a sample user extension. Other - * methods/features of AbstractQueuedSynchronizerTest are tested - * via other test classes, including those for ReentrantLock, - * ReentrantReadWriteLock, and Semaphore + * A simple mutex class, adapted from the class javadoc. Exclusive + * acquire tests exercise this as a sample user extension. Other + * methods/features of AbstractQueuedSynchronizer are tested via + * other test classes, including those for ReentrantLock, + * ReentrantReadWriteLock, and Semaphore. */ static class Mutex extends AbstractQueuedSynchronizer { - public boolean isLocked() { return getState() == 1; } - - public boolean tryAcquireExclusive(int acquires) { - assertTrue(acquires == 1); - return compareAndSetState(0, 1); - } - - public boolean tryReleaseExclusive(int releases) { - setState(0); + /** An eccentric value for locked synchronizer state. */ + static final int LOCKED = (1 << 31) | (1 << 15); + + static final int UNLOCKED = 0; + + @Override public boolean isHeldExclusively() { + int state = getState(); + assertTrue(state == UNLOCKED || state == LOCKED); + return state == LOCKED; + } + + @Override public boolean tryAcquire(int acquires) { + assertEquals(LOCKED, acquires); + return compareAndSetState(UNLOCKED, LOCKED); + } + + @Override public boolean tryRelease(int releases) { + if (getState() != LOCKED) throw new IllegalMonitorStateException(); + assertEquals(LOCKED, releases); + setState(UNLOCKED); return true; } - - public void checkConditionAccess(Thread thread) { - if (getState() == 0) throw new IllegalMonitorStateException(); + + public boolean tryAcquireNanos(long nanos) throws InterruptedException { + return tryAcquireNanos(LOCKED, nanos); + } + + public boolean tryAcquire() { + return tryAcquire(LOCKED); + } + + public boolean tryRelease() { + return tryRelease(LOCKED); + } + + public void acquire() { + acquire(LOCKED); } - - public ConditionObject newCondition() { return new ConditionObject(); } - - public void lock() { - acquireExclusiveUninterruptibly(1); + + public void acquireInterruptibly() throws InterruptedException { + acquireInterruptibly(LOCKED); + } + + public void release() { + release(LOCKED); } + public ConditionObject newCondition() { + return new ConditionObject(); + } } - /** * A simple latch class, to test shared mode. */ - static class BooleanLatch extends AbstractQueuedSynchronizer { + static class BooleanLatch extends AbstractQueuedSynchronizer { public boolean isSignalled() { return getState() != 0; } public int tryAcquireShared(int ignore) { - return isSignalled()? 1 : -1; + return isSignalled() ? 1 : -1; } - + public boolean tryReleaseShared(int ignore) { setState(1); return true; @@ -72,609 +98,1144 @@ public class AbstractQueuedSynchronizerT } /** - * A runnable calling acquireExclusiveInterruptibly + * A runnable calling acquireInterruptibly that does not expect to + * be interrupted. */ - class InterruptibleLockRunnable implements Runnable { - final Mutex lock; - InterruptibleLockRunnable(Mutex l) { lock = l; } - public void run() { - try { - lock.acquireExclusiveInterruptibly(1); - } catch(InterruptedException success){} + class InterruptibleSyncRunnable extends CheckedRunnable { + final Mutex sync; + InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); + } + } + + /** + * A runnable calling acquireInterruptibly that expects to be + * interrupted. + */ + class InterruptedSyncRunnable extends CheckedInterruptedRunnable { + final Mutex sync; + InterruptedSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); } } + /** A constant to clarify calls to checking methods below. */ + static final Thread[] NO_THREADS = new Thread[0]; /** - * A runnable calling acquireExclusiveInterruptibly that expects to be - * interrupted + * Spin-waits until sync.isQueued(t) becomes true. */ - class InterruptedLockRunnable implements Runnable { - final Mutex lock; - InterruptedLockRunnable(Mutex l) { lock = l; } - public void run() { - try { - lock.acquireExclusiveInterruptibly(1); - threadShouldThrow(); - } catch(InterruptedException success){} + void waitForQueuedThread(AbstractQueuedSynchronizer sync, Thread t) { + long startTime = System.nanoTime(); + while (!sync.isQueued(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); } + assertTrue(t.isAlive()); } - + /** - * acquireExclusiveUninterruptiblying an releaseExclusiveed lock succeeds + * Checks that sync has exactly the given queued threads. */ - public void testAcquireExclusiveUninterruptibly() { - Mutex rl = new Mutex(); - rl.acquireExclusiveUninterruptibly(1); - assertTrue(rl.isLocked()); - rl.releaseExclusive(1); + void assertHasQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + Collection actual = sync.getQueuedThreads(); + assertEquals(expected.length > 0, sync.hasQueuedThreads()); + assertEquals(expected.length, sync.getQueueLength()); + assertEquals(expected.length, actual.size()); + assertEquals(expected.length == 0, actual.isEmpty()); + assertEquals(new HashSet(actual), + new HashSet(Arrays.asList(expected))); } /** - * tryAcquireExclusive on an releaseExclusiveed lock succeeds + * Checks that sync has exactly the given (exclusive) queued threads. */ - public void testTryAcquireExclusive() { - Mutex rl = new Mutex(); - assertTrue(rl.tryAcquireExclusive(1)); - assertTrue(rl.isLocked()); - rl.releaseExclusive(1); + void assertHasExclusiveQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getExclusiveQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getSharedQueuedThreads().size()); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); } /** - * hasQueuedThreads reports whether there are waiting threads + * Checks that sync has exactly the given (shared) queued threads. */ - public void testhasQueuedThreads() { - final Mutex lock = new Mutex(); - Thread t1 = new Thread(new InterruptedLockRunnable(lock)); - Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.hasQueuedThreads()); - lock.acquireExclusiveUninterruptibly(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - lock.releaseExclusive(1); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.hasQueuedThreads()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } - - /** - * isQueued(null) throws NPE - */ - public void testIsQueuedNPE() { - final Mutex lock = new Mutex(); - try { - lock.isQueued(null); - shouldThrow(); - } catch (NullPointerException success) { - } - } - - /** - * isQueued reports whether a thread is queued. - */ - public void testIsQueued() { - final Mutex lock = new Mutex(); - Thread t1 = new Thread(new InterruptedLockRunnable(lock)); - Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.isQueued(t1)); - assertFalse(lock.isQueued(t2)); - lock.acquireExclusiveUninterruptibly(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.isQueued(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.isQueued(t1)); - assertTrue(lock.isQueued(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.isQueued(t1)); - assertTrue(lock.isQueued(t2)); - lock.releaseExclusive(1); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.isQueued(t1)); - assertFalse(lock.isQueued(t2)); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } - - /** - * getFirstQueuedThread returns first waiting thread or null is none - */ - public void testGetFirstQueuedThread() { - final Mutex lock = new Mutex(); - Thread t1 = new Thread(new InterruptedLockRunnable(lock)); - Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertNull(lock.getFirstQueuedThread()); - lock.acquireExclusiveUninterruptibly(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t1, lock.getFirstQueuedThread()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t1, lock.getFirstQueuedThread()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t2, lock.getFirstQueuedThread()); - lock.releaseExclusive(1); - Thread.sleep(SHORT_DELAY_MS); - assertNull(lock.getFirstQueuedThread()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + void assertHasSharedQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getSharedQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getExclusiveQueuedThreads().size()); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + } + /** + * Checks that condition c has exactly the given waiter threads, + * after acquiring mutex. + */ + void assertHasWaitersUnlocked(Mutex sync, ConditionObject c, + Thread... threads) { + sync.acquire(); + assertHasWaitersLocked(sync, c, threads); + sync.release(); + } /** - * hasContended reports false if no thread has ever blocked, else true + * Checks that condition c has exactly the given waiter threads. */ - public void testHasContended() { - final Mutex lock = new Mutex(); - Thread t1 = new Thread(new InterruptedLockRunnable(lock)); - Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.hasContended()); - lock.acquireExclusiveUninterruptibly(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasContended()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasContended()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasContended()); - lock.releaseExclusive(1); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasContended()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } - - /** - * timed tryAcquireExclusive is interruptible. - */ - public void testInterruptedException2() { - final Mutex lock = new Mutex(); - lock.acquireExclusiveUninterruptibly(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.acquireExclusiveNanos(1, MEDIUM_DELAY_MS * 1000 * 1000); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - t.interrupt(); - } catch(Exception e){ - unexpectedException(); - } + void assertHasWaitersLocked(Mutex sync, ConditionObject c, + Thread... threads) { + assertEquals(threads.length > 0, sync.hasWaiters(c)); + assertEquals(threads.length, sync.getWaitQueueLength(c)); + assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty()); + assertEquals(threads.length, sync.getWaitingThreads(c).size()); + assertEquals(new HashSet(sync.getWaitingThreads(c)), + new HashSet(Arrays.asList(threads))); } + enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }; /** - * TryAcquireExclusive on a locked lock fails - */ - public void testTryAcquireExclusiveWhenLocked() { - final Mutex lock = new Mutex(); - lock.acquireExclusiveUninterruptibly(1); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.tryAcquireExclusive(1)); - } - }); - try { - t.start(); - t.join(); - lock.releaseExclusive(1); - } catch(Exception e){ - unexpectedException(); - } - } - - /** - * acquireExclusiveTimed on a locked lock times out - */ - public void testacquireExclusiveTimed_Timeout() { - final Mutex lock = new Mutex(); - lock.acquireExclusiveUninterruptibly(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(lock.acquireExclusiveNanos(1, 1000 * 1000)); - } catch (Exception ex) { - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - lock.releaseExclusive(1); - } catch(Exception e){ - unexpectedException(); - } - } - - - /** - * isLocked is true when locked and false when not - */ - public void testIsLocked() { - final Mutex lock = new Mutex(); - lock.acquireExclusiveUninterruptibly(1); - assertTrue(lock.isLocked()); - lock.releaseExclusive(1); - assertFalse(lock.isLocked()); - Thread t = new Thread(new Runnable() { - public void run() { - lock.acquireExclusiveUninterruptibly(1); - try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(); - } - lock.releaseExclusive(1); - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.isLocked()); - t.join(); - assertFalse(lock.isLocked()); - } catch(Exception e){ - unexpectedException(); + * Awaits condition using the specified AwaitMethod. + */ + void await(ConditionObject c, AwaitMethod awaitMethod) + throws InterruptedException { + long timeoutMillis = 2 * LONG_DELAY_MS; + switch (awaitMethod) { + case await: + c.await(); + break; + case awaitTimed: + assertTrue(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining > 0); + break; + case awaitUntil: + assertTrue(c.awaitUntil(delayedDate(timeoutMillis))); + break; } } + /** + * Checks that awaiting the given condition times out (using the + * default timeout duration). + */ + void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) { + long timeoutMillis = timeoutMillis(); + long startTime = System.nanoTime(); + try { + switch (awaitMethod) { + case awaitTimed: + assertFalse(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining <= 0); + break; + case awaitUntil: + assertFalse(c.awaitUntil(delayedDate(timeoutMillis))); + break; + default: + throw new UnsupportedOperationException(); + } + } catch (InterruptedException ie) { threadUnexpectedException(ie); } + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + } /** - * acquireExclusiveInterruptibly is interruptible. - */ - public void testAcquireInterruptibly1() { - final Mutex lock = new Mutex(); - lock.acquireExclusiveUninterruptibly(1); - Thread t = new Thread(new InterruptedLockRunnable(lock)); - try { - t.start(); - t.interrupt(); - lock.releaseExclusive(1); - t.join(); - } catch(Exception e){ - unexpectedException(); - } - } - - /** - * acquireExclusiveInterruptibly succeeds when released, else is interruptible - */ - public void testAcquireInterruptibly2() { - final Mutex lock = new Mutex(); - try { - lock.acquireExclusiveInterruptibly(1); - } catch(Exception e) { - unexpectedException(); - } - Thread t = new Thread(new InterruptedLockRunnable(lock)); - try { - t.start(); - t.interrupt(); - assertTrue(lock.isLocked()); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + * isHeldExclusively is false upon construction + */ + public void testIsHeldExclusively() { + Mutex sync = new Mutex(); + assertFalse(sync.isHeldExclusively()); } /** - * owns is true for a condition created by lock else false + * acquiring released sync succeeds */ - public void testOwns() { - final Mutex lock = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = lock.newCondition(); - final Mutex lock2 = new Mutex(); - assertTrue(lock.owns(c)); - assertFalse(lock2.owns(c)); + public void testAcquire() { + Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); } /** - * Calling await without holding lock throws IllegalMonitorStateException + * tryAcquire on a released sync succeeds */ - public void testAwait_IllegalMonitor() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); + public void testTryAcquire() { + Mutex sync = new Mutex(); + assertTrue(sync.tryAcquire()); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasQueuedThreads()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasQueuedThreads()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasQueuedThreads()); + sync.release(); + awaitTermination(t2); + assertFalse(sync.hasQueuedThreads()); + } + + /** + * isQueued(null) throws NullPointerException + */ + public void testIsQueuedNPE() { + final Mutex sync = new Mutex(); try { - c.await(); + sync.isQueued(null); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); + } catch (NullPointerException success) {} + } + + /** + * isQueued reports whether a thread is queued + */ + public void testIsQueued() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + sync.acquire(); + t1.start(); + waitForQueuedThread(sync, t1); + assertTrue(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertTrue(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + sync.release(); + awaitTermination(t2); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + } + + /** + * getFirstQueuedThread returns first waiting thread or null if none + */ + public void testGetFirstQueuedThread() { + final Mutex sync = new Mutex(); + assertNull(sync.getFirstQueuedThread()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertEquals(t1, sync.getFirstQueuedThread()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertEquals(t1, sync.getFirstQueuedThread()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(t2, sync.getFirstQueuedThread()); + sync.release(); + awaitTermination(t2); + assertNull(sync.getFirstQueuedThread()); + } + + /** + * hasContended reports false if no thread has ever blocked, else true + */ + public void testHasContended() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasContended()); + sync.acquire(); + assertFalse(sync.hasContended()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasContended()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasContended()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasContended()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.hasContended()); + } + + /** + * getQueuedThreads returns all waiting threads + */ + public void testGetQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertFalse(sync.getQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getExclusiveQueuedThreads returns all exclusive waiting threads + */ + public void testGetExclusiveQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertFalse(sync.getExclusiveQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getSharedQueuedThreads does not include exclusively waiting threads + */ + public void testGetSharedQueuedThreads_Exclusive() { + final Mutex sync = new Mutex(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.acquire(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + } + + /** + * getSharedQueuedThreads returns all shared waiting threads + */ + public void testGetSharedQueuedThreads_Shared() { + final BooleanLatch l = new BooleanLatch(); + assertHasSharedQueuedThreads(l, NO_THREADS); + Thread t1 = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t1); + assertHasSharedQueuedThreads(l, t1); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t2); + assertHasSharedQueuedThreads(l, t1, t2); + t1.interrupt(); + awaitTermination(t1); + assertHasSharedQueuedThreads(l, t2); + assertTrue(l.releaseShared(0)); + awaitTermination(t2); + assertHasSharedQueuedThreads(l, NO_THREADS); + } + + /** + * tryAcquireNanos is interruptible + */ + public void testTryAcquireNanos_Interruptible() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS)); + }}); + + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + } + + /** + * tryAcquire on exclusively held sync fails + */ + public void testTryAcquireWhenSynced() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(sync.tryAcquire()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * tryAcquireNanos on an exclusively held sync times out + */ + public void testAcquireNanos_Timeout() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long nanos = MILLISECONDS.toNanos(timeoutMillis()); + assertFalse(sync.tryAcquireNanos(nanos)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * getState is true when acquired and false when not + */ + public void testGetState() { + final Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + + final BooleanLatch acquired = new BooleanLatch(); + final BooleanLatch done = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + done.acquireShared(0); + sync.release(); + }}); + + acquired.acquireShared(0); + assertTrue(sync.isHeldExclusively()); + assertTrue(done.releaseShared(0)); + awaitTermination(t); + assertFalse(sync.isHeldExclusively()); + } + + /** + * acquireInterruptibly succeeds when released, else is interruptible + */ + public void testAcquireInterruptibly() throws InterruptedException { + final Mutex sync = new Mutex(); + final BooleanLatch threadStarted = new BooleanLatch(); + sync.acquireInterruptibly(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(threadStarted.releaseShared(0)); + sync.acquireInterruptibly(); + }}); + + threadStarted.acquireShared(0); + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + assertTrue(sync.isHeldExclusively()); + } + + /** + * owns is true for a condition created by sync else false + */ + public void testOwns() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + assertTrue(sync.owns(c)); + assertFalse(sync2.owns(c)); + } + + /** + * Calling await without holding sync throws IllegalMonitorStateException + */ + public void testAwait_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + for (AwaitMethod awaitMethod : AwaitMethod.values()) { + long startTime = System.nanoTime(); + try { + await(c, awaitMethod); + shouldThrow(); + } catch (IllegalMonitorStateException success) { + } catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); } } /** - * Calling signal without holding lock throws IllegalMonitorStateException + * Calling signal without holding sync throws IllegalMonitorStateException */ - public void testSignal_IllegalMonitor() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); + public void testSignal_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); try { c.signal(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); } /** - * awaitNanos without a signal times out + * Calling signalAll without holding sync throws IllegalMonitorStateException */ - public void testAwaitNanos_Timeout() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); + public void testSignalAll_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); try { - lock.acquireExclusiveUninterruptibly(1); - long t = c.awaitNanos(100); - assertTrue(t <= 0); - lock.releaseExclusive(1); - } - catch (Exception ex) { - unexpectedException(); - } + c.signalAll(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} } /** - * timed await without a signal times out + * await/awaitNanos/awaitUntil without a signal times out */ - public void testAwait_Timeout() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); + public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); } + public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); } + public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); } + public void testAwait_Timeout(AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertAwaitTimesOut(c, awaitMethod); + sync.release(); + } + + /** + * await/awaitNanos/awaitUntil returns when signalled + */ + public void testSignal_await() { testSignal(AwaitMethod.await); } + public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); } + public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); } + public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); } + public void testSignal(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + await(c, awaitMethod); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * hasWaiters(null) throws NullPointerException + */ + public void testHasWaitersNPE() { + final Mutex sync = new Mutex(); try { - lock.acquireExclusiveUninterruptibly(1); - assertFalse(c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - lock.releaseExclusive(1); - } - catch (Exception ex) { - unexpectedException(); - } + sync.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} } /** - * awaitUntil without a signal times out + * getWaitQueueLength(null) throws NullPointerException */ - public void testAwaitUntil_Timeout() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); + public void testGetWaitQueueLengthNPE() { + final Mutex sync = new Mutex(); try { - lock.acquireExclusiveUninterruptibly(1); - java.util.Date d = new java.util.Date(); - assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); - lock.releaseExclusive(1); - } - catch (Exception ex) { - unexpectedException(); - } + sync.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} } /** - * await returns when signalled + * getWaitingThreads(null) throws NullPointerException */ - public void testAwait() { - final Mutex lock = new Mutex(); - final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.acquireExclusiveUninterruptibly(1); - c.await(); - lock.releaseExclusive(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + public void testGetWaitingThreadsNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * hasWaiters throws IllegalArgumentException if not owned + */ + public void testHasWaitersIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.acquireExclusiveUninterruptibly(1); - c.signal(); - lock.releaseExclusive(1); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + sync2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters throws IllegalMonitorStateException if not synced + */ + public void testHasWaitersIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalArgumentException if not owned + */ + public void testGetWaitQueueLengthIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalMonitorStateException if not synced + */ + public void testGetWaitQueueLengthIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads throws IllegalArgumentException if not owned + */ + public void testGetWaitingThreadsIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); } + /** + * getWaitingThreads throws IllegalMonitorStateException if not synced + */ + public void testGetWaitingThreadsIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.hasWaiters(c)); + assertTrue(acquired.releaseShared(0)); + c.await(); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.hasWaiters(c)); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + assertFalse(sync.hasWaiters(c)); + sync.release(); + + awaitTermination(t); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertEquals(0, sync.getWaitQueueLength(c)); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + sync.release(); + + final Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertEquals(2, sync.getWaitQueueLength(c)); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + + final Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + t1.start(); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + sync.release(); + + t2.start(); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertTrue(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(2, sync.getWaitingThreads(c).size()); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * awaitUninterruptibly is uninterruptible + */ + public void testAwaitUninterruptibly() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + assertHasWaitersLocked(sync, c, NO_THREADS); + sync.release(); + }}); + + pleaseInterrupt.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + sync.release(); + t.interrupt(); + assertHasWaitersUnlocked(sync, c, t); + assertThreadStaysAlive(t); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * await/awaitNanos/awaitUntil is interruptible + */ + public void testInterruptible_await() { testInterruptible(AwaitMethod.await); } + public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); } + public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); } + public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); } + public void testInterruptible(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + await(c, awaitMethod); + }}); + + pleaseInterrupt.acquireShared(0); + t.interrupt(); + awaitTermination(t); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll_await() { testSignalAll(AwaitMethod.await); } + public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); } + public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); } + public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); } + public void testSignalAll(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired1.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired2.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + acquired1.acquireShared(0); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + sync.release(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * toString indicates current state + */ + public void testToString() { + Mutex sync = new Mutex(); + assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED)); + sync.acquire(); + assertTrue(sync.toString().contains("State = " + Mutex.LOCKED)); + } + + /** + * A serialized AQS deserializes with current state, but no queued threads + */ + public void testSerialization() { + Mutex sync = new Mutex(); + assertFalse(serialClone(sync).isHeldExclusively()); + sync.acquire(); + Thread t = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t); + assertTrue(sync.isHeldExclusively()); + + Mutex clone = serialClone(sync); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, t); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + t.interrupt(); + awaitTermination(t); + sync.release(); + assertFalse(sync.isHeldExclusively()); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + } /** - * Latch isSignalled initially returns false, then true after release + * tryReleaseShared setting state changes getState */ - public void testLatchIsSignalled() { - final BooleanLatch l = new BooleanLatch(); - assertFalse(l.isSignalled()); - l.releaseShared(0); - assertTrue(l.isSignalled()); + public void testGetStateWithReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); } /** - * release and has no effect when already signalled + * releaseShared has no effect when already signalled */ - public void testLatchBoolean() { - final BooleanLatch l = new BooleanLatch(); - assertFalse(l.isSignalled()); - l.releaseShared(0); - assertTrue(l.isSignalled()); - l.releaseShared(0); - assertTrue(l.isSignalled()); + public void testReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); } /** * acquireSharedInterruptibly returns after release, but not before */ - public void testLatchAcquireSharedInterruptibly() { - final BooleanLatch l = new BooleanLatch(); + public void testAcquireSharedInterruptibly() { + final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.acquireSharedInterruptibly(0); - threadAssertTrue(l.isSignalled()); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - assertFalse(l.isSignalled()); - Thread.sleep(SHORT_DELAY_MS); - l.releaseShared(0); - assertTrue(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } - } - - - /** - * acquireSharedTimed returns after release - */ - public void testLatchTimedacquireSharedInterruptibly() { - final BooleanLatch l = new BooleanLatch(); - - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - threadAssertTrue(l.acquireSharedNanos(0, MEDIUM_DELAY_MS* 1000 * 1000)); - threadAssertTrue(l.isSignalled()); - - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - assertFalse(l.isSignalled()); - Thread.sleep(SHORT_DELAY_MS); - l.releaseShared(0); - assertTrue(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertHasSharedQueuedThreads(l, t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); } - + /** - * acquireSharedInterruptibly throws IE if interrupted before released + * tryAcquireSharedNanos returns after release, but not before */ - public void testLatchAcquireSharedInterruptibly_InterruptedException() { + public void testTryAcquireSharedNanos() { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.acquireSharedInterruptibly(0); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - t.start(); - try { - assertFalse(l.isSignalled()); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); } /** - * acquireSharedTimed throws IE if interrupted before released + * acquireSharedInterruptibly is interruptible */ - public void testLatchTimedAwait_InterruptedException() { + public void testAcquireSharedInterruptibly_Interruptible() { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.acquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - assertFalse(l.isSignalled()); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); } /** - * acquireSharedTimed times out if not released before timeout + * tryAcquireSharedNanos is interruptible */ - public void testLatchAwaitTimeout() { + public void testTryAcquireSharedNanos_Interruptible() { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - threadAssertFalse(l.acquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000)); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + l.tryAcquireSharedNanos(0, nanos); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * tryAcquireSharedNanos times out if not released before timeout + */ + public void testTryAcquireSharedNanos_Timeout() { + final BooleanLatch l = new BooleanLatch(); + final BooleanLatch observedQueued = new BooleanLatch(); + final long timeoutMillis = timeoutMillis(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + for (long millis = timeoutMillis(); + !observedQueued.isSignalled(); + millis *= 2) { + long nanos = MILLISECONDS.toNanos(millis); + long startTime = System.nanoTime(); + assertFalse(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(millisElapsedSince(startTime) >= millis); } - }); - t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - assertFalse(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertFalse(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + observedQueued.releaseShared(0); + assertFalse(l.isSignalled()); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * awaitNanos/timed await with 0 wait times out immediately + */ + public void testAwait_Zero() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(0L) <= 0); + assertFalse(c.await(0L, NANOSECONDS)); + sync.release(); } - + + /** + * awaitNanos/timed await with maximum negative wait times does not underflow + */ + public void testAwait_NegativeInfinity() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0); + assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS)); + sync.release(); + } + }