--- jsr166/src/test/tck/SemaphoreTest.java 2003/09/25 11:02:41 1.5 +++ jsr166/src/test/tck/SemaphoreTest.java 2003/11/03 13:50:07 1.6 @@ -19,14 +19,57 @@ public class SemaphoreTest extends JSR16 } /** + * Subclass to expose protected methods + */ + static class PublicSemaphore extends Semaphore { + PublicSemaphore(int p, boolean f) { super(p, f); } + public Collection getQueuedThreads() { + return super.getQueuedThreads(); + } + public void reducePermits(int p) { + super.reducePermits(p); + } + } + + /** + * A runnable calling acquire + */ + class InterruptibleLockRunnable implements Runnable { + final Semaphore lock; + InterruptibleLockRunnable(Semaphore l) { lock = l; } + public void run() { + try { + lock.acquire(); + } catch(InterruptedException success){} + } + } + + + /** + * A runnable calling acquire that expects to be + * interrupted + */ + class InterruptedLockRunnable implements Runnable { + final Semaphore lock; + InterruptedLockRunnable(Semaphore l) { lock = l; } + public void run() { + try { + lock.acquire(); + threadShouldThrow(); + } catch(InterruptedException success){} + } + } + + /** * Zero, negative, and positive initial values are allowed in constructor */ public void testConstructor() { - Semaphore s0 = new Semaphore(0); + Semaphore s0 = new Semaphore(0, false); assertEquals(0, s0.availablePermits()); - Semaphore s1 = new Semaphore(-1); + assertFalse(s0.isFair()); + Semaphore s1 = new Semaphore(-1, false); assertEquals(-1, s1.availablePermits()); - Semaphore s2 = new Semaphore(-1); + Semaphore s2 = new Semaphore(-1, false); assertEquals(-1, s2.availablePermits()); } @@ -34,7 +77,7 @@ public class SemaphoreTest extends JSR16 * tryAcquire succeeds when sufficent permits, else fails */ public void testTryAcquireInSameThread() { - Semaphore s = new Semaphore(2); + Semaphore s = new Semaphore(2, false); assertEquals(2, s.availablePermits()); assertTrue(s.tryAcquire()); assertTrue(s.tryAcquire()); @@ -46,7 +89,7 @@ public class SemaphoreTest extends JSR16 * Acquire and release of semaphore succeed if initially available */ public void testAcquireReleaseInSameThread() { - Semaphore s = new Semaphore(1); + Semaphore s = new Semaphore(1, false); try { s.acquire(); s.release(); @@ -69,7 +112,7 @@ public class SemaphoreTest extends JSR16 * initially available */ public void testAcquireUninterruptiblyReleaseInSameThread() { - Semaphore s = new Semaphore(1); + Semaphore s = new Semaphore(1, false); try { s.acquireUninterruptibly(); s.release(); @@ -91,7 +134,7 @@ public class SemaphoreTest extends JSR16 * initially available */ public void testTimedAcquireReleaseInSameThread() { - Semaphore s = new Semaphore(1); + Semaphore s = new Semaphore(1, false); try { assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); s.release(); @@ -113,7 +156,7 @@ public class SemaphoreTest extends JSR16 * A release in one thread enables an acquire in another thread */ public void testAcquireReleaseInDifferentThreads() { - final Semaphore s = new Semaphore(0); + final Semaphore s = new Semaphore(0, false); Thread t = new Thread(new Runnable() { public void run() { try { @@ -144,7 +187,7 @@ public class SemaphoreTest extends JSR16 * A release in one thread enables an uninterruptible acquire in another thread */ public void testUninterruptibleAcquireReleaseInDifferentThreads() { - final Semaphore s = new Semaphore(0); + final Semaphore s = new Semaphore(0, false); Thread t = new Thread(new Runnable() { public void run() { s.acquireUninterruptibly(); @@ -172,7 +215,7 @@ public class SemaphoreTest extends JSR16 * A release in one thread enables a timed acquire in another thread */ public void testTimedAcquireReleaseInDifferentThreads() { - final Semaphore s = new Semaphore(1); + final Semaphore s = new Semaphore(1, false); Thread t = new Thread(new Runnable() { public void run() { try { @@ -203,7 +246,7 @@ public class SemaphoreTest extends JSR16 * A waiting acquire blocks interruptibly */ public void testAcquire_InterruptedException() { - final Semaphore s = new Semaphore(0); + final Semaphore s = new Semaphore(0, false); Thread t = new Thread(new Runnable() { public void run() { try { @@ -226,7 +269,7 @@ public class SemaphoreTest extends JSR16 * A waiting timed acquire blocks interruptibly */ public void testTryAcquire_InterruptedException() { - final Semaphore s = new Semaphore(0); + final Semaphore s = new Semaphore(0, false); Thread t = new Thread(new Runnable() { public void run() { try { @@ -247,10 +290,505 @@ public class SemaphoreTest extends JSR16 } /** + * getQueueLength reports number of waiting threads + */ + public void testGetQueueLength() { + final Semaphore lock = new Semaphore(1, false); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + try { + assertEquals(0, lock.getQueueLength()); + lock.acquireUninterruptibly(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); + } catch(Exception e){ + unexpectedException(); + } + } + + /** + * getQueuedThreads includes waiting threads + */ + public void testGetQueuedThreads() { + final PublicSemaphore lock = new PublicSemaphore(1, false); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + try { + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.acquireUninterruptibly(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } catch(Exception e){ + unexpectedException(); + } + } + + + /** + * reducePermits reduces number of permits + */ + public void testReducePermits() { + PublicSemaphore s = new PublicSemaphore(10, false); + assertEquals(10, s.availablePermits()); + s.reducePermits(1); + assertEquals(9, s.availablePermits()); + s.reducePermits(10); + assertEquals(-1, s.availablePermits()); + } + + /** * a deserialized serialized semaphore has same number of permits */ public void testSerialization() { - Semaphore l = new Semaphore(3); + Semaphore l = new Semaphore(3, false); + try { + l.acquire(); + l.release(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + Semaphore r = (Semaphore) in.readObject(); + assertEquals(3, r.availablePermits()); + assertFalse(r.isFair()); + r.acquire(); + r.release(); + } catch(Exception e){ + unexpectedException(); + } + } + + + /** + * Zero, negative, and positive initial values are allowed in constructor + */ + public void testConstructor_fair() { + Semaphore s0 = new Semaphore(0, true); + assertEquals(0, s0.availablePermits()); + assertTrue(s0.isFair()); + Semaphore s1 = new Semaphore(-1, true); + assertEquals(-1, s1.availablePermits()); + Semaphore s2 = new Semaphore(-1, true); + assertEquals(-1, s2.availablePermits()); + } + + /** + * tryAcquire succeeds when sufficent permits, else fails + */ + public void testTryAcquireInSameThread_fair() { + Semaphore s = new Semaphore(2, true); + assertEquals(2, s.availablePermits()); + assertTrue(s.tryAcquire()); + assertTrue(s.tryAcquire()); + assertEquals(0, s.availablePermits()); + assertFalse(s.tryAcquire()); + } + + /** + * tryAcquire(n) succeeds when sufficent permits, else fails + */ + public void testTryAcquireNInSameThread_fair() { + Semaphore s = new Semaphore(2, true); + assertEquals(2, s.availablePermits()); + assertTrue(s.tryAcquire(2)); + assertEquals(0, s.availablePermits()); + assertFalse(s.tryAcquire()); + } + + /** + * Acquire and release of semaphore succeed if initially available + */ + public void testAcquireReleaseInSameThread_fair() { + Semaphore s = new Semaphore(1, true); + try { + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + assertEquals(1, s.availablePermits()); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * Acquire(n) and release(n) of semaphore succeed if initially available + */ + public void testAcquireReleaseNInSameThread_fair() { + Semaphore s = new Semaphore(1, true); + try { + s.release(1); + s.acquire(1); + s.release(2); + s.acquire(2); + s.release(3); + s.acquire(3); + s.release(4); + s.acquire(4); + s.release(5); + s.acquire(5); + assertEquals(1, s.availablePermits()); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * Acquire(n) and release(n) of semaphore succeed if initially available + */ + public void testAcquireUninterruptiblyReleaseNInSameThread_fair() { + Semaphore s = new Semaphore(1, true); + try { + s.release(1); + s.acquireUninterruptibly(1); + s.release(2); + s.acquireUninterruptibly(2); + s.release(3); + s.acquireUninterruptibly(3); + s.release(4); + s.acquireUninterruptibly(4); + s.release(5); + s.acquireUninterruptibly(5); + assertEquals(1, s.availablePermits()); + } finally { + } + } + + /** + * release(n) in one thread enables timed acquire(n) in another thread + */ + public void testTimedAcquireReleaseNInSameThread_fair() { + Semaphore s = new Semaphore(1, true); + try { + s.release(1); + assertTrue(s.tryAcquire(1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(2); + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(3); + assertTrue(s.tryAcquire(3, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(4); + assertTrue(s.tryAcquire(4, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(5); + assertTrue(s.tryAcquire(5, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + assertEquals(1, s.availablePermits()); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * release in one thread enables timed acquire in another thread + */ + public void testTimedAcquireReleaseInSameThread_fair() { + Semaphore s = new Semaphore(1, true); + try { + assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(); + assertEquals(1, s.availablePermits()); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * A release in one thread enables an acquire in another thread + */ + public void testAcquireReleaseInDifferentThreads_fair() { + final Semaphore s = new Semaphore(0, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.acquire(); + s.acquire(); + s.acquire(); + s.acquire(); + } catch(InterruptedException ie){ + threadUnexpectedException(); + } + } + }); + try { + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + t.join(); + assertEquals(2, s.availablePermits()); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * release(n) in one thread enables acquire(n) in another thread + */ + public void testAcquireReleaseNInDifferentThreads_fair() { + final Semaphore s = new Semaphore(0, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.acquire(2); + s.acquire(2); + s.release(4); + } catch(InterruptedException ie){ + threadUnexpectedException(); + } + } + }); + try { + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(6); + s.acquire(2); + s.acquire(2); + s.release(2); + t.join(); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + + + /** + * release in one thread enables timed acquire in another thread + */ + public void testTimedAcquireReleaseInDifferentThreads_fair() { + final Semaphore s = new Semaphore(1, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + + } catch(InterruptedException ie){ + threadUnexpectedException(); + } + } + }); + t.start(); + try { + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + t.join(); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * release(n) in one thread enables timed acquire(n) in another thread + */ + public void testTimedAcquireReleaseNInDifferentThreads_fair() { + final Semaphore s = new Semaphore(2, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + threadAssertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(2); + threadAssertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(2); + } catch(InterruptedException ie){ + threadUnexpectedException(); + } + } + }); + t.start(); + try { + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(2); + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); + s.release(2); + t.join(); + } catch( InterruptedException e){ + unexpectedException(); + } + } + + /** + * A waiting acquire blocks interruptibly + */ + public void testAcquire_InterruptedException_fair() { + final Semaphore s = new Semaphore(0, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.acquire(); + threadShouldThrow(); + } catch(InterruptedException success){} + } + }); + t.start(); + try { + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } catch(InterruptedException e){ + unexpectedException(); + } + } + + /** + * A waiting acquire(n) blocks interruptibly + */ + public void testAcquireN_InterruptedException_fair() { + final Semaphore s = new Semaphore(2, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.acquire(3); + threadShouldThrow(); + } catch(InterruptedException success){} + } + }); + t.start(); + try { + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } catch(InterruptedException e){ + unexpectedException(); + } + } + + /** + * A waiting tryAcquire blocks interruptibly + */ + public void testTryAcquire_InterruptedException_fair() { + final Semaphore s = new Semaphore(0, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.tryAcquire(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + threadShouldThrow(); + } catch(InterruptedException success){ + } + } + }); + t.start(); + try { + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } catch(InterruptedException e){ + unexpectedException(); + } + } + + /** + * A waiting tryAcquire(n) blocks interruptibly + */ + public void testTryAcquireN_InterruptedException_fair() { + final Semaphore s = new Semaphore(1, true); + Thread t = new Thread(new Runnable() { + public void run() { + try { + s.tryAcquire(4, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + threadShouldThrow(); + } catch(InterruptedException success){ + } + } + }); + t.start(); + try { + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } catch(InterruptedException e){ + unexpectedException(); + } + } + + /** + * getQueueLength reports number of waiting threads + */ + public void testGetQueueLength_fair() { + final Semaphore lock = new Semaphore(1, true); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + try { + assertEquals(0, lock.getQueueLength()); + lock.acquireUninterruptibly(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); + } catch(Exception e){ + unexpectedException(); + } + } + + + /** + * a deserialized serialized semaphore has same number of permits + */ + public void testSerialization_fair() { + Semaphore l = new Semaphore(3, true); + try { l.acquire(); l.release(); @@ -263,6 +801,7 @@ public class SemaphoreTest extends JSR16 ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); Semaphore r = (Semaphore) in.readObject(); assertEquals(3, r.availablePermits()); + assertTrue(r.isFair()); r.acquire(); r.release(); } catch(Exception e){ @@ -270,4 +809,5 @@ public class SemaphoreTest extends JSR16 } } + }