1 /*
2  * Written by Doug Lea with assistance from members of JCP JSR-166
3  * Expert Group and released to the public domain, as explained at
4  * http://creativecommons.org/publicdomain/zero/1.0/
5  * Other contributors include Andrew Wright, Jeffrey Hayes,
6  * Pat Fisher, Mike Judd.
7  */
8 
9 package jsr166;
10 
11 import junit.framework.*;
12 import java.util.*;
13 import java.util.concurrent.CountDownLatch;
14 import java.util.concurrent.Semaphore;
15 import static java.util.concurrent.TimeUnit.MILLISECONDS;
16 
17 public class SemaphoreTest extends JSR166TestCase {
18 
19     /**
20      * Subclass to expose protected methods
21      */
22     static class PublicSemaphore extends Semaphore {
PublicSemaphore(int permits)23         PublicSemaphore(int permits) { super(permits); }
PublicSemaphore(int permits, boolean fair)24         PublicSemaphore(int permits, boolean fair) { super(permits, fair); }
getQueuedThreads()25         public Collection<Thread> getQueuedThreads() {
26             return super.getQueuedThreads();
27         }
hasQueuedThread(Thread t)28         public boolean hasQueuedThread(Thread t) {
29             return super.getQueuedThreads().contains(t);
30         }
reducePermits(int reduction)31         public void reducePermits(int reduction) {
32             super.reducePermits(reduction);
33         }
34     }
35 
36     /**
37      * A runnable calling acquire
38      */
39     class InterruptibleLockRunnable extends CheckedRunnable {
40         final Semaphore lock;
InterruptibleLockRunnable(Semaphore s)41         InterruptibleLockRunnable(Semaphore s) { lock = s; }
realRun()42         public void realRun() {
43             try {
44                 lock.acquire();
45             }
46             catch (InterruptedException ignored) {}
47         }
48     }
49 
50     /**
51      * A runnable calling acquire that expects to be interrupted
52      */
53     class InterruptedLockRunnable extends CheckedInterruptedRunnable {
54         final Semaphore lock;
InterruptedLockRunnable(Semaphore s)55         InterruptedLockRunnable(Semaphore s) { lock = s; }
realRun()56         public void realRun() throws InterruptedException {
57             lock.acquire();
58         }
59     }
60 
61     /**
62      * Spin-waits until s.hasQueuedThread(t) becomes true.
63      */
waitForQueuedThread(PublicSemaphore s, Thread t)64     void waitForQueuedThread(PublicSemaphore s, Thread t) {
65         long startTime = System.nanoTime();
66         while (!s.hasQueuedThread(t)) {
67             if (millisElapsedSince(startTime) > LONG_DELAY_MS)
68                 throw new AssertionFailedError("timed out");
69             Thread.yield();
70         }
71         assertTrue(s.hasQueuedThreads());
72         assertTrue(t.isAlive());
73     }
74 
75     /**
76      * Spin-waits until s.hasQueuedThreads() becomes true.
77      */
waitForQueuedThreads(Semaphore s)78     void waitForQueuedThreads(Semaphore s) {
79         long startTime = System.nanoTime();
80         while (!s.hasQueuedThreads()) {
81             if (millisElapsedSince(startTime) > LONG_DELAY_MS)
82                 throw new AssertionFailedError("timed out");
83             Thread.yield();
84         }
85     }
86 
87     enum AcquireMethod {
acquire()88         acquire() {
89             void acquire(Semaphore s) throws InterruptedException {
90                 s.acquire();
91             }
92         },
acquireN()93         acquireN() {
94             void acquire(Semaphore s, int permits) throws InterruptedException {
95                 s.acquire(permits);
96             }
97         },
acquireUninterruptibly()98         acquireUninterruptibly() {
99             void acquire(Semaphore s) {
100                 s.acquireUninterruptibly();
101             }
102         },
acquireUninterruptiblyN()103         acquireUninterruptiblyN() {
104             void acquire(Semaphore s, int permits) {
105                 s.acquireUninterruptibly(permits);
106             }
107         },
tryAcquire()108         tryAcquire() {
109             void acquire(Semaphore s) {
110                 assertTrue(s.tryAcquire());
111             }
112         },
tryAcquireN()113         tryAcquireN() {
114             void acquire(Semaphore s, int permits) {
115                 assertTrue(s.tryAcquire(permits));
116             }
117         },
tryAcquireTimed()118         tryAcquireTimed() {
119             void acquire(Semaphore s) throws InterruptedException {
120                 assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS));
121             }
122         },
123         tryAcquireTimedN {
acquire(Semaphore s, int permits)124             void acquire(Semaphore s, int permits) throws InterruptedException {
125                 assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS));
126             }
127         };
128 
129         // Intentionally meta-circular
130 
131         /** Acquires 1 permit. */
acquire(Semaphore s)132         void acquire(Semaphore s) throws InterruptedException {
133             acquire(s, 1);
134         }
135         /** Acquires the given number of permits. */
acquire(Semaphore s, int permits)136         void acquire(Semaphore s, int permits) throws InterruptedException {
137             for (int i = 0; i < permits; i++)
138                 acquire(s);
139         }
140     }
141 
142     /**
143      * Zero, negative, and positive initial values are allowed in constructor
144      */
testConstructor()145     public void testConstructor()      { testConstructor(false); }
testConstructor_fair()146     public void testConstructor_fair() { testConstructor(true); }
testConstructor(boolean fair)147     public void testConstructor(boolean fair) {
148         for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
149             Semaphore s = new Semaphore(permits, fair);
150             assertEquals(permits, s.availablePermits());
151             assertEquals(fair, s.isFair());
152         }
153     }
154 
155     /**
156      * Constructor without fairness argument behaves as nonfair
157      */
testConstructorDefaultsToNonFair()158     public void testConstructorDefaultsToNonFair() {
159         for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
160             Semaphore s = new Semaphore(permits);
161             assertEquals(permits, s.availablePermits());
162             assertFalse(s.isFair());
163         }
164     }
165 
166     /**
167      * tryAcquire succeeds when sufficient permits, else fails
168      */
testTryAcquireInSameThread()169     public void testTryAcquireInSameThread()      { testTryAcquireInSameThread(false); }
testTryAcquireInSameThread_fair()170     public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); }
testTryAcquireInSameThread(boolean fair)171     public void testTryAcquireInSameThread(boolean fair) {
172         Semaphore s = new Semaphore(2, fair);
173         assertEquals(2, s.availablePermits());
174         assertTrue(s.tryAcquire());
175         assertTrue(s.tryAcquire());
176         assertEquals(0, s.availablePermits());
177         assertFalse(s.tryAcquire());
178         assertFalse(s.tryAcquire());
179         assertEquals(0, s.availablePermits());
180     }
181 
182     /**
183      * timed tryAcquire times out
184      */
testTryAcquire_timeout()185     public void testTryAcquire_timeout()      { testTryAcquire_timeout(false); }
testTryAcquire_timeout_fair()186     public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); }
testTryAcquire_timeout(boolean fair)187     public void testTryAcquire_timeout(boolean fair) {
188         Semaphore s = new Semaphore(0, fair);
189         long startTime = System.nanoTime();
190         try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); }
191         catch (InterruptedException e) { threadUnexpectedException(e); }
192         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
193     }
194 
195     /**
196      * timed tryAcquire(N) times out
197      */
testTryAcquireN_timeout()198     public void testTryAcquireN_timeout()      { testTryAcquireN_timeout(false); }
testTryAcquireN_timeout_fair()199     public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); }
testTryAcquireN_timeout(boolean fair)200     public void testTryAcquireN_timeout(boolean fair) {
201         Semaphore s = new Semaphore(2, fair);
202         long startTime = System.nanoTime();
203         try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); }
204         catch (InterruptedException e) { threadUnexpectedException(e); }
205         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
206     }
207 
208     /**
209      * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N)
210      * are interruptible
211      */
testInterruptible_acquire()212     public void testInterruptible_acquire()               { testInterruptible(false, AcquireMethod.acquire); }
testInterruptible_acquire_fair()213     public void testInterruptible_acquire_fair()          { testInterruptible(true,  AcquireMethod.acquire); }
testInterruptible_acquireN()214     public void testInterruptible_acquireN()              { testInterruptible(false, AcquireMethod.acquireN); }
testInterruptible_acquireN_fair()215     public void testInterruptible_acquireN_fair()         { testInterruptible(true,  AcquireMethod.acquireN); }
testInterruptible_tryAcquireTimed()216     public void testInterruptible_tryAcquireTimed()       { testInterruptible(false, AcquireMethod.tryAcquireTimed); }
testInterruptible_tryAcquireTimed_fair()217     public void testInterruptible_tryAcquireTimed_fair()  { testInterruptible(true,  AcquireMethod.tryAcquireTimed); }
testInterruptible_tryAcquireTimedN()218     public void testInterruptible_tryAcquireTimedN()      { testInterruptible(false, AcquireMethod.tryAcquireTimedN); }
testInterruptible_tryAcquireTimedN_fair()219     public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true,  AcquireMethod.tryAcquireTimedN); }
testInterruptible(boolean fair, final AcquireMethod acquirer)220     public void testInterruptible(boolean fair, final AcquireMethod acquirer) {
221         final PublicSemaphore s = new PublicSemaphore(0, fair);
222         final Semaphore pleaseInterrupt = new Semaphore(0, fair);
223         Thread t = newStartedThread(new CheckedRunnable() {
224             public void realRun() {
225                 // Interrupt before acquire
226                 Thread.currentThread().interrupt();
227                 try {
228                     acquirer.acquire(s);
229                     shouldThrow();
230                 } catch (InterruptedException success) {}
231 
232                 // Interrupt during acquire
233                 try {
234                     acquirer.acquire(s);
235                     shouldThrow();
236                 } catch (InterruptedException success) {}
237 
238                 // Interrupt before acquire(N)
239                 Thread.currentThread().interrupt();
240                 try {
241                     acquirer.acquire(s, 3);
242                     shouldThrow();
243                 } catch (InterruptedException success) {}
244 
245                 pleaseInterrupt.release();
246 
247                 // Interrupt during acquire(N)
248                 try {
249                     acquirer.acquire(s, 3);
250                     shouldThrow();
251                 } catch (InterruptedException success) {}
252             }});
253 
254         waitForQueuedThread(s, t);
255         t.interrupt();
256         await(pleaseInterrupt);
257         waitForQueuedThread(s, t);
258         t.interrupt();
259         awaitTermination(t);
260     }
261 
262     /**
263      * acquireUninterruptibly(), acquireUninterruptibly(N) are
264      * uninterruptible
265      */
testUninterruptible_acquireUninterruptibly()266     public void testUninterruptible_acquireUninterruptibly()       { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); }
testUninterruptible_acquireUninterruptibly_fair()267     public void testUninterruptible_acquireUninterruptibly_fair()  { testUninterruptible(true,  AcquireMethod.acquireUninterruptibly); }
testUninterruptible_acquireUninterruptiblyN()268     public void testUninterruptible_acquireUninterruptiblyN()      { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); }
testUninterruptible_acquireUninterruptiblyN_fair()269     public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true,  AcquireMethod.acquireUninterruptiblyN); }
testUninterruptible(boolean fair, final AcquireMethod acquirer)270     public void testUninterruptible(boolean fair, final AcquireMethod acquirer) {
271         final PublicSemaphore s = new PublicSemaphore(0, fair);
272         final Semaphore pleaseInterrupt = new Semaphore(-1, fair);
273 
274         Thread t1 = newStartedThread(new CheckedRunnable() {
275             public void realRun() throws InterruptedException {
276                 // Interrupt before acquire
277                 pleaseInterrupt.release();
278                 Thread.currentThread().interrupt();
279                 acquirer.acquire(s);
280                 assertTrue(Thread.interrupted());
281             }});
282 
283         Thread t2 = newStartedThread(new CheckedRunnable() {
284             public void realRun() throws InterruptedException {
285                 // Interrupt during acquire
286                 pleaseInterrupt.release();
287                 acquirer.acquire(s);
288                 assertTrue(Thread.interrupted());
289             }});
290 
291         await(pleaseInterrupt);
292         waitForQueuedThread(s, t1);
293         waitForQueuedThread(s, t2);
294         t2.interrupt();
295 
296         assertThreadStaysAlive(t1);
297         assertTrue(t2.isAlive());
298 
299         s.release(2);
300 
301         awaitTermination(t1);
302         awaitTermination(t2);
303     }
304 
305     /**
306      * hasQueuedThreads reports whether there are waiting threads
307      */
testHasQueuedThreads()308     public void testHasQueuedThreads()      { testHasQueuedThreads(false); }
testHasQueuedThreads_fair()309     public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); }
testHasQueuedThreads(boolean fair)310     public void testHasQueuedThreads(boolean fair) {
311         final PublicSemaphore lock = new PublicSemaphore(1, fair);
312         assertFalse(lock.hasQueuedThreads());
313         lock.acquireUninterruptibly();
314         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
315         waitForQueuedThread(lock, t1);
316         assertTrue(lock.hasQueuedThreads());
317         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
318         waitForQueuedThread(lock, t2);
319         assertTrue(lock.hasQueuedThreads());
320         t1.interrupt();
321         awaitTermination(t1);
322         assertTrue(lock.hasQueuedThreads());
323         lock.release();
324         awaitTermination(t2);
325         assertFalse(lock.hasQueuedThreads());
326     }
327 
328     /**
329      * getQueueLength reports number of waiting threads
330      */
testGetQueueLength()331     public void testGetQueueLength()      { testGetQueueLength(false); }
testGetQueueLength_fair()332     public void testGetQueueLength_fair() { testGetQueueLength(true); }
testGetQueueLength(boolean fair)333     public void testGetQueueLength(boolean fair) {
334         final PublicSemaphore lock = new PublicSemaphore(1, fair);
335         assertEquals(0, lock.getQueueLength());
336         lock.acquireUninterruptibly();
337         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
338         waitForQueuedThread(lock, t1);
339         assertEquals(1, lock.getQueueLength());
340         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
341         waitForQueuedThread(lock, t2);
342         assertEquals(2, lock.getQueueLength());
343         t1.interrupt();
344         awaitTermination(t1);
345         assertEquals(1, lock.getQueueLength());
346         lock.release();
347         awaitTermination(t2);
348         assertEquals(0, lock.getQueueLength());
349     }
350 
351     /**
352      * getQueuedThreads includes waiting threads
353      */
testGetQueuedThreads()354     public void testGetQueuedThreads()      { testGetQueuedThreads(false); }
testGetQueuedThreads_fair()355     public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); }
testGetQueuedThreads(boolean fair)356     public void testGetQueuedThreads(boolean fair) {
357         final PublicSemaphore lock = new PublicSemaphore(1, fair);
358         assertTrue(lock.getQueuedThreads().isEmpty());
359         lock.acquireUninterruptibly();
360         assertTrue(lock.getQueuedThreads().isEmpty());
361         Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
362         waitForQueuedThread(lock, t1);
363         assertTrue(lock.getQueuedThreads().contains(t1));
364         Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
365         waitForQueuedThread(lock, t2);
366         assertTrue(lock.getQueuedThreads().contains(t1));
367         assertTrue(lock.getQueuedThreads().contains(t2));
368         t1.interrupt();
369         awaitTermination(t1);
370         assertFalse(lock.getQueuedThreads().contains(t1));
371         assertTrue(lock.getQueuedThreads().contains(t2));
372         lock.release();
373         awaitTermination(t2);
374         assertTrue(lock.getQueuedThreads().isEmpty());
375     }
376 
377     /**
378      * drainPermits reports and removes given number of permits
379      */
testDrainPermits()380     public void testDrainPermits()      { testDrainPermits(false); }
testDrainPermits_fair()381     public void testDrainPermits_fair() { testDrainPermits(true); }
testDrainPermits(boolean fair)382     public void testDrainPermits(boolean fair) {
383         Semaphore s = new Semaphore(0, fair);
384         assertEquals(0, s.availablePermits());
385         assertEquals(0, s.drainPermits());
386         s.release(10);
387         assertEquals(10, s.availablePermits());
388         assertEquals(10, s.drainPermits());
389         assertEquals(0, s.availablePermits());
390         assertEquals(0, s.drainPermits());
391     }
392 
393     /**
394      * release(-N) throws IllegalArgumentException
395      */
testReleaseIAE()396     public void testReleaseIAE()      { testReleaseIAE(false); }
testReleaseIAE_fair()397     public void testReleaseIAE_fair() { testReleaseIAE(true); }
testReleaseIAE(boolean fair)398     public void testReleaseIAE(boolean fair) {
399         Semaphore s = new Semaphore(10, fair);
400         try {
401             s.release(-1);
402             shouldThrow();
403         } catch (IllegalArgumentException success) {}
404     }
405 
406     /**
407      * reducePermits(-N) throws IllegalArgumentException
408      */
testReducePermitsIAE()409     public void testReducePermitsIAE()      { testReducePermitsIAE(false); }
testReducePermitsIAE_fair()410     public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); }
testReducePermitsIAE(boolean fair)411     public void testReducePermitsIAE(boolean fair) {
412         PublicSemaphore s = new PublicSemaphore(10, fair);
413         try {
414             s.reducePermits(-1);
415             shouldThrow();
416         } catch (IllegalArgumentException success) {}
417     }
418 
419     /**
420      * reducePermits reduces number of permits
421      */
testReducePermits()422     public void testReducePermits()      { testReducePermits(false); }
testReducePermits_fair()423     public void testReducePermits_fair() { testReducePermits(true); }
testReducePermits(boolean fair)424     public void testReducePermits(boolean fair) {
425         PublicSemaphore s = new PublicSemaphore(10, fair);
426         assertEquals(10, s.availablePermits());
427         s.reducePermits(0);
428         assertEquals(10, s.availablePermits());
429         s.reducePermits(1);
430         assertEquals(9, s.availablePermits());
431         s.reducePermits(10);
432         assertEquals(-1, s.availablePermits());
433         s.reducePermits(10);
434         assertEquals(-11, s.availablePermits());
435         s.reducePermits(0);
436         assertEquals(-11, s.availablePermits());
437     }
438 
439     /**
440      * a reserialized semaphore has same number of permits and
441      * fairness, but no queued threads
442      */
testSerialization()443     public void testSerialization()      { testSerialization(false); }
testSerialization_fair()444     public void testSerialization_fair() { testSerialization(true); }
testSerialization(boolean fair)445     public void testSerialization(boolean fair) {
446         try {
447             Semaphore s = new Semaphore(3, fair);
448             s.acquire();
449             s.acquire();
450             s.release();
451 
452             Semaphore clone = serialClone(s);
453             assertEquals(fair, s.isFair());
454             assertEquals(fair, clone.isFair());
455             assertEquals(2, s.availablePermits());
456             assertEquals(2, clone.availablePermits());
457             clone.acquire();
458             clone.acquire();
459             clone.release();
460             assertEquals(2, s.availablePermits());
461             assertEquals(1, clone.availablePermits());
462 
463             s = new Semaphore(0, fair);
464             Thread t = newStartedThread(new InterruptibleLockRunnable(s));
465             waitForQueuedThreads(s);
466             clone = serialClone(s);
467             assertEquals(fair, s.isFair());
468             assertEquals(fair, clone.isFair());
469             assertEquals(0, s.availablePermits());
470             assertEquals(0, clone.availablePermits());
471             assertTrue(s.hasQueuedThreads());
472             assertFalse(clone.hasQueuedThreads());
473             s.release();
474             awaitTermination(t);
475             assertFalse(s.hasQueuedThreads());
476             assertFalse(clone.hasQueuedThreads());
477         } catch (InterruptedException e) { threadUnexpectedException(e); }
478     }
479 
480     /**
481      * tryAcquire(n) succeeds when sufficient permits, else fails
482      */
testTryAcquireNInSameThread()483     public void testTryAcquireNInSameThread()      { testTryAcquireNInSameThread(false); }
testTryAcquireNInSameThread_fair()484     public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); }
testTryAcquireNInSameThread(boolean fair)485     public void testTryAcquireNInSameThread(boolean fair) {
486         Semaphore s = new Semaphore(2, fair);
487         assertEquals(2, s.availablePermits());
488         assertFalse(s.tryAcquire(3));
489         assertEquals(2, s.availablePermits());
490         assertTrue(s.tryAcquire(2));
491         assertEquals(0, s.availablePermits());
492         assertFalse(s.tryAcquire(1));
493         assertFalse(s.tryAcquire(2));
494         assertEquals(0, s.availablePermits());
495     }
496 
497     /**
498      * acquire succeeds if permits available
499      */
testReleaseAcquireSameThread_acquire()500     public void testReleaseAcquireSameThread_acquire()       { testReleaseAcquireSameThread(false, AcquireMethod.acquire); }
testReleaseAcquireSameThread_acquire_fair()501     public void testReleaseAcquireSameThread_acquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquire); }
testReleaseAcquireSameThread_acquireN()502     public void testReleaseAcquireSameThread_acquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); }
testReleaseAcquireSameThread_acquireN_fair()503     public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); }
testReleaseAcquireSameThread_acquireUninterruptibly()504     public void testReleaseAcquireSameThread_acquireUninterruptibly()       { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireSameThread_acquireUninterruptibly_fair()505     public void testReleaseAcquireSameThread_acquireUninterruptibly_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireSameThread_acquireUninterruptiblyN()506     public void testReleaseAcquireSameThread_acquireUninterruptiblyN()      { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireSameThread_acquireUninterruptiblyN_fair()507     public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireSameThread_tryAcquire()508     public void testReleaseAcquireSameThread_tryAcquire()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); }
testReleaseAcquireSameThread_tryAcquire_fair()509     public void testReleaseAcquireSameThread_tryAcquire_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); }
testReleaseAcquireSameThread_tryAcquireN()510     public void testReleaseAcquireSameThread_tryAcquireN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); }
testReleaseAcquireSameThread_tryAcquireN_fair()511     public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); }
testReleaseAcquireSameThread_tryAcquireTimed()512     public void testReleaseAcquireSameThread_tryAcquireTimed()       { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); }
testReleaseAcquireSameThread_tryAcquireTimed_fair()513     public void testReleaseAcquireSameThread_tryAcquireTimed_fair()  { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); }
testReleaseAcquireSameThread_tryAcquireTimedN()514     public void testReleaseAcquireSameThread_tryAcquireTimedN()      { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); }
testReleaseAcquireSameThread_tryAcquireTimedN_fair()515     public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); }
testReleaseAcquireSameThread(boolean fair, final AcquireMethod acquirer)516     public void testReleaseAcquireSameThread(boolean fair,
517                                              final AcquireMethod acquirer) {
518         Semaphore s = new Semaphore(1, fair);
519         for (int i = 1; i < 6; i++) {
520             s.release(i);
521             assertEquals(1 + i, s.availablePermits());
522             try {
523                 acquirer.acquire(s, i);
524             } catch (InterruptedException e) { threadUnexpectedException(e); }
525             assertEquals(1, s.availablePermits());
526         }
527     }
528 
529     /**
530      * release in one thread enables acquire in another thread
531      */
testReleaseAcquireDifferentThreads_acquire()532     public void testReleaseAcquireDifferentThreads_acquire()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); }
testReleaseAcquireDifferentThreads_acquire_fair()533     public void testReleaseAcquireDifferentThreads_acquire_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); }
testReleaseAcquireDifferentThreads_acquireN()534     public void testReleaseAcquireDifferentThreads_acquireN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); }
testReleaseAcquireDifferentThreads_acquireN_fair()535     public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); }
testReleaseAcquireDifferentThreads_acquireUninterruptibly()536     public void testReleaseAcquireDifferentThreads_acquireUninterruptibly()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair()537     public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireDifferentThreads_acquireUninterruptiblyN()538     public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair()539     public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
testReleaseAcquireDifferentThreads_tryAcquireTimed()540     public void testReleaseAcquireDifferentThreads_tryAcquireTimed()       { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); }
testReleaseAcquireDifferentThreads_tryAcquireTimed_fair()541     public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair()  { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); }
testReleaseAcquireDifferentThreads_tryAcquireTimedN()542     public void testReleaseAcquireDifferentThreads_tryAcquireTimedN()      { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); }
testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair()543     public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); }
testReleaseAcquireDifferentThreads(boolean fair, final AcquireMethod acquirer)544     public void testReleaseAcquireDifferentThreads(boolean fair,
545                                                    final AcquireMethod acquirer) {
546         final Semaphore s = new Semaphore(0, fair);
547         final int rounds = 4;
548         long startTime = System.nanoTime();
549         Thread t = newStartedThread(new CheckedRunnable() {
550             public void realRun() throws InterruptedException {
551                 for (int i = 0; i < rounds; i++) {
552                     assertFalse(s.hasQueuedThreads());
553                     if (i % 2 == 0)
554                         acquirer.acquire(s);
555                     else
556                         acquirer.acquire(s, 3);
557                 }}});
558 
559         for (int i = 0; i < rounds; i++) {
560             while (! (s.availablePermits() == 0 && s.hasQueuedThreads()))
561                 Thread.yield();
562             assertTrue(t.isAlive());
563             if (i % 2 == 0)
564                 s.release();
565             else
566                 s.release(3);
567         }
568         awaitTermination(t);
569         assertEquals(0, s.availablePermits());
570         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
571     }
572 
573     /**
574      * fair locks are strictly FIFO
575      */
576     public void testFairLocksFifo() {
577         final PublicSemaphore s = new PublicSemaphore(1, true);
578         final CountDownLatch pleaseRelease = new CountDownLatch(1);
579         Thread t1 = newStartedThread(new CheckedRunnable() {
580             public void realRun() throws InterruptedException {
581                 // Will block; permits are available, but not three
582                 s.acquire(3);
583             }});
584 
585         waitForQueuedThreads(s);
586 
587         Thread t2 = newStartedThread(new CheckedRunnable() {
588             public void realRun() throws InterruptedException {
589                 // Will fail, even though 1 permit is available
590                 assertFalse(s.tryAcquire(0L, MILLISECONDS));
591                 assertFalse(s.tryAcquire(1, 0L, MILLISECONDS));
592 
593                 // untimed tryAcquire will barge and succeed
594                 assertTrue(s.tryAcquire());
595                 s.release(2);
596                 assertTrue(s.tryAcquire(2));
597                 s.release();
598 
599                 pleaseRelease.countDown();
600                 // Will queue up behind t1, even though 1 permit is available
601                 s.acquire();
602             }});
603 
604         await(pleaseRelease);
605         waitForQueuedThread(s, t2);
606         s.release(2);
607         awaitTermination(t1);
608         assertTrue(t2.isAlive());
609         s.release();
610         awaitTermination(t2);
611    }
612 
613     /**
614      * toString indicates current number of permits
615      */
616     public void testToString()      { testToString(false); }
617     public void testToString_fair() { testToString(true); }
618     public void testToString(boolean fair) {
619         PublicSemaphore s = new PublicSemaphore(0, fair);
620         assertTrue(s.toString().contains("Permits = 0"));
621         s.release();
622         assertTrue(s.toString().contains("Permits = 1"));
623         s.release(2);
624         assertTrue(s.toString().contains("Permits = 3"));
625         s.reducePermits(5);
626         assertTrue(s.toString().contains("Permits = -2"));
627     }
628 
629 }
630