1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23/*
24 * This file is available under and governed by the GNU General Public
25 * License version 2 only, as published by the Free Software Foundation.
26 * However, the following notice accompanied the original version of this
27 * file:
28 *
29 * Written by Doug Lea with assistance from members of JCP JSR-166
30 * Expert Group and released to the public domain, as explained at
31 * http://creativecommons.org/publicdomain/zero/1.0/
32 * Other contributors include Andrew Wright, Jeffrey Hayes,
33 * Pat Fisher, Mike Judd.
34 */
35
36import static java.util.concurrent.TimeUnit.MILLISECONDS;
37
38import java.util.concurrent.BrokenBarrierException;
39import java.util.concurrent.CountDownLatch;
40import java.util.concurrent.CyclicBarrier;
41import java.util.concurrent.TimeoutException;
42import java.util.concurrent.atomic.AtomicBoolean;
43import java.util.concurrent.atomic.AtomicInteger;
44
45import junit.framework.Test;
46import junit.framework.TestSuite;
47
48public class CyclicBarrierTest extends JSR166TestCase {
49    public static void main(String[] args) {
50        main(suite(), args);
51    }
52    public static Test suite() {
53        return new TestSuite(CyclicBarrierTest.class);
54    }
55
56    /**
57     * Spin-waits till the number of waiters == numberOfWaiters.
58     */
59    void awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters) {
60        long startTime = System.nanoTime();
61        while (barrier.getNumberWaiting() != numberOfWaiters) {
62            if (millisElapsedSince(startTime) > LONG_DELAY_MS)
63                fail("timed out");
64            Thread.yield();
65        }
66    }
67
68    /**
69     * Creating with negative parties throws IAE
70     */
71    public void testConstructor1() {
72        try {
73            new CyclicBarrier(-1, (Runnable)null);
74            shouldThrow();
75        } catch (IllegalArgumentException success) {}
76    }
77
78    /**
79     * Creating with negative parties and no action throws IAE
80     */
81    public void testConstructor2() {
82        try {
83            new CyclicBarrier(-1);
84            shouldThrow();
85        } catch (IllegalArgumentException success) {}
86    }
87
88    /**
89     * getParties returns the number of parties given in constructor
90     */
91    public void testGetParties() {
92        CyclicBarrier b = new CyclicBarrier(2);
93        assertEquals(2, b.getParties());
94        assertEquals(0, b.getNumberWaiting());
95    }
96
97    /**
98     * A 1-party barrier triggers after single await
99     */
100    public void testSingleParty() throws Exception {
101        CyclicBarrier b = new CyclicBarrier(1);
102        assertEquals(1, b.getParties());
103        assertEquals(0, b.getNumberWaiting());
104        b.await();
105        b.await();
106        assertEquals(0, b.getNumberWaiting());
107    }
108
109    /**
110     * The supplied barrier action is run at barrier
111     */
112    public void testBarrierAction() throws Exception {
113        final AtomicInteger count = new AtomicInteger(0);
114        final Runnable incCount = new Runnable() { public void run() {
115            count.getAndIncrement(); }};
116        CyclicBarrier b = new CyclicBarrier(1, incCount);
117        assertEquals(1, b.getParties());
118        assertEquals(0, b.getNumberWaiting());
119        b.await();
120        b.await();
121        assertEquals(0, b.getNumberWaiting());
122        assertEquals(2, count.get());
123    }
124
125    /**
126     * A 2-party/thread barrier triggers after both threads invoke await
127     */
128    public void testTwoParties() throws Exception {
129        final CyclicBarrier b = new CyclicBarrier(2);
130        Thread t = newStartedThread(new CheckedRunnable() {
131            public void realRun() throws Exception {
132                b.await();
133                b.await();
134                b.await();
135                b.await();
136            }});
137
138        b.await();
139        b.await();
140        b.await();
141        b.await();
142        awaitTermination(t);
143    }
144
145    /**
146     * An interruption in one party causes others waiting in await to
147     * throw BrokenBarrierException
148     */
149    public void testAwait1_Interrupted_BrokenBarrier() {
150        final CyclicBarrier c = new CyclicBarrier(3);
151        final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
152        Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
153            public void realRun() throws Exception {
154                pleaseInterrupt.countDown();
155                c.await();
156            }};
157        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
158            public void realRun() throws Exception {
159                pleaseInterrupt.countDown();
160                c.await();
161            }};
162
163        t1.start();
164        t2.start();
165        await(pleaseInterrupt);
166        t1.interrupt();
167        awaitTermination(t1);
168        awaitTermination(t2);
169    }
170
171    /**
172     * An interruption in one party causes others waiting in timed await to
173     * throw BrokenBarrierException
174     */
175    public void testAwait2_Interrupted_BrokenBarrier() throws Exception {
176        final CyclicBarrier c = new CyclicBarrier(3);
177        final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
178        Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
179            public void realRun() throws Exception {
180                pleaseInterrupt.countDown();
181                c.await(LONG_DELAY_MS, MILLISECONDS);
182            }};
183        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
184            public void realRun() throws Exception {
185                pleaseInterrupt.countDown();
186                c.await(LONG_DELAY_MS, MILLISECONDS);
187            }};
188
189        t1.start();
190        t2.start();
191        await(pleaseInterrupt);
192        t1.interrupt();
193        awaitTermination(t1);
194        awaitTermination(t2);
195    }
196
197    /**
198     * A timeout in timed await throws TimeoutException
199     */
200    public void testAwait3_TimeoutException() throws InterruptedException {
201        final CyclicBarrier c = new CyclicBarrier(2);
202        Thread t = newStartedThread(new CheckedRunnable() {
203            public void realRun() throws Exception {
204                long startTime = System.nanoTime();
205                try {
206                    c.await(timeoutMillis(), MILLISECONDS);
207                    shouldThrow();
208                } catch (TimeoutException success) {}
209                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
210            }});
211
212        awaitTermination(t);
213    }
214
215    /**
216     * A timeout in one party causes others waiting in timed await to
217     * throw BrokenBarrierException
218     */
219    public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException {
220        final CyclicBarrier c = new CyclicBarrier(3);
221        Thread t1 = newStartedThread(new CheckedRunnable() {
222            public void realRun() throws Exception {
223                try {
224                    c.await(LONG_DELAY_MS, MILLISECONDS);
225                    shouldThrow();
226                } catch (BrokenBarrierException success) {}
227            }});
228        Thread t2 = newStartedThread(new CheckedRunnable() {
229            public void realRun() throws Exception {
230                awaitNumberWaiting(c, 1);
231                long startTime = System.nanoTime();
232                try {
233                    c.await(timeoutMillis(), MILLISECONDS);
234                    shouldThrow();
235                } catch (TimeoutException success) {}
236                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
237            }});
238
239        awaitTermination(t1);
240        awaitTermination(t2);
241    }
242
243    /**
244     * A timeout in one party causes others waiting in await to
245     * throw BrokenBarrierException
246     */
247    public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException {
248        final CyclicBarrier c = new CyclicBarrier(3);
249        Thread t1 = newStartedThread(new CheckedRunnable() {
250            public void realRun() throws Exception {
251                try {
252                    c.await();
253                    shouldThrow();
254                } catch (BrokenBarrierException success) {}
255            }});
256        Thread t2 = newStartedThread(new CheckedRunnable() {
257            public void realRun() throws Exception {
258                awaitNumberWaiting(c, 1);
259                long startTime = System.nanoTime();
260                try {
261                    c.await(timeoutMillis(), MILLISECONDS);
262                    shouldThrow();
263                } catch (TimeoutException success) {}
264                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
265            }});
266
267        awaitTermination(t1);
268        awaitTermination(t2);
269    }
270
271    /**
272     * A reset of an active barrier causes waiting threads to throw
273     * BrokenBarrierException
274     */
275    public void testReset_BrokenBarrier() throws InterruptedException {
276        final CyclicBarrier c = new CyclicBarrier(3);
277        final CountDownLatch pleaseReset = new CountDownLatch(2);
278        Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
279            public void realRun() throws Exception {
280                pleaseReset.countDown();
281                c.await();
282            }};
283        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
284            public void realRun() throws Exception {
285                pleaseReset.countDown();
286                c.await();
287            }};
288
289        t1.start();
290        t2.start();
291        await(pleaseReset);
292
293        awaitNumberWaiting(c, 2);
294        c.reset();
295        awaitTermination(t1);
296        awaitTermination(t2);
297    }
298
299    /**
300     * A reset before threads enter barrier does not throw
301     * BrokenBarrierException
302     */
303    public void testReset_NoBrokenBarrier() throws Exception {
304        final CyclicBarrier c = new CyclicBarrier(3);
305        c.reset();
306
307        Thread t1 = newStartedThread(new CheckedRunnable() {
308            public void realRun() throws Exception {
309                c.await();
310            }});
311        Thread t2 = newStartedThread(new CheckedRunnable() {
312            public void realRun() throws Exception {
313                c.await();
314            }});
315
316        c.await();
317        awaitTermination(t1);
318        awaitTermination(t2);
319    }
320
321    /**
322     * All threads block while a barrier is broken.
323     */
324    public void testReset_Leakage() throws InterruptedException {
325        final CyclicBarrier c = new CyclicBarrier(2);
326        final AtomicBoolean done = new AtomicBoolean();
327        Thread t = newStartedThread(new CheckedRunnable() {
328            public void realRun() {
329                while (!done.get()) {
330                    try {
331                        while (c.isBroken())
332                            c.reset();
333
334                        c.await();
335                        shouldThrow();
336                    }
337                    catch (BrokenBarrierException ok) {}
338                    catch (InterruptedException ok) {}
339                }}});
340
341        for (int i = 0; i < 4; i++) {
342            delay(timeoutMillis());
343            t.interrupt();
344        }
345        done.set(true);
346        t.interrupt();
347        awaitTermination(t);
348    }
349
350    /**
351     * Reset of a non-broken barrier does not break barrier
352     */
353    public void testResetWithoutBreakage() throws Exception {
354        final CyclicBarrier barrier = new CyclicBarrier(3);
355        for (int i = 0; i < 3; i++) {
356            final CyclicBarrier start = new CyclicBarrier(3);
357            Thread t1 = newStartedThread(new CheckedRunnable() {
358                public void realRun() throws Exception {
359                    start.await();
360                    barrier.await();
361                }});
362
363            Thread t2 = newStartedThread(new CheckedRunnable() {
364                public void realRun() throws Exception {
365                    start.await();
366                    barrier.await();
367                }});
368
369            start.await();
370            barrier.await();
371            awaitTermination(t1);
372            awaitTermination(t2);
373            assertFalse(barrier.isBroken());
374            assertEquals(0, barrier.getNumberWaiting());
375            if (i == 1) barrier.reset();
376            assertFalse(barrier.isBroken());
377            assertEquals(0, barrier.getNumberWaiting());
378        }
379    }
380
381    /**
382     * Reset of a barrier after interruption reinitializes it.
383     */
384    public void testResetAfterInterrupt() throws Exception {
385        final CyclicBarrier barrier = new CyclicBarrier(3);
386        for (int i = 0; i < 2; i++) {
387            final CyclicBarrier start = new CyclicBarrier(3);
388            Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
389                public void realRun() throws Exception {
390                    start.await();
391                    barrier.await();
392                }};
393
394            Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
395                public void realRun() throws Exception {
396                    start.await();
397                    barrier.await();
398                }};
399
400            t1.start();
401            t2.start();
402            start.await();
403            t1.interrupt();
404            awaitTermination(t1);
405            awaitTermination(t2);
406            assertTrue(barrier.isBroken());
407            assertEquals(0, barrier.getNumberWaiting());
408            barrier.reset();
409            assertFalse(barrier.isBroken());
410            assertEquals(0, barrier.getNumberWaiting());
411        }
412    }
413
414    /**
415     * Reset of a barrier after timeout reinitializes it.
416     */
417    public void testResetAfterTimeout() throws Exception {
418        final CyclicBarrier barrier = new CyclicBarrier(3);
419        for (int i = 0; i < 2; i++) {
420            assertEquals(0, barrier.getNumberWaiting());
421            Thread t1 = newStartedThread(new CheckedRunnable() {
422                public void realRun() throws Exception {
423                    try {
424                        barrier.await();
425                        shouldThrow();
426                    } catch (BrokenBarrierException success) {}
427                }});
428            Thread t2 = newStartedThread(new CheckedRunnable() {
429                public void realRun() throws Exception {
430                    awaitNumberWaiting(barrier, 1);
431                    long startTime = System.nanoTime();
432                    try {
433                        barrier.await(timeoutMillis(), MILLISECONDS);
434                        shouldThrow();
435                    } catch (TimeoutException success) {}
436                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
437                }});
438
439            awaitTermination(t1);
440            awaitTermination(t2);
441            assertEquals(0, barrier.getNumberWaiting());
442            assertTrue(barrier.isBroken());
443            assertEquals(0, barrier.getNumberWaiting());
444            barrier.reset();
445            assertFalse(barrier.isBroken());
446            assertEquals(0, barrier.getNumberWaiting());
447        }
448    }
449
450    /**
451     * Reset of a barrier after a failed command reinitializes it.
452     */
453    public void testResetAfterCommandException() throws Exception {
454        final CyclicBarrier barrier =
455            new CyclicBarrier(3, new Runnable() {
456                    public void run() {
457                        throw new NullPointerException(); }});
458        for (int i = 0; i < 2; i++) {
459            final CyclicBarrier start = new CyclicBarrier(3);
460            Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
461                public void realRun() throws Exception {
462                    start.await();
463                    barrier.await();
464                }};
465
466            Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
467                public void realRun() throws Exception {
468                    start.await();
469                    barrier.await();
470                }};
471
472            t1.start();
473            t2.start();
474            start.await();
475            awaitNumberWaiting(barrier, 2);
476            try {
477                barrier.await();
478                shouldThrow();
479            } catch (NullPointerException success) {}
480            awaitTermination(t1);
481            awaitTermination(t2);
482            assertTrue(barrier.isBroken());
483            assertEquals(0, barrier.getNumberWaiting());
484            barrier.reset();
485            assertFalse(barrier.isBroken());
486            assertEquals(0, barrier.getNumberWaiting());
487        }
488    }
489}
490