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