1 /*
   2  * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6253848 6366811
  27  * @summary Basic tests for CyclicBarrier
  28  * @author Martin Buchholz, David Holmes
  29  */
  30 
  31 import java.util.*;
  32 import java.util.concurrent.*;
  33 import java.util.concurrent.atomic.AtomicInteger;
  34 import static java.util.concurrent.TimeUnit.*;
  35 
  36 public class Basic {
  37 
  38     private static void checkBroken(final CyclicBarrier barrier) {
  39         check(barrier.isBroken());
  40         equal(barrier.getNumberWaiting(), 0);
  41 
  42         THROWS(BrokenBarrierException.class,
  43                new Fun() { public void f() throws Throwable {
  44                    barrier.await(); }},
  45                new Fun() { public void f() throws Throwable {
  46                    barrier.await(100, MILLISECONDS); }});
  47     }
  48 
  49     private static void reset(CyclicBarrier barrier) {
  50         barrier.reset();
  51         check(! barrier.isBroken());
  52         equal(barrier.getNumberWaiting(), 0);
  53     }
  54 
  55     private static void checkResult(Awaiter a, Class<? extends Throwable> c) {
  56         Throwable t = a.result();
  57         if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) {
  58             //      t.printStackTrace();
  59             fail("Mismatch in thread " +
  60                  a.getName() + ": " +
  61                  t + ", " +
  62                  (c == null ? "<null>" : c.getName()));
  63         } else {
  64             pass();
  65         }
  66     }
  67 
  68     //----------------------------------------------------------------
  69     // Mechanism to get all victim threads into "running" mode.
  70     // The fact that this also uses CyclicBarrier is entirely coincidental.
  71     //----------------------------------------------------------------
  72     private static final CyclicBarrier atTheStartingGate = new CyclicBarrier(3);
  73 
  74     private static void toTheStartingGate() {
  75         try { atTheStartingGate.await(10, SECONDS); pass(); }
  76         catch (Throwable t) {
  77             unexpected(t);
  78             reset(atTheStartingGate);
  79             throw new Error(t);
  80         }
  81     }
  82 
  83     //----------------------------------------------------------------
  84     // Convenience methods for creating threads that call CyclicBarrier.await
  85     //----------------------------------------------------------------
  86     private static abstract class Awaiter extends Thread {
  87         static AtomicInteger count = new AtomicInteger(1);
  88 
  89         {
  90             this.setName("Awaiter:"+count.getAndIncrement());
  91             this.setDaemon(true);
  92         }
  93 
  94         private volatile Throwable result = null;
  95         protected void result(Throwable result) { this.result = result; }
  96         public Throwable result() { return this.result; }
  97     }
  98 
  99     private static Awaiter awaiter(final CyclicBarrier barrier) {
 100         return new Awaiter() { public void run() {
 101             toTheStartingGate();
 102 
 103             try { barrier.await(); }
 104             catch (Throwable result) { result(result); }}};
 105     }
 106 
 107     private static Awaiter awaiter(final CyclicBarrier barrier,
 108                                    final long millis) {
 109         return new Awaiter() { public void run() {
 110             toTheStartingGate();
 111 
 112             try { barrier.await(millis, MILLISECONDS); }
 113             catch (Throwable result) { result(result); }}};
 114     }
 115 
 116     // Returns an infinite lazy list of all possible awaiter pair combinations.
 117     private static Iterator<Awaiter> awaiterIterator(final CyclicBarrier barrier) {
 118         return new Iterator<Awaiter>() {
 119             int i = 0;
 120             public boolean hasNext() { return true; }
 121             public Awaiter next() {
 122                 switch ((i++)&7) {
 123                 case 0: case 2: case 4: case 5:
 124                     return awaiter(barrier);
 125                 default:
 126                     return awaiter(barrier, 10 * 1000); }}
 127             public void remove() {throw new UnsupportedOperationException();}};
 128     }
 129 
 130     private static void realMain(String[] args) throws Throwable {
 131 
 132         Thread.currentThread().setName("mainThread");
 133 
 134         //----------------------------------------------------------------
 135         // Normal use
 136         //----------------------------------------------------------------
 137         try {
 138             CyclicBarrier barrier = new CyclicBarrier(3);
 139             equal(barrier.getParties(), 3);
 140             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 141             for (boolean doReset : new boolean[] {false, true})
 142                 for (int i = 0; i < 4; i++) {
 143                     Awaiter a1 = awaiters.next(); a1.start();
 144                     Awaiter a2 = awaiters.next(); a2.start();
 145                     toTheStartingGate();
 146                     barrier.await();
 147                     a1.join();
 148                     a2.join();
 149                     checkResult(a1, null);
 150                     checkResult(a2, null);
 151                     check(! barrier.isBroken());
 152                     equal(barrier.getParties(), 3);
 153                     equal(barrier.getNumberWaiting(), 0);
 154                     if (doReset) reset(barrier);
 155                 }
 156         } catch (Throwable t) { unexpected(t); }
 157 
 158         //----------------------------------------------------------------
 159         // One thread interrupted
 160         //----------------------------------------------------------------
 161         try {
 162             CyclicBarrier barrier = new CyclicBarrier(3);
 163             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 164             for (int i = 0; i < 4; i++) {
 165                 Awaiter a1 = awaiters.next(); a1.start();
 166                 Awaiter a2 = awaiters.next(); a2.start();
 167                 toTheStartingGate();
 168                 a1.interrupt();
 169                 a1.join();
 170                 a2.join();
 171                 checkResult(a1, InterruptedException.class);
 172                 checkResult(a2, BrokenBarrierException.class);
 173                 checkBroken(barrier);
 174                 reset(barrier);
 175             }
 176         } catch (Throwable t) { unexpected(t); }
 177 
 178         //----------------------------------------------------------------
 179         // Barrier is reset while threads are waiting
 180         //----------------------------------------------------------------
 181         try {
 182             CyclicBarrier barrier = new CyclicBarrier(3);
 183             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 184             for (int i = 0; i < 4; i++) {
 185                 Awaiter a1 = awaiters.next(); a1.start();
 186                 Awaiter a2 = awaiters.next(); a2.start();
 187                 toTheStartingGate();
 188                 while (barrier.getNumberWaiting() < 2) Thread.yield();
 189                 barrier.reset();
 190                 a1.join();
 191                 a2.join();
 192                 checkResult(a1, BrokenBarrierException.class);
 193                 checkResult(a2, BrokenBarrierException.class);
 194                 check(! barrier.isBroken());
 195                 equal(barrier.getParties(), 3);
 196                 equal(barrier.getNumberWaiting(), 0);
 197             }
 198         } catch (Throwable t) { unexpected(t); }
 199 
 200         //----------------------------------------------------------------
 201         // One thread timed out
 202         //----------------------------------------------------------------
 203         try {
 204             CyclicBarrier barrier = new CyclicBarrier(3);
 205             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 206             for (long timeout : new long[] { 0L, 10L }) {
 207                 for (int i = 0; i < 2; i++) {
 208                     Awaiter a1 = awaiter(barrier, timeout); a1.start();
 209                     Awaiter a2 = awaiters.next();           a2.start();
 210                     toTheStartingGate();
 211                     a1.join();
 212                     a2.join();
 213                     checkResult(a1, TimeoutException.class);
 214                     checkResult(a2, BrokenBarrierException.class);
 215                     checkBroken(barrier);
 216                     equal(barrier.getParties(), 3);
 217                     reset(barrier);
 218                 }
 219             }
 220         } catch (Throwable t) { unexpected(t); }
 221 
 222         //----------------------------------------------------------------
 223         // Barrier action completed normally
 224         //----------------------------------------------------------------
 225         try {
 226             final AtomicInteger count = new AtomicInteger(0);
 227             final CyclicBarrier[] kludge = new CyclicBarrier[1];
 228             Runnable action = new Runnable() { public void run() {
 229                 count.incrementAndGet();
 230                 equal(kludge[0].getNumberWaiting(),
 231                       kludge[0].getParties());
 232                 System.out.println("OK!"); }};
 233             CyclicBarrier barrier = new CyclicBarrier(3, action);
 234             kludge[0] = barrier;
 235             equal(barrier.getParties(), 3);
 236             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 237             for (int i = 0; i < 4; i++) {
 238                 Awaiter a1 = awaiters.next(); a1.start();
 239                 Awaiter a2 = awaiters.next(); a2.start();
 240                 toTheStartingGate();
 241                 while (barrier.getNumberWaiting() < 2) Thread.yield();
 242                 try { barrier.await(); }
 243                 catch (Throwable t) { unexpected(t); }
 244                 a1.join();
 245                 a2.join();
 246                 checkResult(a1, null);
 247                 checkResult(a2, null);
 248                 check(! barrier.isBroken());
 249                 equal(barrier.getNumberWaiting(), 0);
 250                 reset(barrier);
 251                 equal(count.get(), i+1);
 252             }
 253         } catch (Throwable t) { unexpected(t); }
 254 
 255         //----------------------------------------------------------------
 256         // Barrier action threw exception
 257         //----------------------------------------------------------------
 258         try {
 259             Runnable action = new Runnable() {
 260                     public void run() { throw new Error(); }};
 261             CyclicBarrier barrier = new CyclicBarrier(3, action);
 262             Iterator<Awaiter> awaiters = awaiterIterator(barrier);
 263             for (int i = 0; i < 4; i++) {
 264                 Awaiter a1 = awaiters.next(); a1.start();
 265                 Awaiter a2 = awaiters.next(); a2.start();
 266                 toTheStartingGate();
 267                 while (barrier.getNumberWaiting() < 2) Thread.yield();
 268                 try {
 269                     barrier.await();
 270                     fail("Expected Error not thrown"); }
 271                 catch (Error e) { pass(); }
 272                 catch (Throwable t) { unexpected(t); }
 273                 a1.join();
 274                 a2.join();
 275                 checkResult(a1, BrokenBarrierException.class);
 276                 checkResult(a2, BrokenBarrierException.class);
 277                 checkBroken(barrier);
 278                 reset(barrier);
 279             }
 280         } catch (Throwable t) { unexpected(t); }
 281 
 282         testInterrupts();
 283     }
 284 
 285     /**
 286      * Handling of extra interrupts while waiting - tests for bug 6366811
 287      */
 288     private static void testInterrupts() {
 289         final int N = 10;
 290         final CyclicBarrier startingGate = new CyclicBarrier(N+1);
 291 
 292         /**
 293          * A version of Awaiter that also records interrupted state.
 294          */
 295         class Waiter extends CheckedThread {
 296             private boolean timed;
 297             private CyclicBarrier barrier;
 298             private CountDownLatch doneSignal;
 299             private Throwable throwable;
 300             private boolean interrupted;
 301 
 302             public Waiter(boolean timed,
 303                           CountDownLatch doneSignal,
 304                           CyclicBarrier barrier) {
 305                 this.timed = timed;
 306                 this.doneSignal = doneSignal;
 307                 this.barrier = barrier;
 308             }
 309             Throwable throwable() { return this.throwable; }
 310             boolean interruptBit() { return this.interrupted; }
 311             void realRun() throws Throwable {
 312                 startingGate.await(10, SECONDS);
 313                 try {
 314                     if (timed) barrier.await(10, SECONDS);
 315                     else barrier.await(); }
 316                 catch (Throwable throwable) { this.throwable = throwable; }
 317 
 318                 try { doneSignal.await(10, SECONDS); }
 319                 catch (InterruptedException e) { interrupted = true; }
 320             }
 321         }
 322 
 323         //----------------------------------------------------------------
 324         // Interrupt occurs during barrier trip
 325         //----------------------------------------------------------------
 326         try {
 327             final CountDownLatch doneSignal = new CountDownLatch(1);
 328             final List<Waiter> waiters = new ArrayList<Waiter>(N);
 329 
 330             // work around finality of closed-over variables
 331             final Runnable[] realAction = new Runnable[1];
 332             final Runnable delegateAction =
 333                 new Runnable() {public void run() {realAction[0].run();}};
 334             final CyclicBarrier barrier = new CyclicBarrier(N+1, delegateAction);
 335 
 336             realAction[0] = new Runnable() { public void run() {
 337                 try {
 338                     for (int i = 0; i < N/2; i++)
 339                         waiters.get(i).interrupt();
 340                     // we need to try and ensure that the waiters get
 341                     // to process their interruption before we do the
 342                     // signalAll that trips the barrier. Using sleep
 343                     // seems to work reliably while yield does not.
 344                     Thread.sleep(100);
 345                 } catch (Throwable t) { unexpected(t); }
 346             }};
 347             for (int i = 0; i < N; i++) {
 348                 Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
 349                 waiter.start();
 350                 waiters.add(waiter);
 351             }
 352             startingGate.await(10, SECONDS);
 353             while (barrier.getNumberWaiting() < N) Thread.yield();
 354             barrier.await();
 355             doneSignal.countDown();
 356             int countInterrupted = 0;
 357             int countInterruptedException = 0;
 358             int countBrokenBarrierException = 0;
 359             for (Waiter waiter : waiters) {
 360                 waiter.join();
 361                 equal(waiter.throwable(), null);
 362                 if (waiter.interruptBit())
 363                     countInterrupted++;
 364             }
 365             equal(countInterrupted, N/2);
 366             check(! barrier.isBroken());
 367         } catch (Throwable t) { unexpected(t); }
 368 
 369         //----------------------------------------------------------------
 370         // Multiple interrupts occur during barrier await
 371         //----------------------------------------------------------------
 372         try {
 373             final CountDownLatch doneSignal = new CountDownLatch(1);
 374             final CyclicBarrier barrier = new CyclicBarrier(N+1);
 375             final List<Waiter> waiters = new ArrayList<Waiter>(N);
 376             for (int i = 0; i < N; i++) {
 377                 Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
 378                 waiter.start();
 379                 waiters.add(waiter);
 380             }
 381             startingGate.await(10, SECONDS);
 382             while (barrier.getNumberWaiting() < N) Thread.yield();
 383             for (int i = 0; i < N/2; i++)
 384                 waiters.get(i).interrupt();
 385             doneSignal.countDown();
 386             int countInterrupted = 0;
 387             int countInterruptedException = 0;
 388             int countBrokenBarrierException = 0;
 389             for (Waiter waiter : waiters) {
 390                 waiter.join();
 391                 if (waiter.throwable() instanceof InterruptedException)
 392                     countInterruptedException++;
 393                 if (waiter.throwable() instanceof BrokenBarrierException)
 394                     countBrokenBarrierException++;
 395                 if (waiter.interruptBit())
 396                     countInterrupted++;
 397             }
 398             equal(countInterrupted, N/2-1);
 399             equal(countInterruptedException, 1);
 400             equal(countBrokenBarrierException, N-1);
 401             checkBroken(barrier);
 402             reset(barrier);
 403         } catch (Throwable t) { unexpected(t); }
 404     }
 405 
 406     //--------------------- Infrastructure ---------------------------
 407     static volatile int passed = 0, failed = 0;
 408     static void pass() {passed++;}
 409     static void fail() {failed++; Thread.dumpStack();}
 410     static void fail(String msg) {System.out.println(msg); fail();}
 411     static void unexpected(Throwable t) {failed++; t.printStackTrace();}
 412     static void check(boolean cond) {if (cond) pass(); else fail();}
 413     static void equal(Object x, Object y) {
 414         if (x == null ? y == null : x.equals(y)) pass();
 415         else fail(x + " not equal to " + y);}
 416     public static void main(String[] args) throws Throwable {
 417         try {realMain(args);} catch (Throwable t) {unexpected(t);}
 418         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
 419         if (failed > 0) throw new AssertionError("Some tests failed");}
 420     static abstract class Fun { abstract void f() throws Throwable; }
 421     private static void THROWS(Class<? extends Throwable> k, Fun... fs) {
 422         for (Fun f : fs)
 423             try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
 424             catch (Throwable t) {
 425                 if (k.isAssignableFrom(t.getClass())) pass();
 426                 else unexpected(t);}}
 427     private static abstract class CheckedThread extends Thread {
 428         abstract void realRun() throws Throwable;
 429         public void run() {
 430             try {realRun();} catch (Throwable t) {unexpected(t);}}}
 431 }