Path: blob/master/test/hotspot/jtreg/serviceability/monitoring/ThreadInfo/GetLockOwnerName/GetLockOwnerName.java
41161 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 8167108 826515326* @summary The test checks that ThreadInfo.getLockOwnerName() returns a27* non-null string for a blocked thread and then makes repeated calls28* to getThreadInfo() and ThreadInfo.getLockOwnerName() until the thread29* has exited.30* @requires vm.jvmti31* @run main/othervm/native -agentlib:GetLockOwnerName GetLockOwnerName32*/3334import java.io.PrintStream;35import java.lang.management.ManagementFactory;36import java.lang.management.ThreadInfo;37import java.lang.management.ThreadMXBean;3839//40// main blocker contender releaser41// ================= ================ =================== ================42// launch blocker43// <launch returns> blocker running44// launch contender enter threadLock45// <launch returns> wait for notify contender running46// launch releaser : block on threadLock47// <launch returns> : : releaser running48// wait for : : wait for notify49// contended enter : : :50// <ready to test> : : :51// getThreadInfo : : :52// verify contender : : :53// lock owner name : : :54// is "blocker" : : :55// notify releaser : : :56// loop until thread : : wait finishes57// is NULL : : notify blocker58// get thread info wait finishes : releaser exits59// get lock owner exit threadLock : :60// name blocker exits enter threadLock :61// join releaser : exit threadLock <exit finishes>62// <join returns> : contender exits63// join blocker <exit finishes> :64// <join returns> :65// join contender <exit finishes>66// <join returns>67//6869public class GetLockOwnerName {70private static final String AGENT_LIB = "GetLockOwnerName";7172private static final int DEF_TIME_MAX = 60; // default max # secs to test73private static final int JOIN_MAX = 30; // max # secs to wait for join7475public static final int TS_INIT = 1; // initial testState76public static final int TS_BLOCKER_RUNNING = 2; // blocker is running77public static final int TS_CONTENDER_RUNNING = 3; // contender is running78public static final int TS_RELEASER_RUNNING = 4; // releaser is running79public static final int TS_CONTENDER_BLOCKED = 5; // contender is blocked80public static final int TS_READY_TO_RELEASE = 6; // ready to release the blocker81public static final int TS_DONE_BLOCKING = 7; // done blocking threadLock82public static final int TS_CONTENDER_DONE = 8; // contender has run; done8384public static Object barrierLaunch = new Object(); // controls thread launch85public static Object barrierBlocker = new Object(); // controls blocker86public static Object barrierReleaser = new Object(); // controls releaser87public static Object threadLock = new Object(); // testing object8889public static long count = 0;90public static boolean printDebug = false;91public volatile static int testState;9293private static void log(String msg) { System.out.println(msg); }9495native static int wait4ContendedEnter(GetLockOwnerNameWorker thr);9697public static void main(String[] args) throws Exception {98try {99System.loadLibrary(AGENT_LIB);100log("Loaded library: " + AGENT_LIB);101} catch (UnsatisfiedLinkError ule) {102log("Failed to load library: " + AGENT_LIB);103log("java.library.path: " + System.getProperty("java.library.path"));104throw ule;105}106107int timeMax = 0;108if (args.length == 0) {109timeMax = DEF_TIME_MAX;110} else {111int argIndex = 0;112int argsLeft = args.length;113if (args[0].equals("-p")) {114printDebug = true;115argIndex = 1;116argsLeft--;117}118if (argsLeft == 0) {119timeMax = DEF_TIME_MAX;120} else if (argsLeft == 1) {121try {122timeMax = Integer.parseUnsignedInt(args[argIndex]);123} catch (NumberFormatException nfe) {124System.err.println("'" + args[argIndex] +125"': invalid timeMax value.");126usage();127}128} else {129usage();130}131}132133int retCode = run(timeMax, System.out);134if (retCode != 0) {135throw new RuntimeException("Test failed with retCode=" + retCode);136}137}138139public static void logDebug(String mesg) {140if (printDebug) {141System.err.println(Thread.currentThread().getName() + ": " + mesg);142}143}144145public static void usage() {146System.err.println("Usage: " + AGENT_LIB + " [-p][time_max]");147System.err.println("where:");148System.err.println(" -p print debug info");149System.err.println(" time_max max looping time in seconds");150System.err.println(" (default is " + DEF_TIME_MAX +151" seconds)");152System.exit(1);153}154155public static int run(int timeMax, PrintStream out) {156return (new GetLockOwnerName()).doWork(timeMax, out);157}158159public static void checkTestState(int exp) {160if (testState != exp) {161System.err.println("Failure at " + count + " loops.");162throw new InternalError("Unexpected test state value: "163+ "expected=" + exp + " actual=" + testState);164}165}166167public int doWork(int timeMax, PrintStream out) {168ThreadMXBean mbean = ManagementFactory.getThreadMXBean();169170GetLockOwnerNameWorker blocker; // blocker thread171GetLockOwnerNameWorker contender; // contender thread172GetLockOwnerNameWorker releaser; // releaser thread173174System.out.println("About to execute for " + timeMax + " seconds.");175176long start_time = System.currentTimeMillis();177while (System.currentTimeMillis() < start_time + (timeMax * 1000)) {178count++;179testState = TS_INIT; // starting the test loop180181// launch the blocker thread182synchronized (barrierLaunch) {183blocker = new GetLockOwnerNameWorker("blocker");184blocker.start();185186while (testState != TS_BLOCKER_RUNNING) {187try {188barrierLaunch.wait(); // wait until it is running189} catch (InterruptedException ex) {190}191}192}193194// launch the contender thread195synchronized (barrierLaunch) {196contender = new GetLockOwnerNameWorker("contender");197contender.start();198199while (testState != TS_CONTENDER_RUNNING) {200try {201barrierLaunch.wait(); // wait until it is running202} catch (InterruptedException ex) {203}204}205}206207// launch the releaser thread208synchronized (barrierLaunch) {209releaser = new GetLockOwnerNameWorker("releaser");210releaser.start();211212while (testState != TS_RELEASER_RUNNING) {213try {214barrierLaunch.wait(); // wait until it is running215} catch (InterruptedException ex) {216}217}218}219220// wait for the contender thread to block221logDebug("before contended enter wait");222int retCode = wait4ContendedEnter(contender);223if (retCode != 0) {224throw new RuntimeException("error in JVMTI GetThreadState " +225"or GetCurrentContendedMonitor " +226"retCode=" + retCode);227}228testState = TS_CONTENDER_BLOCKED;229logDebug("done contended enter wait");230231//232// At this point, all of the child threads are running233// and we can get to meat of the test:234//235// - query the contender thread and verify that it is blocked236// by the blocker thread237// - tell the releaser thread to release the blocker thread238// - continue to query the contender thread until it exits239//240long id = 0;241ThreadInfo info = null;242int lateCount = 0;243244checkTestState(TS_CONTENDER_BLOCKED);245246id = contender.getId();247info = mbean.getThreadInfo(id, 0);248String name = info.getLockOwnerName();249250if (name == null) {251out.println("Failure at " + count + " loops.");252throw new RuntimeException("ThreadInfo.GetLockOwnerName() "253+ "returned null name for "254+ "contender.");255} else if (!name.equals("blocker")) {256out.println("Failure at " + count + " loops.");257throw new RuntimeException("name='" + name + "': name "258+ "should be blocker.");259} else {260logDebug("ThreadInfo.GetLockOwnerName() returned blocker.");261}262263synchronized (barrierReleaser) {264// tell releaser thread to release the blocker thread265testState = TS_READY_TO_RELEASE;266barrierReleaser.notify();267}268269while (true) {270// maxDepth == 0 requires no safepoint so alternate.271int maxDepth = ((count % 1) == 1) ? Integer.MAX_VALUE : 0;272info = mbean.getThreadInfo(id, maxDepth);273if (info == null) {274// the contender has exited275break;276}277name = info.getLockOwnerName();278// We can't verify that name == null here because contender279// might be slow leaving the threadLock monitor.280lateCount++;281}282logDebug("made " + lateCount + " late calls to getThreadInfo() " +283"and info.getLockOwnerName().");284285try {286releaser.join(JOIN_MAX * 1000);287if (releaser.isAlive()) {288System.err.println("Failure at " + count + " loops.");289throw new InternalError("releaser thread is stuck");290}291blocker.join(JOIN_MAX * 1000);292if (blocker.isAlive()) {293System.err.println("Failure at " + count + " loops.");294throw new InternalError("blocker thread is stuck");295}296contender.join(JOIN_MAX * 1000);297if (contender.isAlive()) {298System.err.println("Failure at " + count + " loops.");299throw new InternalError("contender thread is stuck");300}301} catch (InterruptedException ex) {302}303304checkTestState(TS_CONTENDER_DONE);305}306307System.out.println("Executed " + count + " loops in " + timeMax +308" seconds.");309310return 0;311}312}313314class GetLockOwnerNameWorker extends Thread {315public GetLockOwnerNameWorker(String name) {316super(name);317}318319public void run() {320GetLockOwnerName.logDebug("thread running");321322//323// The blocker thread:324// - grabs threadLock325// - holds threadLock until we tell it let go326// - releases threadLock327//328if (getName().equals("blocker")) {329// grab threadLock before we tell main we are running330GetLockOwnerName.logDebug("before enter threadLock");331synchronized(GetLockOwnerName.threadLock) {332GetLockOwnerName.logDebug("enter threadLock");333334GetLockOwnerName.checkTestState(GetLockOwnerName.TS_INIT);335336synchronized(GetLockOwnerName.barrierBlocker) {337synchronized(GetLockOwnerName.barrierLaunch) {338// tell main we are running339GetLockOwnerName.testState = GetLockOwnerName.TS_BLOCKER_RUNNING;340GetLockOwnerName.barrierLaunch.notify();341}342GetLockOwnerName.logDebug("thread waiting");343while (GetLockOwnerName.testState != GetLockOwnerName.TS_DONE_BLOCKING) {344try {345// wait for main to tell us when to exit threadLock346GetLockOwnerName.barrierBlocker.wait();347} catch (InterruptedException ex) {348}349}350}351GetLockOwnerName.logDebug("exit threadLock");352}353}354//355// The contender thread:356// - tries to grab the threadLock357// - grabs threadLock358// - releases threadLock359//360else if (getName().equals("contender")) {361synchronized(GetLockOwnerName.barrierLaunch) {362// tell main we are running363GetLockOwnerName.testState = GetLockOwnerName.TS_CONTENDER_RUNNING;364GetLockOwnerName.barrierLaunch.notify();365}366367GetLockOwnerName.logDebug("before enter threadLock");368synchronized(GetLockOwnerName.threadLock) {369GetLockOwnerName.logDebug("enter threadLock");370371GetLockOwnerName.checkTestState(GetLockOwnerName.TS_DONE_BLOCKING);372GetLockOwnerName.testState = GetLockOwnerName.TS_CONTENDER_DONE;373374GetLockOwnerName.logDebug("exit threadLock");375}376}377//378// The releaser thread:379// - tries to grab the barrierBlocker (should not block!)380// - grabs barrierBlocker381// - releases the blocker thread382// - releases barrierBlocker383//384else if (getName().equals("releaser")) {385synchronized(GetLockOwnerName.barrierReleaser) {386synchronized(GetLockOwnerName.barrierLaunch) {387// tell main we are running388GetLockOwnerName.testState = GetLockOwnerName.TS_RELEASER_RUNNING;389GetLockOwnerName.barrierLaunch.notify();390}391GetLockOwnerName.logDebug("thread waiting");392while (GetLockOwnerName.testState != GetLockOwnerName.TS_READY_TO_RELEASE) {393try {394// wait for main to tell us when to continue395GetLockOwnerName.barrierReleaser.wait();396} catch (InterruptedException ex) {397}398}399}400401GetLockOwnerName.logDebug("before enter barrierBlocker");402synchronized (GetLockOwnerName.barrierBlocker) {403GetLockOwnerName.logDebug("enter barrierBlocker");404405// tell blocker thread to exit threadLock406GetLockOwnerName.testState = GetLockOwnerName.TS_DONE_BLOCKING;407GetLockOwnerName.barrierBlocker.notify();408409GetLockOwnerName.logDebug("released blocker thread");410GetLockOwnerName.logDebug("exit barrierBlocker");411}412}413}414}415416417