/* * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /* * @bug 5086470 6358247 * @summary LockingThread is used by LockedMonitors test. * It will create threads that have: * - a stack frame acquires no monitor * - a stack frame acquires one or more monitors * - a stack frame blocks on Object.wait * and the monitor waiting is not locked. * @author Mandy Chung * * @build Barrier * @build ThreadDump */ import java.lang.management.*; import java.util.*; public class LockingThread extends Thread { static Lock lock1 = new Lock("lock1"); static Lock lock2 = new Lock("lock2"); static Lock lock3 = new Lock("lock3"); static Lock lock4 = new Lock("lock4"); static Lock lock5 = new Lock("lock5"); static Lock lock6 = new Lock("lock6"); static Lock lock7 = new Lock("lock7"); static Lock lock8 = new Lock("lock8"); static LockingThread t1 = new Thread1(); static LockingThread t2 = new Thread2(); static Barrier barr = new Barrier(2); static int count = 2; static void startLockingThreads() { t1.setDaemon(true); t2.setDaemon(true); t1.start(); t2.start(); // wait until t1 waits while (count != 0) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } static long[] getThreadIds() { return new long[] {t1.getId(), t2.getId()}; } static void checkLockedMonitors(ThreadInfo[] tinfos) throws Exception { int matches = 0; for (ThreadInfo ti : tinfos) { if (ti.getThreadId() == t1.getId()) { t1.checkLockedMonitors(ti); matches++; } if (ti.getThreadId() == t2.getId()) { t2.checkLockedMonitors(ti); matches++; } } if (matches != 2) { throw new RuntimeException("MonitorInfo missing"); } } static class Lock { String name; Lock(String name) { this.name = name; } public String toString() { return name; } } final String threadName; Lock waitingLock; int numOwnedMonitors; Map<String, Lock[]> ownedMonitors; public LockingThread(String name) { this.threadName = name; } protected void setExpectedResult(Lock waitingLock, int numOwnedMonitors, Map<String, Lock[]> ownedMonitors) { this.waitingLock = waitingLock; this.numOwnedMonitors = numOwnedMonitors; this.ownedMonitors = ownedMonitors; } void checkLockedMonitors(ThreadInfo info) throws Exception { checkThreadInfo(info); MonitorInfo[] monitors = info.getLockedMonitors(); if (monitors.length != numOwnedMonitors) { ThreadDump.threadDump(); throw new RuntimeException("Number of locked monitors = " + monitors.length + " not matched. Expected: " + numOwnedMonitors); } // check if each monitor returned in the list is the expected // one for (MonitorInfo m : monitors) { StackTraceElement ste = m.getLockedStackFrame(); int depth = m.getLockedStackDepth(); checkStackFrame(info, ste, depth); checkMonitor(m, ste.getMethodName()); } // check if each expected monitor is included in the returned // list for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { for (Lock l : e.getValue()) { checkMonitor(e.getKey(), l, monitors); } } if (info.getLockedSynchronizers().length != 0) { ThreadDump.threadDump(); throw new RuntimeException("Number of locked synchronizers = " + info.getLockedSynchronizers().length + " not matched. Expected: 0."); } } void checkThreadInfo(ThreadInfo info) throws Exception { if (!getName().equals(info.getThreadName())) { throw new RuntimeException("Name: " + info.getThreadName() + " not matched. Expected: " + getName()); } LockInfo l = info.getLockInfo(); if ((waitingLock == null && l != null) || (waitingLock != null && l == null)) { throw new RuntimeException("LockInfo: " + l + " not matched. Expected: " + waitingLock); } String waitingLockName = waitingLock.getClass().getName(); int hcode = System.identityHashCode(waitingLock); if (!waitingLockName.equals(l.getClassName())) { throw new RuntimeException("LockInfo : " + l + " class name not matched. Expected: " + waitingLockName); } if (hcode != l.getIdentityHashCode()) { throw new RuntimeException("LockInfo: " + l + " IdentityHashCode not matched. Expected: " + hcode); } String lockName = info.getLockName(); String[] s = lockName.split("@"); if (!waitingLockName.equals(s[0])) { throw new RuntimeException("LockName: " + lockName + " class name not matched. Expected: " + waitingLockName); } int i = Integer.parseInt(s[1], 16); if (hcode != i) { throw new RuntimeException("LockName: " + lockName + " IdentityHashCode not matched. Expected: " + hcode); } } void checkStackFrame(ThreadInfo info, StackTraceElement ste, int depth) { StackTraceElement[] stacktrace = info.getStackTrace(); if (!ste.equals(stacktrace[depth])) { System.out.println("LockedStackFrame:- " + ste); System.out.println("StackTrace at " + depth + " :-" + stacktrace[depth]); throw new RuntimeException("LockedStackFrame does not match " + "stack frame in ThreadInfo.getStackTrace"); } } void checkMonitor(MonitorInfo m, String methodName) { for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { if (methodName.equals(e.getKey())) { for (Lock l : e.getValue()) { String className = l.getClass().getName(); int hcode = System.identityHashCode(l); if (className.equals(m.getClassName()) && hcode == m.getIdentityHashCode()) { // monitor matched the expected return; } } } } throw new RuntimeException("Monitor not expected" + m); } void checkMonitor(String methodName, Lock l, MonitorInfo[] monitors) { String className = l.getClass().getName(); int hcode = System.identityHashCode(l); for (MonitorInfo m : monitors) { if (className.equals(m.getClassName()) && hcode == m.getIdentityHashCode() && methodName.equals(m.getLockedStackFrame().getMethodName())) { return; } } throw new RuntimeException("Monitor not found in the returned list" + " Method: " + methodName + " Lock: " + l); } static class Thread1 extends LockingThread { public Thread1() { super("t1"); initExpectedResult(); } public void run() { A(); } void A() { synchronized(lock1) { synchronized(lock2) { synchronized(lock3) { B(); } } } } void B() { synchronized(lock4) { synchronized(lock5) { C(); } } } void C() { synchronized(lock6) { D(); } } void D() { synchronized(lock7) { try { // signal to about to wait count--; lock7.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } Map<String, Lock[]> LOCKED_MONITORS; Lock WAITING_LOCK = lock7; int OWNED_MONITORS = 6; void initExpectedResult() { LOCKED_MONITORS = new HashMap<String, Lock[]>(); LOCKED_MONITORS.put("D", new Lock[0]); // no monitored locked LOCKED_MONITORS.put("C", new Lock[] {lock6}); LOCKED_MONITORS.put("B", new Lock[] {lock5, lock4}); LOCKED_MONITORS.put("A", new Lock[] {lock3, lock2, lock1}); this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS); } } static class Thread2 extends LockingThread { Map<String, Lock[]> LOCKED_MONITORS = new HashMap<String, Lock[]>(); Lock WAITING_LOCK = lock8; int OWNED_MONITORS = 0; public Thread2() { super("t2"); this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS); } public void run() { synchronized(lock8) { try { synchronized(lock7) { count--; } lock8.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } }