--- /dev/null Thu Oct 31 11:53:02 2013 +++ new/test/lib/testlibrary/ThreadStateController.java Thu Oct 31 11:53:01 2013 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; + +/** + * ThreadStateController allows the caller to tranition to a specific + * thread state. + */ +public class ThreadStateController extends Thread { + // used to achieve waiting states + private final Object lock; + public ThreadStateController(String name, Object lock) { + super(name); + this.lock = lock; + } + + public static void checkThreadState(ThreadStateController t, Thread.State expected) { + // maximum number of retries when checking for thread state. + final int MAX_RETRY = 500; + + // wait for the thread to transition to the expected state. + // There is a small window between the thread checking the state + // and the thread actual entering that state. + Thread.State state; + int retryCount=0; + while ((state = t.getState()) != expected && retryCount < MAX_RETRY) { + goSleep(10); + retryCount++; + } + + if (state == null) { + throw new RuntimeException(t.getName() + " expected to have " + + expected + " but got null."); + } + + if (state != expected) { + throw new RuntimeException(String.format("%s expected in %s state but got %s " + + "(iterations %d interrupted %d)%n", + t.getName(), expected, state, t.iterations, t.interrupted)); + } + } + + private static void goSleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + // Phaser to sync between the main thread putting + // this thread into various states + private Phaser phaser = new Phaser(2); + private final int RUNNABLE = 0; + private final int BLOCKED = 1; + private final int WAITING = 2; + private final int TIMED_WAITING = 3; + private final int PARKED = 4; + private final int TIMED_PARKED = 5; + private final int SLEEPING = 6; + private final int TERMINATE = 7; + + private volatile int state = RUNNABLE; + private boolean done = false; + + // for debugging + private AtomicInteger iterations = new AtomicInteger(); + private AtomicInteger interrupted = new AtomicInteger(); + public void run() { + // Signal main thread to continue. + phaser.arriveAndAwaitAdvance(); + + while (!done) { + iterations.incrementAndGet(); + switch (state) { + case RUNNABLE: { + double sum = 0; + for (int i = 0; i < 1000; i++) { + double r = Math.random(); + double x = Math.pow(3, r); + sum += x - r; + } + break; + } + case BLOCKED: { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to block."); + synchronized (lock) { + // finish blocking + state = RUNNABLE; + } + break; + } + case WAITING: { + synchronized (lock) { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to wait."); + try { + lock.wait(); + } catch (InterruptedException e) { + // ignore + interrupted.incrementAndGet(); + } + } + break; + } + case TIMED_WAITING: { + synchronized (lock) { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to timed wait."); + try { + lock.wait(10000); + } catch (InterruptedException e) { + // ignore + interrupted.incrementAndGet(); + } + } + break; + } + case PARKED: { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to park."); + LockSupport.park(); + // give a chance for the main thread to block + goSleep(10); + break; + } + case TIMED_PARKED: { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to timed park."); + long deadline = System.currentTimeMillis() + 10000*1000; + LockSupport.parkUntil(deadline); + + // give a chance for the main thread to block + goSleep(10); + break; + } + case SLEEPING: { + // signal main thread. + phaser.arrive(); + System.out.println(" myThread is going to sleep."); + try { + Thread.sleep(1000000); + } catch (InterruptedException e) { + // finish sleeping + } + break; + } + case TERMINATE: { + done = true; + // signal main thread. + phaser.arrive(); + break; + } + default: + break; + } + } + } + + public void waitUntilStarted() { + // wait for MyThread to start. + phaser.arriveAndAwaitAdvance(); + } + + public void goBlocked() { + System.out.println("Waiting myThread to go blocked."); + setState(BLOCKED); + // wait for MyThread to get to a point just before being blocked + phaser.arriveAndAwaitAdvance(); + } + + public void goWaiting() { + System.out.println("Waiting myThread to go waiting."); + setState(WAITING); + // wait for MyThread to get to just before wait on object. + phaser.arriveAndAwaitAdvance(); + } + + public void goTimedWaiting() { + System.out.println("Waiting myThread to go timed waiting."); + setState(TIMED_WAITING); + // wait for MyThread to get to just before timed wait call. + phaser.arriveAndAwaitAdvance(); + } + + public void goParked() { + System.out.println("Waiting myThread to go parked."); + setState(PARKED); + // wait for MyThread to get to just before parked. + phaser.arriveAndAwaitAdvance(); + } + + public void goTimedParked() { + System.out.println("Waiting myThread to go timed parked."); + setState(TIMED_PARKED); + // wait for MyThread to get to just before timed park. + phaser.arriveAndAwaitAdvance(); + } + + public void goSleeping() { + System.out.println("Waiting myThread to go sleeping."); + setState(SLEEPING); + // wait for MyThread to get to just before sleeping + phaser.arriveAndAwaitAdvance(); + } + + public void terminate() { + System.out.println("Waiting myThread to terminate."); + setState(TERMINATE); + // wait for MyThread to get to just before terminate + phaser.arriveAndAwaitAdvance(); + } + + private void setState(int newState) { + switch (state) { + case BLOCKED: + while (state == BLOCKED) { + goSleep(10); + } + state = newState; + break; + case WAITING: + case TIMED_WAITING: + state = newState; + synchronized (lock) { + lock.notify(); + } + break; + case PARKED: + case TIMED_PARKED: + state = newState; + LockSupport.unpark(this); + break; + case SLEEPING: + state = newState; + this.interrupt(); + break; + default: + state = newState; + break; + } + iterations.set(0); + interrupted.set(0); + } +}