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  * @summary stress test for register/arriveAndDeregister
  37  * @run main FickleRegister 300
  38  */
  39 
  40 import java.util.ArrayList;
  41 import java.util.concurrent.Phaser;
  42 import java.util.concurrent.atomic.AtomicLong;
  43 
  44 public class FickleRegister {
  45     final AtomicLong count = new AtomicLong(0);
  46     final long testDurationMillisDefault = 10_000L;
  47     final long testDurationMillis;
  48     final long quittingTimeNanos;
  49     final int chunkSize = 1000;
  50 
  51     FickleRegister(String[] args) {
  52         testDurationMillis = (args.length > 0) ?
  53             Long.valueOf(args[0]) : testDurationMillisDefault;
  54         quittingTimeNanos = System.nanoTime() +
  55             testDurationMillis * 1000L * 1000L;
  56     }
  57 
  58     class Runner extends CheckedRunnable {
  59         final Phaser p;
  60         Runner(Phaser phaser) { p = phaser; }
  61         public void realRun() {
  62             int prevPhase = -1;
  63             for (int k = 1;; k++) {
  64                 for (int i = 0; i < chunkSize; i++) {
  65                     int phase = p.register();
  66                     if (phase < 0) break;
  67                     check(phase > prevPhase);
  68                     prevPhase = phase;
  69                     equal(phase, p.arriveAndDeregister());
  70                     check(phase < p.awaitAdvance(phase));
  71                 }
  72                 if (System.nanoTime() - quittingTimeNanos > 0) {
  73                     count.getAndAdd(k * chunkSize);
  74                     break;
  75                 }
  76             }
  77         }
  78     }
  79 
  80     void test(String[] args) throws Throwable {
  81         final Phaser parent = new Phaser() {
  82                 protected boolean onAdvance(int phase, int parties) {
  83                     return false;
  84                 }
  85             };
  86 
  87         final Phaser child1 = new Phaser(parent);
  88         final Phaser child2 = new Phaser(parent);
  89         final Phaser subchild1 = new Phaser(child1);
  90         final Phaser subchild2 = new Phaser(child2);
  91         final Phaser[] phasers = {
  92             parent, child1, child2, subchild1, subchild2
  93         };
  94 
  95         int reps = 4;
  96         ArrayList<Thread> threads = new ArrayList<>();
  97         for (int j = 0; j < reps; ++j) {
  98             threads.add(new Thread(new Runner(subchild1)));
  99             threads.add(new Thread(new Runner(child1)));
 100             threads.add(new Thread(new Runner(parent)));
 101             threads.add(new Thread(new Runner(child2)));
 102             threads.add(new Thread(new Runner(subchild2)));
 103         }
 104 
 105         for (Thread thread : threads)
 106             thread.start();
 107 
 108         for (Thread thread : threads)
 109             thread.join();
 110 
 111         System.out.println("Parent:    " + parent);
 112         System.out.println("Child1:    " + child1);
 113         System.out.println("Child2:    " + child2);
 114         System.out.println("Subchild1: " + subchild1);
 115         System.out.println("Subchild2: " + subchild2);
 116         System.out.println("Iterations:" + count.get());
 117 
 118         for (Phaser phaser : phasers) {
 119             check(phaser.getPhase() > 0);
 120             equal(0, phaser.getRegisteredParties());
 121             equal(0, phaser.getUnarrivedParties());
 122             equal(parent.getPhase(), phaser.getPhase());
 123         }
 124     }
 125 
 126     //--------------------- Infrastructure ---------------------------
 127     volatile int passed = 0, failed = 0;
 128     void pass() {passed++;}
 129     void fail() {failed++; Thread.dumpStack();}
 130     void fail(String msg) {System.err.println(msg); fail();}
 131     void unexpected(Throwable t) {failed++; t.printStackTrace();}
 132     void check(boolean cond) {if (cond) pass(); else fail();}
 133     void equal(Object x, Object y) {
 134         if (x == null ? y == null : x.equals(y)) pass();
 135         else fail(x + " not equal to " + y);}
 136     public static void main(String[] args) throws Throwable {
 137         new FickleRegister(args).instanceMain(args);}
 138     public void instanceMain(String[] args) throws Throwable {
 139         try {test(args);} catch (Throwable t) {unexpected(t);}
 140         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
 141         if (failed > 0) throw new AssertionError("Some tests failed");}
 142 
 143     abstract class CheckedRunnable implements Runnable {
 144         protected abstract void realRun() throws Throwable;
 145 
 146         public final void run() {
 147             try {realRun();} catch (Throwable t) {unexpected(t);}
 148         }
 149     }
 150 }