Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/management/ThreadMXBean/Locks.java
38821 views
/*1* Copyright (c) 2003, 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*/2223/*24* @test25* @bug 453053826* @summary Basic unit test of ThreadInfo.getLockName()27* and ThreadInfo.getLockOwnerName()28* @author Mandy Chung29* @author Jaroslav Bachorik30*31* @library /lib/testlibrary32* @build jdk.testlibrary.*33* @run main/othervm Locks34*/3536import java.lang.management.*;37import java.util.concurrent.Phaser;38import jdk.testlibrary.LockFreeLogManager;3940public class Locks {41private static final Object objA = new Object();42private static final Object objB = new Object();43private static final Object objC = new Object();44private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean();45private static final LockFreeLogManager logger = new LockFreeLogManager();4647private static boolean testFailed = false;4849private static String getLockName(Object lock) {50if (lock == null) return null;5152return lock.getClass().getName() + '@' +53Integer.toHexString(System.identityHashCode(lock));54}5556private static void assertNoLock(Thread t) {57long tid = t.getId();58ThreadInfo info = tm.getThreadInfo(tid);59String result = info.getLockName();6061if (result != null) {62throw new RuntimeException("Thread " + t.getName() + " is not supposed to hold any lock. " +63"Currently owning lock: " + result);64}65}6667private static void checkBlockedObject(Thread t, Object lock, Thread owner,68Thread.State expectedState) {69long tid = t.getId();70ThreadInfo info = tm.getThreadInfo(tid);71String result = info.getLockName();72String expectedLock = (lock != null ? getLockName(lock) : null);73String expectedOwner = (owner != null ? owner.getName() : null);7475if (lock != null) {76if (expectedState == Thread.State.BLOCKED) {77int retryCount=0;78while(info.getThreadState() != Thread.State.BLOCKED) {79if (retryCount++ > 500) {80throw new RuntimeException("Thread " + t.getName() +81" is expected to block on " + expectedLock +82" but got " + result +83" Thread.State = " + info.getThreadState());84}85goSleep(100);86info = tm.getThreadInfo(tid);87result = info.getLockName();88}89}90if (expectedState == Thread.State.WAITING &&91info.getThreadState() != Thread.State.WAITING) {92throw new RuntimeException("Thread " + t.getName() +93" is expected to wait on " + expectedLock +94" but got " + result +95" Thread.State = " + info.getThreadState());96}97}9899if ((result != null && !result.equals(expectedLock)) ||100(result == null && expectedLock != null)) {101throw new RuntimeException("Thread " + t.getName() + " is blocked on " +102expectedLock + " but got " + result);103}104result = info.getLockOwnerName();105if ((result != null && !result.equals(expectedOwner)) ||106(result == null && expectedOwner != null)) {107throw new RuntimeException("Owner of " + lock + " should be " +108expectedOwner + " but got " + result);109}110}111112private static void goSleep(long ms) {113try {114Thread.sleep(ms);115} catch (InterruptedException e) {116e.printStackTrace();117testFailed = true;118}119}120121private static volatile int dummyCounter = 0;122123static class LockAThread extends Thread {124private final Phaser p;125public LockAThread(Phaser p) {126super("LockAThread");127this.p = p;128}129public void run() {130synchronized(objA) {131// stop here for LockBThread to hold objB132log("LockAThread about to block on objB");133p.arriveAndAwaitAdvance(); // Phase 1 (blocking)134synchronized(objB) {135dummyCounter++;136};137}138p.arriveAndAwaitAdvance(); // Phase 2 (blocking)139log("LockAThread about to exit");140// Make sure the current thread is not holding any lock141assertNoLock(this);142}143}144145static class LockBThread extends Thread {146private final Phaser p;147public LockBThread(Phaser p) {148super("LockBThread");149this.p = p;150}151public void run() {152synchronized(objB) {153log("LockBThread about to block on objC");154p.arriveAndAwaitAdvance(); // Phase 1 (blocking)155// Signal main thread about to block on objC156synchronized(objC) {157dummyCounter++;158};159}160p.arriveAndAwaitAdvance(); // Phase 2 (blocking)161log("LockBThread about to exit");162// Make sure the current thread is not holding any lock163assertNoLock(this);164}165}166167private static WaitingThread waiter;168private static final Object ready = new Object();169private static CheckerThread checker;170static class WaitingThread extends Thread {171private final Phaser p;172173volatile boolean waiting = false;174175public WaitingThread(Phaser p) {176super("WaitingThread");177this.p = p;178}179@Override180public void run() {181synchronized(objC) {182log("WaitingThread about to wait on objC");183try {184// Signal checker thread, about to wait on objC.185waiting = false;186p.arriveAndAwaitAdvance(); // Phase 1 (waiting)187waiting = true;188objC.wait();189} catch (InterruptedException e) {190e.printStackTrace();191testFailed = true;192}193194// block until CheckerThread finishes checking195log("WaitingThread about to block on ready");196// signal checker thread that it is about acquire197// object ready.198p.arriveAndAwaitAdvance(); // Phase 2 (waiting)199synchronized(ready) {200dummyCounter++;201}202}203synchronized(objC) {204try {205// signal checker thread, about to wait on objC206waiting = false;207p.arriveAndAwaitAdvance(); // Phase 3 (waiting)208waiting = true;209objC.wait();210} catch (InterruptedException e) {211e.printStackTrace();212testFailed = true;213}214}215log("WaitingThread about to exit waiting on objC 2");216}217218public void waitForWaiting() {219p.arriveAndAwaitAdvance();220while (!waiting) {221goSleep(10);222}223waitForState(State.WAITING);224}225226public void waitForBlocked() {227p.arriveAndAwaitAdvance();228waitForState(State.BLOCKED);229}230231private void waitForState(Thread.State state) {232while (!waiter.isInterrupted() && waiter.getState() != state) {233Thread.yield();234}235}236}237static class CheckerThread extends Thread {238public CheckerThread() {239super("CheckerThread");240}241242public void run() {243synchronized (ready) {244// wait until WaitingThread about to wait for objC245waiter.waitForWaiting(); // Phase 1 (waiting)246checkBlockedObject(waiter, objC, null, Thread.State.WAITING);247248synchronized (objC) {249objC.notify();250}251252// wait for waiter thread to about to enter253// synchronized object ready.254waiter.waitForBlocked(); // Phase 2 (waiting)255checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);256}257258// wait for signal from waiting thread that it is about259// wait for objC.260waiter.waitForWaiting(); // Phase 3 (waiting)261synchronized(objC) {262checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);263objC.notify();264}265266}267}268269public static void main(String args[]) throws Exception {270Thread mainThread = Thread.currentThread();271272// Test uncontested case273LockAThread t1;274LockBThread t2;275276Phaser p = new Phaser(3);277synchronized(objC) {278// Make sure the main thread is not holding any lock279assertNoLock(mainThread);280281// Test deadlock case282// t1 holds lockA and attempts to lock B283// t2 holds lockB and attempts to lock C284285t1 = new LockAThread(p);286t1.start();287288t2 = new LockBThread(p);289t2.start();290291p.arriveAndAwaitAdvance(); // Phase 1 (blocking)292checkBlockedObject(t2, objC, mainThread, Thread.State.BLOCKED);293checkBlockedObject(t1, objB, t2, Thread.State.BLOCKED);294295long[] expectedThreads = new long[3];296expectedThreads[0] = t1.getId(); // blocked on lockB297expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC298expectedThreads[2] = mainThread.getId(); // owner of lockC299findThreadsBlockedOn(objB, expectedThreads);300}301p.arriveAndAwaitAdvance(); // Phase 2 (blocking)302303p = new Phaser(2);304// Test Object.wait() case305waiter = new WaitingThread(p);306waiter.start();307308checker = new CheckerThread();309checker.start();310311try {312waiter.join();313checker.join();314} catch (InterruptedException e) {315e.printStackTrace();316testFailed = true;317}318319if (testFailed) {320throw new RuntimeException("TEST FAILED.");321}322System.out.println("Test passed.");323}324325private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock)326throws Exception {327ThreadInfo ownerInfo = null;328for (ThreadInfo info : infos) {329String blockedLock = info.getLockName();330if (lock.equals(blockedLock)) {331long threadId = info.getLockOwnerId();332if (threadId == -1) {333throw new RuntimeException("TEST FAILED: " +334lock + " expected to have owner");335}336for (int j = 0; j < infos.length; j++) {337if (infos[j].getThreadId() == threadId) {338ownerInfo = infos[j];339break;340}341}342}343}344return ownerInfo;345}346private static void findThreadsBlockedOn(Object o, long[] expectedThreads)347throws Exception {348String lock = getLockName(o);349// Check with ThreadInfo with no stack trace (i.e. no safepoint)350ThreadInfo[] infos = tm.getThreadInfo(tm.getAllThreadIds());351doCheck(infos, lock, expectedThreads);352353// Check with ThreadInfo with stack trace354infos = tm.getThreadInfo(tm.getAllThreadIds(), 1);355doCheck(infos, lock, expectedThreads);356}357358private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads)359throws Exception {360ThreadInfo ownerInfo = null;361// Find the thread who is blocking on lock362for (ThreadInfo info : infos) {363String blockedLock = info.getLockName();364if (lock.equals(blockedLock)) {365log("%s blocked on %s", info.getThreadName(), blockedLock);366ownerInfo = info;367}368}369if (ownerInfo == null) {370throw new RuntimeException("TEST FAILED: " +371"Can't retrieve ThreadInfo for the blocked thread");372}373374long[] threads = new long[10];375int count = 0;376threads[count++] = ownerInfo.getThreadId();377while (ownerInfo != null && ownerInfo.getThreadState() == Thread.State.BLOCKED) {378ownerInfo = findOwnerInfo(infos, lock);379threads[count++] = ownerInfo.getThreadId();380log(" Owner = %s id = %d",381ownerInfo.getThreadName(),382ownerInfo.getThreadId()383);384lock = ownerInfo.getLockName();385log("%s Id = %d blocked on %s",386ownerInfo.getThreadName(),387ownerInfo.getThreadId(),388lock389);390}391log("");392393if (count != expectedThreads.length) {394throw new RuntimeException("TEST FAILED: " +395"Expected chain of threads not matched; current count =" + count);396}397for (int i = 0; i < count; i++) {398if (threads[i] != expectedThreads[i]) {399log("TEST FAILED: Unexpected thread in the chain %s expected to be %s",400threads[i],401expectedThreads[i]402);403}404}405}406407private static void log(String format, Object ... args) {408logger.log(format + "%n", args);409}410}411412413