Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/Thread/ThreadStateController.java
38811 views
/*1* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved.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 it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 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 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.util.concurrent.Phaser;24import java.util.concurrent.TimeUnit;25import java.util.concurrent.TimeoutException;26import java.util.concurrent.atomic.AtomicInteger;27import java.util.concurrent.locks.LockSupport;2829import jdk.testlibrary.LockFreeLogManager;3031/**32* ThreadStateController allows a thread to request this thread to transition33* to a specific thread state. The {@linkplain #transitionTo request} is34* a blocking call that the calling thread will wait until this thread is about35* going to the new state. Only one request of state transition at a time36* is supported (the Phaser expects only parties of 2 to arrive and advance37* to next phase).38*/39public class ThreadStateController extends Thread {40// used to achieve waiting states41private final Object lock;42public ThreadStateController(String name, Object lock) {43super(name);44this.lock = lock;45}4647public void checkThreadState(Thread.State expected) {48// maximum number of retries when checking for thread state.49final int MAX_RETRY = 500;5051// wait for the thread to transition to the expected state.52// There is a small window between the thread checking the state53// and the thread actual entering that state.54Thread.State state;55int retryCount=0;56while ((state = getState()) != expected && retryCount < MAX_RETRY) {57pause(10);58retryCount++;59}6061if (state == null) {62throw new RuntimeException(getName() + " expected to have " +63expected + " but got null.");64}6566if (state != expected) {67throw new RuntimeException(String.format("%s expected in %s state but got %s " +68"(iterations %d interrupted %d)%n",69getName(), expected, state, iterations.get(), interrupted.get()));70}71}7273public static void pause(long ms) {74try {75Thread.sleep(ms);76} catch (InterruptedException e) {77throw new RuntimeException(e);78}79}8081// Phaser to sync between the main thread putting82// this thread into various states83private final Phaser phaser = new Phaser(2);84private volatile int newState = S_RUNNABLE;85private volatile int state = 0;86private boolean done = false;8788private static final int S_RUNNABLE = 1;89private static final int S_BLOCKED = 2;90private static final int S_WAITING = 3;91private static final int S_TIMED_WAITING = 4;92private static final int S_PARKED = 5;93private static final int S_TIMED_PARKED = 6;94private static final int S_SLEEPING = 7;95private static final int S_TERMINATE = 8;9697// for debugging98private final AtomicInteger iterations = new AtomicInteger();99private final AtomicInteger interrupted = new AtomicInteger();100101private final LockFreeLogManager logManager = new LockFreeLogManager();102103@Override104public void run() {105// this thread has started106while (!done) {107// state transition108int nextState = state;109if (newState != state) {110nextState = newState;111iterations.set(0);112interrupted.set(0);113}114iterations.incrementAndGet();115switch (nextState) {116case S_RUNNABLE: {117stateChange(nextState);118double sum = 0;119for (int i = 0; i < 1000; i++) {120double r = Math.random();121double x = Math.pow(3, r);122sum += x - r;123}124break;125}126case S_BLOCKED: {127log("%d: %s is going to block (iterations %d)%n",128getId(), getName(), iterations.get());129stateChange(nextState);130// going to block on lock131synchronized (lock) {132log("%d: %s acquired the lock (iterations %d)%n",133getId(), getName(), iterations.get());134try {135// this thread has escaped the BLOCKED state136// release the lock and a short wait before continue137lock.wait(10);138} catch (InterruptedException e) {139// ignore140interrupted.incrementAndGet();141}142}143break;144}145case S_WAITING: {146synchronized (lock) {147log("%d: %s is going to waiting (iterations %d interrupted %d)%n",148getId(), getName(), iterations.get(), interrupted.get());149try {150stateChange(nextState);151lock.wait();152log("%d: %s wakes up from waiting (iterations %d interrupted %d)%n",153getId(), getName(), iterations.get(), interrupted.get());154} catch (InterruptedException e) {155// ignore156interrupted.incrementAndGet();157}158}159break;160}161case S_TIMED_WAITING: {162synchronized (lock) {163log("%d: %s is going to timed waiting (iterations %d interrupted %d)%n",164getId(), getName(), iterations.get(), interrupted.get());165try {166stateChange(nextState);167lock.wait(10000);168log("%d: %s wakes up from timed waiting (iterations %d interrupted %d)%n",169getId(), getName(), iterations.get(), interrupted.get());170} catch (InterruptedException e) {171// ignore172interrupted.incrementAndGet();173}174}175break;176}177case S_PARKED: {178log("%d: %s is going to park (iterations %d)%n",179getId(), getName(), iterations.get());180stateChange(nextState);181LockSupport.park();182break;183}184case S_TIMED_PARKED: {185log("%d: %s is going to timed park (iterations %d)%n",186getId(), getName(), iterations.get());187long deadline = System.currentTimeMillis() + 10000*1000;188stateChange(nextState);189LockSupport.parkUntil(deadline);190break;191}192case S_SLEEPING: {193log("%d: %s is going to sleep (iterations %d interrupted %d)%n",194getId(), getName(), iterations.get(), interrupted.get());195try {196stateChange(nextState);197Thread.sleep(1000000);198} catch (InterruptedException e) {199// finish sleeping200interrupted.incrementAndGet();201}202break;203}204case S_TERMINATE: {205done = true;206stateChange(nextState);207break;208}209default:210break;211}212}213}214215/**216* Change the state if it matches newState.217*/218private void stateChange(int nextState) {219// no state change220if (state == nextState)221return;222223// transition to the new state224if (newState == nextState) {225state = nextState;226phaser.arrive();227log("%d: state change: %s %s%n",228getId(), toStateName(nextState), phaserToString(phaser));229return;230}231232// should never reach here233throw new RuntimeException("current " + state + " next " + nextState +234" new state " + newState);235}236237/**238* Blocks until this thread transitions to the given state239*/240public void transitionTo(Thread.State tstate) throws InterruptedException {241switch (tstate) {242case RUNNABLE:243nextState(S_RUNNABLE);244break;245case BLOCKED:246nextState(S_BLOCKED);247break;248case WAITING:249nextState(S_WAITING);250break;251case TIMED_WAITING:252nextState(S_TIMED_WAITING);253break;254case TERMINATED:255nextState(S_TERMINATE);256break;257default:258break;259}260}261262/**263* Blocks until this thread transitions to sleeping264*/265public void transitionToSleep() throws InterruptedException {266nextState(S_SLEEPING);267}268269/**270* Blocks until this thread transitions to park or timed park271*/272public void transitionToPark(boolean timed) throws InterruptedException {273nextState(timed ? S_TIMED_PARKED : S_PARKED);274}275276private void nextState(int s) throws InterruptedException {277final long id = Thread.currentThread().getId();278log("%d: wait until the thread transitions to %s %s%n",279id, toStateName(s), phaserToString(phaser));280this.newState = s;281int phase = phaser.arrive();282log("%d: awaiting party arrive %s %s%n",283id, toStateName(s), phaserToString(phaser));284for (;;) {285// when this thread has changed its state before it waits or parks286// on a lock, a potential race might happen if it misses the notify287// or unpark. Hence await for the phaser to advance with timeout288// to cope with this race condition.289switch (state) {290case S_WAITING:291case S_TIMED_WAITING:292synchronized (lock) {293lock.notify();294}295break;296case S_PARKED:297case S_TIMED_PARKED:298LockSupport.unpark(this);299break;300case S_SLEEPING:301this.interrupt();302break;303case S_BLOCKED:304default:305break;306}307try {308phaser.awaitAdvanceInterruptibly(phase, 100, TimeUnit.MILLISECONDS);309log("%d: arrived at %s %s%n",310id, toStateName(s), phaserToString(phaser));311return;312} catch (TimeoutException ex) {313// this thread hasn't arrived at this phase314log("%d: Timeout: %s%n", id, phaser);315}316}317}318319private String phaserToString(Phaser p) {320return "[phase = " + p.getPhase() +321" parties = " + p.getRegisteredParties() +322" arrived = " + p.getArrivedParties() + "]";323}324325private String toStateName(int state) {326switch (state) {327case S_RUNNABLE:328return "runnable";329case S_WAITING:330return "waiting";331case S_TIMED_WAITING:332return "timed waiting";333case S_PARKED:334return "parked";335case S_TIMED_PARKED:336return "timed parked";337case S_SLEEPING:338return "sleeping";339case S_BLOCKED:340return "blocked";341case S_TERMINATE:342return "terminated";343default:344return "unknown " + state;345}346}347348private void log(String msg, Object ... params) {349logManager.log(msg, params);350}351352/**353* Waits for the controller to complete the test run and returns the354* generated log355* @return The controller log356* @throws InterruptedException357*/358public String getLog() throws InterruptedException {359this.join();360361return logManager.toString();362}363}364365366