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 } --- EOF ---