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