Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/SuspendWithObjectMonitorEnter/SuspendWithObjectMonitorEnter.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 enter.27* @requires vm.jvmti28* @library /test/lib29* @compile SuspendWithObjectMonitorEnter.java30* @run main/othervm/native -agentlib:SuspendWithObjectMonitorEnter SuspendWithObjectMonitorEnter31*/3233import java.io.PrintStream;3435//36// main blocker contender resumer37// ================= ================ =================== ================38// launch blocker39// <launch returns> blocker running40// launch contender enter threadLock41// <launch returns> wait for notify contender running42// launch resumer : block on threadLock43// <launch returns> : : resumer running44// suspend contender : <suspended> wait for notify45// <ready to test> : : :46// : : : :47// notify blocker wait finishes : :48// notify resumer exit threadLock : wait finishes49// join blocker : : enter threadLock50// <join returns> blocker exits <resumed> resume contender51// join resumer : exit threadLock52// <join returns> enter threadLock resumer exits53// join contender exit threadLock54// <join returns> contender exits55//5657public class SuspendWithObjectMonitorEnter {58private static final String AGENT_LIB = "SuspendWithObjectMonitorEnter";59private static final int exit_delta = 95;6061private static final int DEF_TIME_MAX = 60; // default max # secs to test62private static final int JOIN_MAX = 30; // max # secs to wait for join6364public static final int TS_INIT = 1; // initial testState65public static final int TS_BLOCKER_RUNNING = 2; // blocker is running66public static final int TS_CONTENDER_RUNNING = 3; // contender is running67public static final int TS_RESUMER_RUNNING = 4; // resumer is running68public static final int TS_CALL_SUSPEND = 5; // call suspend on contender69public static final int TS_DONE_BLOCKING = 6; // done blocking threadLock70public static final int TS_READY_TO_RESUME = 7; // ready to resume contender71public static final int TS_CALL_RESUME = 8; // call resume on contender72public static final int TS_CONTENDER_DONE = 9; // contender has run; done7374public static Object barrierLaunch = new Object(); // controls thread launch75public static Object barrierBlocker = new Object(); // controls blocker76public 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(SuspendWithObjectMonitorEnterWorker thr);86native static int wait4ContendedEnter(SuspendWithObjectMonitorEnterWorker 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 SuspendWithObjectMonitorEnter()).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) {156SuspendWithObjectMonitorEnterWorker blocker; // blocker thread157SuspendWithObjectMonitorEnterWorker contender; // contender thread158SuspendWithObjectMonitorEnterWorker resumer; // resumer thread159160System.out.println("About to execute for " + timeMax + " seconds.");161162long start_time = System.currentTimeMillis();163while (System.currentTimeMillis() < start_time + (timeMax * 1000)) {164count++;165testState = TS_INIT; // starting the test loop166167// launch the blocker thread168synchronized (barrierLaunch) {169blocker = new SuspendWithObjectMonitorEnterWorker("blocker");170blocker.start();171172while (testState != TS_BLOCKER_RUNNING) {173try {174barrierLaunch.wait(0); // wait until it is running175} catch (InterruptedException ex) {176}177}178}179180// launch the contender thread181synchronized (barrierLaunch) {182contender = new SuspendWithObjectMonitorEnterWorker("contender");183contender.start();184185while (testState != TS_CONTENDER_RUNNING) {186try {187barrierLaunch.wait(0); // wait until it is running188} catch (InterruptedException ex) {189}190}191}192193// launch the resumer thread194synchronized (barrierLaunch) {195resumer = new SuspendWithObjectMonitorEnterWorker("resumer", contender);196resumer.start();197198while (testState != TS_RESUMER_RUNNING) {199try {200barrierLaunch.wait(0); // wait until it is running201} catch (InterruptedException ex) {202}203}204}205206// wait for the contender thread to block207logDebug("before contended enter wait");208int retCode = wait4ContendedEnter(contender);209if (retCode != 0) {210throw new RuntimeException("error in JVMTI GetThreadState: " +211"retCode=" + retCode);212}213logDebug("done contended enter wait");214215checkTestState(TS_RESUMER_RUNNING);216testState = TS_CALL_SUSPEND;217logDebug("before suspend thread");218retCode = suspendThread(contender);219if (retCode != 0) {220throw new RuntimeException("error in JVMTI SuspendThread: " +221"retCode=" + retCode);222}223logDebug("suspended thread");224225//226// At this point, all of the child threads are running227// and we can get to meat of the test:228//229// - suspended threadLock contender230// - a threadLock exit in the blocker thread231// - a threadLock enter in the resumer thread232// - resumption of the contender thread233// - a threadLock enter in the freshly resumed contender thread234//235synchronized (barrierBlocker) {236checkTestState(TS_CALL_SUSPEND);237238// tell blocker thread to exit threadLock239testState = TS_DONE_BLOCKING;240barrierBlocker.notify();241}242243synchronized (barrierResumer) {244// tell resumer thread to resume contender thread245testState = TS_READY_TO_RESUME;246barrierResumer.notify();247248// Can't call checkTestState() here because the249// resumer thread may have already resumed the250// contender thread.251}252253try {254blocker.join();255resumer.join(JOIN_MAX * 1000);256if (resumer.isAlive()) {257System.err.println("Failure at " + count + " loops.");258throw new InternalError("resumer thread is stuck");259}260contender.join(JOIN_MAX * 1000);261if (contender.isAlive()) {262System.err.println("Failure at " + count + " loops.");263throw new InternalError("contender thread is stuck");264}265} catch (InterruptedException ex) {266}267268checkTestState(TS_CONTENDER_DONE);269}270271System.out.println("Executed " + count + " loops in " + timeMax +272" seconds.");273274return 0;275}276}277278class SuspendWithObjectMonitorEnterWorker extends Thread {279private SuspendWithObjectMonitorEnterWorker target; // target for resume operation280281public SuspendWithObjectMonitorEnterWorker(String name) {282super(name);283}284285public SuspendWithObjectMonitorEnterWorker(String name, SuspendWithObjectMonitorEnterWorker target) {286super(name);287this.target = target;288}289290native static int resumeThread(SuspendWithObjectMonitorEnterWorker thr);291292public void run() {293SuspendWithObjectMonitorEnter.logDebug("thread running");294295//296// Launch the blocker thread:297// - grabs threadLock298// - holds threadLock until we tell it let go299// - releases threadLock300//301if (getName().equals("blocker")) {302// grab threadLock before we tell main we are running303SuspendWithObjectMonitorEnter.logDebug("before enter threadLock");304synchronized(SuspendWithObjectMonitorEnter.threadLock) {305SuspendWithObjectMonitorEnter.logDebug("enter threadLock");306307SuspendWithObjectMonitorEnter.checkTestState(SuspendWithObjectMonitorEnter.TS_INIT);308309synchronized(SuspendWithObjectMonitorEnter.barrierBlocker) {310synchronized(SuspendWithObjectMonitorEnter.barrierLaunch) {311// tell main we are running312SuspendWithObjectMonitorEnter.testState = SuspendWithObjectMonitorEnter.TS_BLOCKER_RUNNING;313SuspendWithObjectMonitorEnter.barrierLaunch.notify();314}315SuspendWithObjectMonitorEnter.logDebug("thread waiting");316// TS_READY_TO_RESUME is set right after TS_DONE_BLOCKING317// is set so either can get the blocker thread out of318// this wait() wrapper:319while (SuspendWithObjectMonitorEnter.testState != SuspendWithObjectMonitorEnter.TS_DONE_BLOCKING &&320SuspendWithObjectMonitorEnter.testState != SuspendWithObjectMonitorEnter.TS_READY_TO_RESUME) {321try {322// wait for main to tell us when to exit threadLock323SuspendWithObjectMonitorEnter.barrierBlocker.wait(0);324} catch (InterruptedException ex) {325}326}327}328SuspendWithObjectMonitorEnter.logDebug("exit threadLock");329}330}331//332// Launch the contender thread:333// - tries to grab the threadLock334// - grabs threadLock335// - releases threadLock336//337else if (getName().equals("contender")) {338synchronized(SuspendWithObjectMonitorEnter.barrierLaunch) {339// tell main we are running340SuspendWithObjectMonitorEnter.testState = SuspendWithObjectMonitorEnter.TS_CONTENDER_RUNNING;341SuspendWithObjectMonitorEnter.barrierLaunch.notify();342}343344SuspendWithObjectMonitorEnter.logDebug("before enter threadLock");345synchronized(SuspendWithObjectMonitorEnter.threadLock) {346SuspendWithObjectMonitorEnter.logDebug("enter threadLock");347348SuspendWithObjectMonitorEnter.checkTestState(SuspendWithObjectMonitorEnter.TS_CALL_RESUME);349SuspendWithObjectMonitorEnter.testState = SuspendWithObjectMonitorEnter.TS_CONTENDER_DONE;350351SuspendWithObjectMonitorEnter.logDebug("exit threadLock");352}353}354//355// Launch the resumer thread:356// - tries to grab the threadLock (should not block!)357// - grabs threadLock358// - resumes the contended thread359// - releases threadLock360//361else if (getName().equals("resumer")) {362synchronized(SuspendWithObjectMonitorEnter.barrierResumer) {363synchronized(SuspendWithObjectMonitorEnter.barrierLaunch) {364// tell main we are running365SuspendWithObjectMonitorEnter.testState = SuspendWithObjectMonitorEnter.TS_RESUMER_RUNNING;366SuspendWithObjectMonitorEnter.barrierLaunch.notify();367}368SuspendWithObjectMonitorEnter.logDebug("thread waiting");369while (SuspendWithObjectMonitorEnter.testState != SuspendWithObjectMonitorEnter.TS_READY_TO_RESUME) {370try {371// wait for main to tell us when to continue372SuspendWithObjectMonitorEnter.barrierResumer.wait(0);373} catch (InterruptedException ex) {374}375}376}377378SuspendWithObjectMonitorEnter.logDebug("before enter threadLock");379synchronized(SuspendWithObjectMonitorEnter.threadLock) {380SuspendWithObjectMonitorEnter.logDebug("enter threadLock");381382SuspendWithObjectMonitorEnter.checkTestState(SuspendWithObjectMonitorEnter.TS_READY_TO_RESUME);383SuspendWithObjectMonitorEnter.testState = SuspendWithObjectMonitorEnter.TS_CALL_RESUME;384385// resume the contender thread so contender.join() can work386SuspendWithObjectMonitorEnter.logDebug("before resume thread");387int retCode = resumeThread(target);388if (retCode != 0) {389throw new RuntimeException("error in JVMTI ResumeThread: " +390"retCode=" + retCode);391}392SuspendWithObjectMonitorEnter.logDebug("resumed thread");393394SuspendWithObjectMonitorEnter.logDebug("exit threadLock");395}396}397}398}399400401