1 /* 2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @bug 5086470 6358247 26 * @summary LockingThread is used by LockedMonitors test. 27 * It will create threads that have: 28 * - a stack frame acquires no monitor 29 * - a stack frame acquires one or more monitors 30 * - a stack frame blocks on Object.wait 31 * and the monitor waiting is not locked. 32 * @author Mandy Chung 33 * 34 * @build Barrier 35 * @build ThreadDump 36 */ 37 38 import java.lang.management.*; 39 import java.util.*; 40 41 public class LockingThread extends Thread { 42 static Lock lock1 = new Lock("lock1"); 43 static Lock lock2 = new Lock("lock2"); 44 static Lock lock3 = new Lock("lock3"); 45 static Lock lock4 = new Lock("lock4"); 46 static Lock lock5 = new Lock("lock5"); 47 static Lock lock6 = new Lock("lock6"); 48 static Lock lock7 = new Lock("lock7"); 49 static Lock lock8 = new Lock("lock8"); 50 51 static LockingThread t1 = new Thread1(); 52 static LockingThread t2 = new Thread2(); 53 static Barrier barr = new Barrier(2); 54 static int count = 2; startLockingThreads()55 static void startLockingThreads() { 56 t1.setDaemon(true); 57 t2.setDaemon(true); 58 t1.start(); 59 t2.start(); 60 61 // wait until t1 waits 62 while (count != 0) { 63 try { 64 Thread.sleep(100); 65 } catch (InterruptedException e) { 66 throw new RuntimeException(e); 67 } 68 } 69 Utils.waitForBlockWaitingState(t1); 70 Utils.waitForBlockWaitingState(t2); 71 } getThreadIds()72 static long[] getThreadIds() { 73 return new long[] {t1.getId(), t2.getId()}; 74 } 75 checkLockedMonitors(ThreadInfo[] tinfos)76 static void checkLockedMonitors(ThreadInfo[] tinfos) 77 throws Exception { 78 79 int matches = 0; 80 for (ThreadInfo ti : tinfos) { 81 if (ti.getThreadId() == t1.getId()) { 82 t1.checkLockedMonitors(ti); 83 matches++; 84 } 85 if (ti.getThreadId() == t2.getId()) { 86 t2.checkLockedMonitors(ti); 87 matches++; 88 } 89 } 90 if (matches != 2) { 91 throw new RuntimeException("MonitorInfo missing"); 92 } 93 } 94 95 static class Lock { 96 String name; Lock(String name)97 Lock(String name) { 98 this.name = name; 99 } toString()100 public String toString() { 101 return name; 102 } 103 } 104 105 final String threadName; 106 Lock waitingLock; 107 int numOwnedMonitors; 108 Map<String, Lock[]> ownedMonitors; LockingThread(String name)109 public LockingThread(String name) { 110 this.threadName = name; 111 } 112 setExpectedResult(Lock waitingLock, int numOwnedMonitors, Map<String, Lock[]> ownedMonitors)113 protected void setExpectedResult(Lock waitingLock, 114 int numOwnedMonitors, 115 Map<String, Lock[]> ownedMonitors) { 116 this.waitingLock = waitingLock; 117 this.numOwnedMonitors = numOwnedMonitors; 118 this.ownedMonitors = ownedMonitors; 119 } 120 checkLockedMonitors(ThreadInfo info)121 void checkLockedMonitors(ThreadInfo info) 122 throws Exception { 123 checkThreadInfo(info); 124 125 MonitorInfo[] monitors = info.getLockedMonitors(); 126 if (monitors.length != numOwnedMonitors) { 127 ThreadDump.threadDump(); 128 throw new RuntimeException("Number of locked monitors = " + 129 monitors.length + 130 " not matched. Expected: " + numOwnedMonitors); 131 } 132 // check if each monitor returned in the list is the expected 133 // one 134 for (MonitorInfo m : monitors) { 135 StackTraceElement ste = m.getLockedStackFrame(); 136 int depth = m.getLockedStackDepth(); 137 checkStackFrame(info, ste, depth); 138 checkMonitor(m, ste.getMethodName()); 139 } 140 // check if each expected monitor is included in the returned 141 // list 142 for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { 143 for (Lock l : e.getValue()) { 144 checkMonitor(e.getKey(), l, monitors); 145 } 146 } 147 148 if (info.getLockedSynchronizers().length != 0) { 149 ThreadDump.threadDump(); 150 throw new RuntimeException("Number of locked synchronizers = " + 151 info.getLockedSynchronizers().length + 152 " not matched. Expected: 0."); 153 } 154 } 155 checkThreadInfo(ThreadInfo info)156 void checkThreadInfo(ThreadInfo info) throws Exception { 157 if (!getName().equals(info.getThreadName())) { 158 throw new RuntimeException("Name: " + info.getThreadName() + 159 " not matched. Expected: " + getName()); 160 } 161 LockInfo l = info.getLockInfo(); 162 if ((waitingLock == null && l != null) || 163 (waitingLock != null && l == null)) { 164 throw new RuntimeException("LockInfo: " + l + 165 " not matched. Expected: " + waitingLock); 166 } 167 168 String waitingLockName = waitingLock.getClass().getName(); 169 int hcode = System.identityHashCode(waitingLock); 170 if (!waitingLockName.equals(l.getClassName())) { 171 throw new RuntimeException("LockInfo : " + l + 172 " class name not matched. Expected: " + waitingLockName); 173 } 174 if (hcode != l.getIdentityHashCode()) { 175 throw new RuntimeException("LockInfo: " + l + 176 " IdentityHashCode not matched. Expected: " + hcode); 177 } 178 179 String lockName = info.getLockName(); 180 String[] s = lockName.split("@"); 181 if (!waitingLockName.equals(s[0])) { 182 throw new RuntimeException("LockName: " + lockName + 183 " class name not matched. Expected: " + waitingLockName); 184 } 185 int i = Integer.parseInt(s[1], 16); 186 if (hcode != i) { 187 throw new RuntimeException("LockName: " + lockName + 188 " IdentityHashCode not matched. Expected: " + hcode); 189 } 190 } 191 checkStackFrame(ThreadInfo info, StackTraceElement ste, int depth)192 void checkStackFrame(ThreadInfo info, StackTraceElement ste, int depth) { 193 StackTraceElement[] stacktrace = info.getStackTrace(); 194 if (!ste.equals(stacktrace[depth])) { 195 System.out.println("LockedStackFrame:- " + ste); 196 System.out.println("StackTrace at " + depth + " :-" + 197 stacktrace[depth]); 198 throw new RuntimeException("LockedStackFrame does not match " + 199 "stack frame in ThreadInfo.getStackTrace"); 200 } 201 } checkMonitor(MonitorInfo m, String methodName)202 void checkMonitor(MonitorInfo m, String methodName) { 203 for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { 204 if (methodName.equals(e.getKey())) { 205 for (Lock l : e.getValue()) { 206 String className = l.getClass().getName(); 207 int hcode = System.identityHashCode(l); 208 if (className.equals(m.getClassName()) && 209 hcode == m.getIdentityHashCode()) { 210 // monitor matched the expected 211 return; 212 } 213 } 214 } 215 } 216 throw new RuntimeException("Monitor not expected" + m); 217 } checkMonitor(String methodName, Lock l, MonitorInfo[] monitors)218 void checkMonitor(String methodName, Lock l, MonitorInfo[] monitors) { 219 String className = l.getClass().getName(); 220 int hcode = System.identityHashCode(l); 221 for (MonitorInfo m : monitors) { 222 if (className.equals(m.getClassName()) && 223 hcode == m.getIdentityHashCode() && 224 methodName.equals(m.getLockedStackFrame().getMethodName())) { 225 return; 226 } 227 } 228 throw new RuntimeException("Monitor not found in the returned list" + 229 " Method: " + methodName + " Lock: " + l); 230 231 } 232 233 static class Thread1 extends LockingThread { Thread1()234 public Thread1() { 235 super("t1"); 236 initExpectedResult(); 237 } run()238 public void run() { 239 A(); 240 } A()241 void A() { 242 synchronized(lock1) { 243 synchronized(lock2) { 244 synchronized(lock3) { 245 B(); 246 } 247 } 248 } 249 } B()250 void B() { 251 synchronized(lock4) { 252 synchronized(lock5) { 253 C(); 254 } 255 } 256 } C()257 void C() { 258 synchronized(lock6) { 259 D(); 260 } 261 } D()262 void D() { 263 synchronized(lock7) { 264 try { 265 // signal to about to wait 266 count--; 267 lock7.wait(); 268 } catch (InterruptedException e) { 269 throw new RuntimeException(e); 270 } 271 } 272 } 273 274 Map<String, Lock[]> LOCKED_MONITORS; 275 Lock WAITING_LOCK = lock7; 276 int OWNED_MONITORS = 6; initExpectedResult()277 void initExpectedResult() { 278 LOCKED_MONITORS = new HashMap<String, Lock[]>(); 279 LOCKED_MONITORS.put("D", new Lock[0]); // no monitored locked 280 LOCKED_MONITORS.put("C", new Lock[] {lock6}); 281 LOCKED_MONITORS.put("B", new Lock[] {lock5, lock4}); 282 LOCKED_MONITORS.put("A", new Lock[] {lock3, lock2, lock1}); 283 this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS); 284 } 285 286 } 287 288 static class Thread2 extends LockingThread { 289 Map<String, Lock[]> LOCKED_MONITORS = new HashMap<String, Lock[]>(); 290 Lock WAITING_LOCK = lock8; 291 int OWNED_MONITORS = 0; Thread2()292 public Thread2() { 293 super("t2"); 294 this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS); 295 } run()296 public void run() { 297 synchronized(lock8) { 298 try { 299 synchronized(lock7) { 300 count--; 301 } 302 lock8.wait(); 303 } catch (InterruptedException e) { 304 throw new RuntimeException(e); 305 } 306 } 307 } 308 } 309 310 } 311