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 }