Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorWait/SuspendWithObjectMonitorWait.java
41153 views
/*1* Copyright (c) 2001, 2021, 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*/2223/*24* @test25* @bug 4413752 826288126* @summary Test SuspendThread with ObjectMonitor wait.27* @requires vm.jvmti28* @library /test/lib29* @compile SuspendWithObjectMonitorWait.java30* @run main/othervm/native -agentlib:SuspendWithObjectMonitorWait SuspendWithObjectMonitorWait31*/3233import java.io.PrintStream;3435//36// main waiter resumer37// ================= ================== ===================38// launch waiter39// <launch returns> waiter running40// launch resumer enter threadLock41// <launch returns> threadLock.wait() resumer running42// enter threadLock : wait for notify43// threadLock.notify wait finishes :44// : reenter blocks :45// suspend waiter <suspended> :46// exit threadLock : :47// <ready to test> : :48// : : :49// notify resumer : wait finishes50// join resumer : enter threadLock51// : <resumed> resume waiter52// : : exit threadLock53// : reenter threadLock :54// <join returns> : resumer exits55// join waiter :56// <join returns> waiter exits57//5859public class SuspendWithObjectMonitorWait {60private static final String AGENT_LIB = "SuspendWithObjectMonitorWait";61private static final int exit_delta = 95;6263private static final int DEF_TIME_MAX = 60; // default max # secs to test64private static final int JOIN_MAX = 30; // max # secs to wait for join6566public static final int TS_INIT = 1; // initial testState67public static final int TS_WAITER_RUNNING = 2; // waiter is running68public static final int TS_RESUMER_RUNNING = 3; // resumer is running69public static final int TS_READY_TO_NOTIFY = 4; // ready to notify threadLock70public static final int TS_CALL_SUSPEND = 5; // call suspend on contender71public static final int TS_READY_TO_RESUME = 6; // ready to resume waiter72public static final int TS_CALL_RESUME = 7; // call resume on waiter73public static final int TS_WAITER_DONE = 8; // waiter has run; done7475public static Object barrierLaunch = new Object(); // controls thread launch76public static Object barrierResumer = new Object(); // controls resumer77public static Object threadLock = new Object(); // testing object7879public static long count = 0;80public static boolean printDebug = false;81public volatile static int testState;8283private static void log(String msg) { System.out.println(msg); }8485native static int suspendThread(SuspendWithObjectMonitorWaitWorker thr);86native static int wait4ContendedEnter(SuspendWithObjectMonitorWaitWorker thr);8788public static void main(String[] args) throws Exception {89try {90System.loadLibrary(AGENT_LIB);91log("Loaded library: " + AGENT_LIB);92} catch (UnsatisfiedLinkError ule) {93log("Failed to load library: " + AGENT_LIB);94log("java.library.path: " + System.getProperty("java.library.path"));95throw ule;96}9798int timeMax = 0;99if (args.length == 0) {100timeMax = DEF_TIME_MAX;101} else {102int argIndex = 0;103int argsLeft = args.length;104if (args[0].equals("-p")) {105printDebug = true;106argIndex = 1;107argsLeft--;108}109if (argsLeft == 0) {110timeMax = DEF_TIME_MAX;111} else if (argsLeft == 1) {112try {113timeMax = Integer.parseUnsignedInt(args[argIndex]);114} catch (NumberFormatException nfe) {115System.err.println("'" + args[argIndex] +116"': invalid timeMax value.");117usage();118}119} else {120usage();121}122}123124System.exit(run(timeMax, System.out) + exit_delta);125}126127public static void logDebug(String mesg) {128if (printDebug) {129System.err.println(Thread.currentThread().getName() + ": " + mesg);130}131}132133public static void usage() {134System.err.println("Usage: " + AGENT_LIB + " [-p][time_max]");135System.err.println("where:");136System.err.println(" -p ::= print debug info");137System.err.println(" time_max ::= max looping time in seconds");138System.err.println(" (default is " + DEF_TIME_MAX +139" seconds)");140System.exit(1);141}142143public static int run(int timeMax, PrintStream out) {144return (new SuspendWithObjectMonitorWait()).doWork(timeMax, out);145}146147public static void checkTestState(int exp) {148if (testState != exp) {149System.err.println("Failure at " + count + " loops.");150throw new InternalError("Unexpected test state value: "151+ "expected=" + exp + " actual=" + testState);152}153}154155public int doWork(int timeMax, PrintStream out) {156SuspendWithObjectMonitorWaitWorker waiter; // waiter thread157SuspendWithObjectMonitorWaitWorker resumer; // resumer thread158159System.out.println("About to execute for " + timeMax + " seconds.");160161long start_time = System.currentTimeMillis();162while (System.currentTimeMillis() < start_time + (timeMax * 1000)) {163count++;164testState = TS_INIT; // starting the test loop165166// launch the waiter thread167synchronized (barrierLaunch) {168waiter = new SuspendWithObjectMonitorWaitWorker("waiter");169waiter.start();170171while (testState != TS_WAITER_RUNNING) {172try {173barrierLaunch.wait(0); // wait until it is running174} catch (InterruptedException ex) {175}176}177}178179// launch the resumer thread180synchronized (barrierLaunch) {181resumer = new SuspendWithObjectMonitorWaitWorker("resumer", waiter);182resumer.start();183184while (testState != TS_RESUMER_RUNNING) {185try {186barrierLaunch.wait(0); // wait until it is running187} catch (InterruptedException ex) {188}189}190}191192checkTestState(TS_RESUMER_RUNNING);193194// The waiter thread was synchronized on threadLock before it195// set TS_WAITER_RUNNING and notified barrierLaunch above so196// we cannot enter threadLock until the waiter thread calls197// threadLock.wait().198synchronized (threadLock) {199// notify waiter thread so it can try to reenter threadLock200testState = TS_READY_TO_NOTIFY;201threadLock.notify();202203// wait for the waiter thread to block204logDebug("before contended enter wait");205int retCode = wait4ContendedEnter(waiter);206if (retCode != 0) {207throw new RuntimeException("error in JVMTI GetThreadState: "208+ "retCode=" + retCode);209}210logDebug("done contended enter wait");211212checkTestState(TS_READY_TO_NOTIFY);213testState = TS_CALL_SUSPEND;214logDebug("before suspend thread");215retCode = suspendThread(waiter);216if (retCode != 0) {217throw new RuntimeException("error in JVMTI SuspendThread: "218+ "retCode=" + retCode);219}220logDebug("suspended thread");221}222223//224// At this point, all of the child threads are running225// and we can get to meat of the test:226//227// - suspended threadLock waiter (trying to reenter)228// - a threadLock enter in the resumer thread229// - resumption of the waiter thread230// - a threadLock enter in the freshly resumed waiter thread231//232233synchronized (barrierResumer) {234checkTestState(TS_CALL_SUSPEND);235236// tell resumer thread to resume waiter thread237testState = TS_READY_TO_RESUME;238barrierResumer.notify();239240// Can't call checkTestState() here because the241// resumer thread may have already resumed the242// waiter thread.243}244245try {246resumer.join(JOIN_MAX * 1000);247if (resumer.isAlive()) {248System.err.println("Failure at " + count + " loops.");249throw new InternalError("resumer thread is stuck");250}251waiter.join(JOIN_MAX * 1000);252if (waiter.isAlive()) {253System.err.println("Failure at " + count + " loops.");254throw new InternalError("waiter thread is stuck");255}256} catch (InterruptedException ex) {257}258259checkTestState(TS_WAITER_DONE);260}261262System.out.println("Executed " + count + " loops in " + timeMax +263" seconds.");264265return 0;266}267}268269class SuspendWithObjectMonitorWaitWorker extends Thread {270private SuspendWithObjectMonitorWaitWorker target; // target for resume operation271272public SuspendWithObjectMonitorWaitWorker(String name) {273super(name);274}275276public SuspendWithObjectMonitorWaitWorker(String name, SuspendWithObjectMonitorWaitWorker target) {277super(name);278this.target = target;279}280281native static int resumeThread(SuspendWithObjectMonitorWaitWorker thr);282283public void run() {284SuspendWithObjectMonitorWait.logDebug("thread running");285286//287// Launch the waiter thread:288// - grab the threadLock289// - threadLock.wait()290// - releases threadLock291//292if (getName().equals("waiter")) {293// grab threadLock before we tell main we are running294SuspendWithObjectMonitorWait.logDebug("before enter threadLock");295synchronized(SuspendWithObjectMonitorWait.threadLock) {296SuspendWithObjectMonitorWait.logDebug("enter threadLock");297298SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_INIT);299300synchronized(SuspendWithObjectMonitorWait.barrierLaunch) {301// tell main we are running302SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_WAITER_RUNNING;303SuspendWithObjectMonitorWait.barrierLaunch.notify();304}305306SuspendWithObjectMonitorWait.logDebug("before wait");307308// TS_READY_TO_NOTIFY is set after the main thread has309// entered threadLock so a spurious wakeup can't get the310// waiter thread out of this threadLock.wait(0) call:311while (SuspendWithObjectMonitorWait.testState <= SuspendWithObjectMonitorWait.TS_READY_TO_NOTIFY) {312try {313SuspendWithObjectMonitorWait.threadLock.wait(0);314} catch (InterruptedException ex) {315}316}317318SuspendWithObjectMonitorWait.logDebug("after wait");319320SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_CALL_RESUME);321SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_WAITER_DONE;322323SuspendWithObjectMonitorWait.logDebug("exit threadLock");324}325}326//327// Launch the resumer thread:328// - tries to grab the threadLock (should not block!)329// - grabs threadLock330// - resumes the waiter thread331// - releases threadLock332//333else if (getName().equals("resumer")) {334synchronized(SuspendWithObjectMonitorWait.barrierResumer) {335synchronized(SuspendWithObjectMonitorWait.barrierLaunch) {336// tell main we are running337SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_RESUMER_RUNNING;338SuspendWithObjectMonitorWait.barrierLaunch.notify();339}340SuspendWithObjectMonitorWait.logDebug("thread waiting");341while (SuspendWithObjectMonitorWait.testState != SuspendWithObjectMonitorWait.TS_READY_TO_RESUME) {342try {343// wait for main to tell us when to continue344SuspendWithObjectMonitorWait.barrierResumer.wait(0);345} catch (InterruptedException ex) {346}347}348}349350SuspendWithObjectMonitorWait.logDebug("before enter threadLock");351synchronized(SuspendWithObjectMonitorWait.threadLock) {352SuspendWithObjectMonitorWait.logDebug("enter threadLock");353354SuspendWithObjectMonitorWait.checkTestState(SuspendWithObjectMonitorWait.TS_READY_TO_RESUME);355SuspendWithObjectMonitorWait.testState = SuspendWithObjectMonitorWait.TS_CALL_RESUME;356357// resume the waiter thread so waiter.join() can work358SuspendWithObjectMonitorWait.logDebug("before resume thread");359int retCode = resumeThread(target);360if (retCode != 0) {361throw new RuntimeException("error in JVMTI ResumeThread: " +362"retCode=" + retCode);363}364SuspendWithObjectMonitorWait.logDebug("resumed thread");365366SuspendWithObjectMonitorWait.logDebug("exit threadLock");367}368}369}370}371372373