0N/A/*
3261N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 4530538
0N/A * @summary Basic unit test of ThreadInfo.getLockName()
0N/A * and ThreadInfo.getLockOwnerName()
0N/A * @author Mandy Chung
0N/A *
0N/A * @build ThreadExecutionSynchronizer
2495N/A * @run main/othervm Locks
0N/A */
0N/A
0N/Aimport java.lang.management.*;
0N/A
0N/Apublic class Locks {
0N/A private static Object objA = new Object();
0N/A private static Object objB = new Object();
0N/A private static Object objC = new Object();
0N/A private static ThreadMXBean tm = ManagementFactory.getThreadMXBean();
0N/A
0N/A private static boolean testFailed = false;
0N/A
0N/A private static String getLockName(Object lock) {
0N/A if (lock == null) return null;
0N/A
0N/A return lock.getClass().getName() + '@' +
0N/A Integer.toHexString(System.identityHashCode(lock));
0N/A }
0N/A
0N/A private static void checkBlockedObject(Thread t, Object lock, Thread owner,
0N/A Thread.State expectedState) {
0N/A ThreadInfo info = tm.getThreadInfo(t.getId());
0N/A String result = info.getLockName();
0N/A String expectedLock = (lock != null ? getLockName(lock) : null);
0N/A String expectedOwner = (owner != null ? owner.getName() : null);
0N/A
0N/A if (lock != null) {
0N/A if (expectedState ==Thread.State.BLOCKED) {
0N/A int retryCount=0;
0N/A while(info.getThreadState() != Thread.State.BLOCKED) {
0N/A if (retryCount++ > 500) {
0N/A throw new RuntimeException("Thread " + t.getName() +
0N/A " is expected to block on " + expectedLock +
0N/A " but got " + result +
0N/A " Thread.State = " + info.getThreadState());
0N/A }
0N/A goSleep(100);
0N/A }
0N/A }
0N/A if (expectedState == Thread.State.WAITING &&
0N/A info.getThreadState() != Thread.State.WAITING) {
0N/A throw new RuntimeException("Thread " + t.getName() +
0N/A " is expected to wait on " + expectedLock +
0N/A " but got " + result +
0N/A " Thread.State = " + info.getThreadState());
0N/A }
0N/A }
0N/A
0N/A if ((result != null && !result.equals(expectedLock)) ||
0N/A (result == null && expectedLock != null)) {
0N/A throw new RuntimeException("Thread " + t.getName() + " is blocked on " +
0N/A expectedLock + " but got " + result);
0N/A }
0N/A result = info.getLockOwnerName();
0N/A if ((result != null && !result.equals(expectedOwner)) ||
0N/A (result == null && expectedOwner != null)) {
0N/A throw new RuntimeException("Owner of " + lock + " should be " +
0N/A expectedOwner + " but got " + result);
0N/A }
0N/A }
0N/A
0N/A private static void goSleep(long ms) {
0N/A try {
0N/A Thread.sleep(ms);
0N/A } catch (InterruptedException e) {
0N/A e.printStackTrace();
0N/A testFailed = true;
0N/A }
0N/A }
0N/A
0N/A static ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer();
0N/A static ThreadExecutionSynchronizer thrsync1 = new ThreadExecutionSynchronizer();
0N/A
0N/A static class LockAThread extends Thread {
0N/A public LockAThread() {
0N/A super("LockAThread");
0N/A }
0N/A public void run() {
0N/A synchronized(objA) {
0N/A // stop here for LockBThread to hold objB
0N/A thrsync.waitForSignal();
0N/A
0N/A System.out.println("LockAThread about to block on objB");
0N/A synchronized(objB) {};
0N/A }
0N/A System.out.println("LockAThread about to exit");
0N/A // The state could be anything. The expected state value
0N/A // passed with this method is not verified.
0N/A checkBlockedObject(this, null, null, Thread.State.TERMINATED);
0N/A }
0N/A }
0N/A
0N/A static class LockBThread extends Thread {
0N/A public LockBThread() {
0N/A super("LockBThread");
0N/A }
0N/A public void run() {
0N/A synchronized(objB) {
0N/A // signal waiting LockAThread.
0N/A thrsync.signal();
0N/A
0N/A System.out.println("LockBThread about to block on objC");
0N/A // Signal main thread about to block on objC
0N/A thrsync1.signal();
0N/A synchronized(objC) {};
0N/A }
0N/A System.out.println("LockBThread about to exit");
0N/A // The state could be anything. The expected state value
0N/A // passed with this method is not verified.
0N/A checkBlockedObject(this, null, null, Thread.State.TERMINATED);
0N/A }
0N/A
0N/A public void aboutToLockC() {
0N/A // Stop here till LockBThread about to blocked
0N/A // for lock objC.
0N/A thrsync1.waitForSignal();
0N/A goSleep(500);
0N/A }
0N/A }
0N/A
0N/A private static WaitingThread waiter;
0N/A private static Object ready = new Object();
0N/A private static CheckerThread checker;
0N/A static class WaitingThread extends Thread {
0N/A public WaitingThread() {
0N/A super("WaitingThread");
0N/A }
0N/A public void run() {
0N/A synchronized(objC) {
0N/A System.out.println("WaitingThread about to wait on objC");
0N/A try {
0N/A // Signal checker thread, about to wait on objC.
0N/A thrsync.signal();
0N/A objC.wait();
0N/A } catch (InterruptedException e) {
0N/A e.printStackTrace();
0N/A testFailed = true;
0N/A }
0N/A
0N/A // block until CheckerThread finishes checking
0N/A System.out.println("WaitingThread about to block on ready");
0N/A // signal checker thread that it is about acquire
0N/A // object ready.
0N/A thrsync.signal();
0N/A synchronized(ready) {};
0N/A }
0N/A synchronized(objC) {
0N/A try {
0N/A // signal checker thread, about to wait on objC
0N/A thrsync.signal();
0N/A objC.wait();
0N/A } catch (InterruptedException e) {
0N/A e.printStackTrace();
0N/A testFailed = true;
0N/A }
0N/A }
0N/A System.out.println("WaitingThread about to exit waiting on objC 2");
0N/A }
0N/A }
0N/A static class CheckerThread extends Thread {
0N/A public CheckerThread() {
0N/A super("CheckerThread");
0N/A }
0N/A public void run() {
0N/A synchronized (ready) {
0N/A // wait until WaitingThread about to wait for objC
0N/A thrsync.waitForSignal();
497N/A
497N/A int retryCount = 0;
497N/A while (waiter.getState() != Thread.State.WAITING
497N/A && retryCount++ < 500) {
497N/A goSleep(100);
497N/A }
0N/A checkBlockedObject(waiter, objC, null, Thread.State.WAITING);
0N/A
0N/A synchronized (objC) {
0N/A objC.notify();
0N/A }
0N/A
0N/A // wait for waiter thread to about to enter
0N/A // synchronized object ready.
0N/A thrsync.waitForSignal();
0N/A // give chance for waiter thread to get blocked on
0N/A // object ready.
0N/A goSleep(50);
0N/A checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);
0N/A }
0N/A
0N/A // wait for signal from waiting thread that it is about
0N/A // wait for objC.
0N/A thrsync.waitForSignal();
0N/A synchronized(objC) {
0N/A checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);
0N/A objC.notify();
0N/A }
0N/A
0N/A }
0N/A }
0N/A
0N/A public static void main(String args[]) throws Exception {
0N/A Thread mainThread = Thread.currentThread();
0N/A
0N/A // Test uncontested case
0N/A LockAThread t1;
0N/A LockBThread t2;
0N/A
0N/A synchronized(objC) {
0N/A // The state could be anything. The expected state value
0N/A // passed with this method is not verified.
0N/A checkBlockedObject(mainThread, null, null, Thread.State.RUNNABLE);
0N/A
0N/A // Test deadlock case
0N/A // t1 holds lockA and attempts to lock B
0N/A // t2 holds lockB and attempts to lock C
0N/A t1 = new LockAThread();
0N/A t1.start();
0N/A
0N/A t2 = new LockBThread();
0N/A t2.start();
0N/A
0N/A t2.aboutToLockC();
0N/A
0N/A checkBlockedObject(t1, objB, t2, Thread.State.BLOCKED);
0N/A checkBlockedObject(t2, objC, mainThread, Thread.State.BLOCKED);
0N/A
0N/A long[] expectedThreads = new long[3];
0N/A expectedThreads[0] = t1.getId(); // blocked on lockB
0N/A expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC
0N/A expectedThreads[2] = mainThread.getId(); // owner of lockC
0N/A findThreadsBlockedOn(objB, expectedThreads);
0N/A }
0N/A goSleep(100);
0N/A
0N/A // Test Object.wait() case
0N/A waiter = new WaitingThread();
0N/A waiter.start();
0N/A
0N/A checker = new CheckerThread();
0N/A checker.start();
0N/A
0N/A try {
0N/A waiter.join();
0N/A checker.join();
0N/A } catch (InterruptedException e) {
0N/A e.printStackTrace();
0N/A testFailed = true;
0N/A }
0N/A
0N/A if (testFailed) {
0N/A throw new RuntimeException("TEST FAILED.");
0N/A }
0N/A System.out.println("Test passed.");
0N/A }
0N/A
0N/A private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock)
0N/A throws Exception {
0N/A ThreadInfo ownerInfo = null;
0N/A for (int i = 0; i < infos.length; i++) {
0N/A String blockedLock = infos[i].getLockName();
0N/A if (lock.equals(blockedLock)) {
0N/A long threadId = infos[i].getLockOwnerId();
0N/A if (threadId == -1) {
0N/A throw new RuntimeException("TEST FAILED: " +
0N/A lock + " expected to have owner");
0N/A }
0N/A for (int j = 0; j < infos.length; j++) {
0N/A if (infos[j].getThreadId() == threadId) {
0N/A ownerInfo = infos[j];
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return ownerInfo;
0N/A }
0N/A private static void findThreadsBlockedOn(Object o, long[] expectedThreads)
0N/A throws Exception {
0N/A String lock = getLockName(o);
0N/A // Check with ThreadInfo with no stack trace (i.e. no safepoint)
0N/A ThreadInfo[] infos = tm.getThreadInfo(tm.getAllThreadIds());
0N/A doCheck(infos, lock, expectedThreads);
0N/A
0N/A // Check with ThreadInfo with stack trace
0N/A infos = tm.getThreadInfo(tm.getAllThreadIds(), 1);
0N/A doCheck(infos, lock, expectedThreads);
0N/A }
0N/A
0N/A private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads)
0N/A throws Exception {
0N/A ThreadInfo ownerInfo = null;
0N/A // Find the thread who is blocking on lock
0N/A for (int i = 0; i < infos.length; i++) {
0N/A String blockedLock = infos[i].getLockName();
0N/A if (lock.equals(blockedLock)) {
0N/A System.out.print(infos[i].getThreadName() +
0N/A " blocked on " + blockedLock);
0N/A ownerInfo = infos[i];
0N/A }
0N/A }
0N/A
0N/A long[] threads = new long[10];
0N/A int count = 0;
0N/A threads[count++] = ownerInfo.getThreadId();
0N/A while (ownerInfo != null && ownerInfo.getThreadState() == Thread.State.BLOCKED) {
0N/A ownerInfo = findOwnerInfo(infos, lock);
0N/A threads[count++] = ownerInfo.getThreadId();
0N/A System.out.println(" Owner = " + ownerInfo.getThreadName() +
0N/A " id = " + ownerInfo.getThreadId());
0N/A lock = ownerInfo.getLockName();
0N/A System.out.print(ownerInfo.getThreadName() + " Id = " +
0N/A ownerInfo.getThreadId() +
0N/A " blocked on " + lock);
0N/A }
0N/A System.out.println();
0N/A
0N/A if (count != expectedThreads.length) {
0N/A throw new RuntimeException("TEST FAILED: " +
0N/A "Expected chain of threads not matched; current count =" + count);
0N/A }
0N/A for (int i = 0; i < count; i++) {
0N/A if (threads[i] != expectedThreads[i]) {
0N/A System.out.println("TEST FAILED: " +
0N/A "Unexpected thread in the chain " + threads[i] +
0N/A " expected to be " + expectedThreads[i]);
0N/A }
0N/A }
0N/A }
0N/A}