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 */ 33 34 /* 35 * @test 36 * @bug 6445158 37 * @summary Basic tests for Phaser 38 * @author Chris Hegarty 39 */ 40 41 import java.util.Iterator; 42 import java.util.LinkedList; 43 import java.util.concurrent.Phaser; 44 import java.util.concurrent.TimeUnit; 45 import java.util.concurrent.TimeoutException; 46 import java.util.concurrent.atomic.AtomicInteger; 47 import static java.util.concurrent.TimeUnit.*; 48 49 public class Basic { 50 51 private static final int TIMEOUT = 100; 52 53 private static void checkTerminated(final Phaser phaser) { 54 check(phaser.isTerminated()); 55 int unarriverParties = phaser.getUnarrivedParties(); 56 int registeredParties = phaser.getRegisteredParties(); 57 int phase = phaser.getPhase(); 58 check(phase < 0); 59 equal(phase, phaser.arrive()); 60 equal(phase, phaser.arriveAndDeregister()); 61 equal(phase, phaser.arriveAndAwaitAdvance()); 62 equal(phase, phaser.bulkRegister(10)); 63 equal(phase, phaser.register()); 64 try { 65 equal(phase, phaser.awaitAdvanceInterruptibly(0)); 66 equal(phase, phaser.awaitAdvanceInterruptibly(0, 10, SECONDS)); 67 } catch (Exception ie) { 68 unexpected(ie); 69 } 70 equal(phaser.getUnarrivedParties(), unarriverParties); 71 equal(phaser.getRegisteredParties(), registeredParties); 72 } 73 74 private static void checkResult(Arriver a, Class<? extends Throwable> c) { 75 Throwable t = a.result(); 76 if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { 77 // t.printStackTrace(); 78 fail("Mismatch in thread " + 79 a.getName() + ": " + 80 t + ", " + 81 (c == null ? "<null>" : c.getName())); 82 } else { 83 pass(); 84 } 85 } 86 87 //---------------------------------------------------------------- 88 // Mechanism to get all test threads into "running" mode. 89 //---------------------------------------------------------------- 90 private static Phaser atTheStartingGate = new Phaser(3); 91 92 private static void toTheStartingGate() { 93 try { 94 boolean expectNextPhase = false; 95 if (atTheStartingGate.getUnarrivedParties() == 1) { 96 expectNextPhase = true; 97 } 98 int phase = atTheStartingGate.getPhase(); 99 equal(phase, atTheStartingGate.arrive()); 100 int awaitPhase = atTheStartingGate.awaitAdvanceInterruptibly 101 (phase, 30, SECONDS); 102 if (expectNextPhase) check(awaitPhase == (phase + 1)); 103 104 pass(); 105 } catch (Throwable t) { 106 unexpected(t); 107 // reset(atTheStartingGate); 108 throw new Error(t); 109 } 110 } 111 112 //---------------------------------------------------------------- 113 // Convenience methods for creating threads that call arrive, 114 // awaitAdvance, arriveAndAwaitAdvance, awaitAdvanceInterruptibly 115 //---------------------------------------------------------------- 116 private static abstract class Arriver extends Thread { 117 static AtomicInteger count = new AtomicInteger(1); 118 119 Arriver() { 120 this("Arriver"); 121 } 122 123 Arriver(String name) { 124 this.setName(name + ":" + count.getAndIncrement()); 125 this.setDaemon(true); 126 } 127 128 private volatile Throwable result; 129 private volatile int phase; 130 protected void result(Throwable result) { this.result = result; } 131 public Throwable result() { return this.result; } 132 protected void phase(int phase) { this.phase = phase; } 133 public int phase() { return this.phase; } 134 } 135 136 private static abstract class Awaiter extends Arriver { 137 Awaiter() { super("Awaiter"); } 138 Awaiter(String name) { super(name); } 139 } 140 141 private static Arriver arriver(final Phaser phaser) { 142 return new Arriver() { public void run() { 143 toTheStartingGate(); 144 145 try { phase(phaser.arrive()); } 146 catch (Throwable result) { result(result); }}}; 147 } 148 149 private static AtomicInteger cycleArriveAwaitAdvance = new AtomicInteger(1); 150 151 private static Awaiter awaiter(final Phaser phaser) { 152 return new Awaiter() { public void run() { 153 toTheStartingGate(); 154 155 try { 156 if (cycleArriveAwaitAdvance.getAndIncrement() % 2 == 0) 157 phase(phaser.awaitAdvance(phaser.arrive())); 158 else 159 phase(phaser.arriveAndAwaitAdvance()); 160 } catch (Throwable result) { result(result); }}}; 161 } 162 163 private static Awaiter awaiter(final Phaser phaser, 164 final long timeout, 165 final TimeUnit unit) { 166 return new Awaiter("InterruptibleWaiter") { public void run() { 167 toTheStartingGate(); 168 169 try { 170 if (timeout < 0) 171 phase(phaser.awaitAdvanceInterruptibly(phaser.arrive())); 172 else 173 phase(phaser.awaitAdvanceInterruptibly(phaser.arrive(), 174 timeout, 175 unit)); 176 } catch (Throwable result) { result(result); }}}; 177 } 178 179 // Returns an infinite lazy list of all possible arriver/awaiter combinations. 180 private static Iterator<Arriver> arriverIterator(final Phaser phaser) { 181 return new Iterator<Arriver>() { 182 int i = 0; 183 public boolean hasNext() { return true; } 184 public Arriver next() { 185 switch ((i++)&7) { 186 case 0: case 4: 187 return arriver(phaser); 188 case 1: case 5: 189 return awaiter(phaser); 190 case 2: case 6: case 7: 191 return awaiter(phaser, -1, SECONDS); 192 default: 193 return awaiter(phaser, 30, SECONDS); }} 194 public void remove() {throw new UnsupportedOperationException();}}; 195 } 196 197 // Returns an infinite lazy list of all possible awaiter only combinations. 198 private static Iterator<Awaiter> awaiterIterator(final Phaser phaser) { 199 return new Iterator<Awaiter>() { 200 int i = 0; 201 public boolean hasNext() { return true; } 202 public Awaiter next() { 203 switch ((i++)&7) { 204 case 1: case 4: case 7: 205 return awaiter(phaser); 206 case 2: case 5: 207 return awaiter(phaser, -1, SECONDS); 208 default: 209 return awaiter(phaser, 30, SECONDS); }} 210 public void remove() {throw new UnsupportedOperationException();}}; 211 } 212 213 private static void realMain(String[] args) throws Throwable { 214 215 Thread.currentThread().setName("mainThread"); 216 217 //---------------------------------------------------------------- 218 // Normal use 219 //---------------------------------------------------------------- 220 try { 221 Phaser phaser = new Phaser(3); 222 equal(phaser.getRegisteredParties(), 3); 223 equal(phaser.getArrivedParties(), 0); 224 equal(phaser.getPhase(), 0); 225 check(phaser.getRoot().equals(phaser)); 226 equal(phaser.getParent(), null); 227 check(!phaser.isTerminated()); 228 229 Iterator<Arriver> arrivers = arriverIterator(phaser); 230 int phase = 0; 231 for (int i = 0; i < 10; i++) { 232 equal(phaser.getPhase(), phase++); 233 Arriver a1 = arrivers.next(); a1.start(); 234 Arriver a2 = arrivers.next(); a2.start(); 235 toTheStartingGate(); 236 phaser.arriveAndAwaitAdvance(); 237 a1.join(); 238 a2.join(); 239 checkResult(a1, null); 240 checkResult(a2, null); 241 check(!phaser.isTerminated()); 242 equal(phaser.getRegisteredParties(), 3); 243 equal(phaser.getArrivedParties(), 0); 244 } 245 } catch (Throwable t) { unexpected(t); } 246 247 //---------------------------------------------------------------- 248 // One thread interrupted 249 //---------------------------------------------------------------- 250 try { 251 Phaser phaser = new Phaser(3); 252 Iterator<Arriver> arrivers = arriverIterator(phaser); 253 int phase = phaser.getPhase(); 254 for (int i = 0; i < 4; i++) { 255 check(phaser.getPhase() == phase); 256 Awaiter a1 = awaiter(phaser, 30, SECONDS); a1.start(); 257 Arriver a2 = arrivers.next(); a2.start(); 258 toTheStartingGate(); 259 int count = 0; 260 while (a1.result() == null && count < 20) { 261 Thread.sleep(TIMEOUT); 262 a1.interrupt(); 263 count++; 264 } 265 a1.join(); 266 phaser.arriveAndAwaitAdvance(); 267 a2.join(); 268 checkResult(a1, InterruptedException.class); 269 checkResult(a2, null); 270 check(!phaser.isTerminated()); 271 equal(phaser.getRegisteredParties(), 3); 272 equal(phaser.getArrivedParties(), 0); 273 phase++; 274 } 275 } catch (Throwable t) { unexpected(t); } 276 277 //---------------------------------------------------------------- 278 // Phaser is terminated while threads are waiting 279 //---------------------------------------------------------------- 280 try { 281 for (int i = 0; i < 4; i++) { 282 Phaser phaser = new Phaser(3); 283 Iterator<Awaiter> awaiters = awaiterIterator(phaser); 284 Arriver a1 = awaiters.next(); a1.start(); 285 Arriver a2 = awaiters.next(); a2.start(); 286 toTheStartingGate(); 287 while (phaser.getArrivedParties() < 2) Thread.yield(); 288 equal(0, phaser.getPhase()); 289 phaser.forceTermination(); 290 a1.join(); 291 a2.join(); 292 equal(0 + Integer.MIN_VALUE, a1.phase); 293 equal(0 + Integer.MIN_VALUE, a2.phase); 294 int arrivedParties = phaser.getArrivedParties(); 295 checkTerminated(phaser); 296 equal(phaser.getArrivedParties(), arrivedParties); 297 } 298 } catch (Throwable t) { unexpected(t); } 299 300 //---------------------------------------------------------------- 301 // Adds new unarrived parties to this phaser 302 //---------------------------------------------------------------- 303 try { 304 Phaser phaser = new Phaser(1); 305 Iterator<Arriver> arrivers = arriverIterator(phaser); 306 LinkedList<Arriver> arriverList = new LinkedList<Arriver>(); 307 int phase = phaser.getPhase(); 308 for (int i = 1; i < 5; i++) { 309 atTheStartingGate = new Phaser(1+(3*i)); 310 check(phaser.getPhase() == phase); 311 // register 3 more 312 phaser.register(); phaser.register(); phaser.register(); 313 for (int z=0; z<(3*i); z++) { 314 arriverList.add(arrivers.next()); 315 } 316 for (Arriver arriver : arriverList) 317 arriver.start(); 318 319 toTheStartingGate(); 320 phaser.arriveAndAwaitAdvance(); 321 322 for (Arriver arriver : arriverList) { 323 arriver.join(); 324 checkResult(arriver, null); 325 } 326 equal(phaser.getRegisteredParties(), 1 + (3*i)); 327 equal(phaser.getArrivedParties(), 0); 328 arriverList.clear(); 329 phase++; 330 } 331 atTheStartingGate = new Phaser(3); 332 } catch (Throwable t) { unexpected(t); } 333 334 //---------------------------------------------------------------- 335 // One thread timed out 336 //---------------------------------------------------------------- 337 try { 338 Phaser phaser = new Phaser(3); 339 Iterator<Arriver> arrivers = arriverIterator(phaser); 340 for (long timeout : new long[] { 0L, 5L }) { 341 for (int i = 0; i < 2; i++) { 342 Awaiter a1 = awaiter(phaser, timeout, SECONDS); a1.start(); 343 Arriver a2 = arrivers.next(); a2.start(); 344 toTheStartingGate(); 345 a1.join(); 346 checkResult(a1, TimeoutException.class); 347 phaser.arrive(); 348 a2.join(); 349 checkResult(a2, null); 350 check(!phaser.isTerminated()); 351 } 352 } 353 } catch (Throwable t) { unexpected(t); } 354 355 //---------------------------------------------------------------- 356 // Barrier action completed normally 357 //---------------------------------------------------------------- 358 try { 359 final AtomicInteger count = new AtomicInteger(0); 360 final Phaser[] kludge = new Phaser[1]; 361 Phaser phaser = new Phaser(3) { 362 @Override 363 protected boolean onAdvance(int phase, int registeredParties) { 364 int countPhase = count.getAndIncrement(); 365 equal(countPhase, phase); 366 equal(kludge[0].getPhase(), phase); 367 equal(kludge[0].getRegisteredParties(), registeredParties); 368 if (phase >= 3) 369 return true; // terminate 370 371 return false; 372 } 373 }; 374 kludge[0] = phaser; 375 equal(phaser.getRegisteredParties(), 3); 376 Iterator<Awaiter> awaiters = awaiterIterator(phaser); 377 for (int i = 0; i < 4; i++) { 378 Awaiter a1 = awaiters.next(); a1.start(); 379 Awaiter a2 = awaiters.next(); a2.start(); 380 toTheStartingGate(); 381 while (phaser.getArrivedParties() < 2) Thread.yield(); 382 phaser.arrive(); 383 a1.join(); 384 a2.join(); 385 checkResult(a1, null); 386 checkResult(a2, null); 387 equal(count.get(), i+1); 388 if (i < 3) { 389 check(!phaser.isTerminated()); 390 equal(phaser.getRegisteredParties(), 3); 391 equal(phaser.getArrivedParties(), 0); 392 equal(phaser.getUnarrivedParties(), 3); 393 equal(phaser.getPhase(), count.get()); 394 } else 395 checkTerminated(phaser); 396 } 397 } catch (Throwable t) { unexpected(t); } 398 399 } 400 401 //--------------------- Infrastructure --------------------------- 402 static volatile int passed = 0, failed = 0; 403 static void pass() {passed++;} 404 static void fail() {failed++; Thread.dumpStack();} 405 static void fail(String msg) {System.out.println(msg); fail();} 406 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 407 static void check(boolean cond) {if (cond) pass(); else fail();} 408 static void equal(Object x, Object y) { 409 if (x == null ? y == null : x.equals(y)) pass(); 410 else fail(x + " not equal to " + y);} 411 public static void main(String[] args) throws Throwable { 412 try {realMain(args);} catch (Throwable t) {unexpected(t);} 413 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 414 if (failed > 0) throw new AssertionError("Some tests failed");} 415 }