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