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 SynchronizersLockingThread is used by LockedSynchronizers. 27 * It will create threads that acquire ReentrantLock and also object 28 * monitors. 29 * @author Mandy Chung 30 * 31 * @build ThreadDump Utils 32 */ 33 34import java.lang.management.*; 35import java.util.*; 36import java.util.concurrent.locks.ReentrantLock; 37import java.util.concurrent.locks.Condition; 38 39public class SynchronizerLockingThread extends Thread { 40 static ReentrantLock lock1 = new ReentrantLock(); 41 static ReentrantLock lock2 = new ReentrantLock(); 42 static ReentrantLock lock3 = new ReentrantLock(); 43 static ReentrantLock lock4 = new ReentrantLock(); 44 static Lock lock5 = new Lock("lock5"); 45 static Lock lock6 = new Lock("lock6"); 46 static Lock lock7 = new Lock("lock7"); 47 static ReentrantLock lock8 = new ReentrantLock(); 48 49 static SynchronizerLockingThread t1 = new Thread1(); 50 static SynchronizerLockingThread t2 = new Thread2(); 51 static int count = 2; 52 static void startLockingThreads() { 53 t1.setDaemon(true); 54 t2.setDaemon(true); 55 t1.start(); 56 t2.start(); 57 58 // wait until t1 and t2 waits 59 while (count != 0) { 60 try { 61 Thread.sleep(100); 62 } catch (InterruptedException e) { 63 throw new RuntimeException(e); 64 } 65 } 66 67 Utils.waitForBlockWaitingState(t1); 68 Utils.waitForBlockWaitingState(t2); 69 } 70 71 static long[] getThreadIds() { 72 return new long[] {t1.getId(), t2.getId()}; 73 } 74 75 static void checkLocks(ThreadInfo[] tinfos) throws Exception { 76 int matches = 0; 77 for (ThreadInfo info : tinfos) { 78 if (info.getThreadId() == t1.getId()) { 79 t1.checkLocks(info); 80 matches++; 81 } 82 if (info.getThreadId() == t2.getId()) { 83 t2.checkLocks(info); 84 matches++; 85 } 86 } 87 if (matches != 2) { 88 throw new RuntimeException("MonitorInfo missing"); 89 } 90 } 91 92 static class Lock { 93 String name; 94 Lock(String name) { 95 this.name = name; 96 } 97 public String toString() { 98 return name; 99 } 100 } 101 102 final String threadName; 103 Lock waitingLock; 104 int numOwnedMonitors; 105 Map<String, Lock[]> ownedMonitors; 106 Condition waitingSync; 107 int numOwnedSyncs; 108 Map<String, ReentrantLock[]> ownedSyncs; 109 public SynchronizerLockingThread(String name) { 110 this.threadName = name; 111 } 112 113 protected void setExpectedResult(Lock waitingLock, 114 int numOwnedMonitors, 115 Map<String, Lock[]> ownedMonitors, 116 Condition waitingSync, 117 int numOwnedSyncs, 118 Map<String, ReentrantLock[]> ownedSyncs) { 119 this.waitingLock = waitingLock; 120 this.numOwnedMonitors = numOwnedMonitors; 121 this.ownedMonitors = ownedMonitors; 122 this.waitingSync = waitingSync; 123 this.numOwnedSyncs = numOwnedSyncs; 124 this.ownedSyncs = ownedSyncs; 125 } 126 127 void checkLocks(ThreadInfo info) throws Exception { 128 checkThreadInfo(info); 129 MonitorInfo[] monitors = info.getLockedMonitors(); 130 if (monitors.length != numOwnedMonitors) { 131 ThreadDump.threadDump(); 132 throw new RuntimeException("Number of locked monitors = " + 133 monitors.length + 134 " not matched. Expected: " + numOwnedMonitors); 135 } 136 // check if each monitor returned in the list is the expected 137 // one 138 for (MonitorInfo m : monitors) { 139 StackTraceElement ste = m.getLockedStackFrame(); 140 int depth = m.getLockedStackDepth(); 141 checkStackFrame(info, ste, depth); 142 checkMonitor(m, ste.getMethodName()); 143 } 144 // check if each expected monitor is included in the returned 145 // list 146 for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { 147 for (Lock l : e.getValue()) { 148 checkMonitor(e.getKey(), l, monitors); 149 } 150 } 151 152 // We can only check if the length matches since we have no 153 // way to get the AbstractOwnableSynchronizer in ReentrantLock 154 LockInfo[] syncs = info.getLockedSynchronizers(); 155 if (syncs.length != numOwnedSyncs) { 156 ThreadDump.threadDump(); 157 throw new RuntimeException("Number of locked syncs = " + 158 syncs.length + 159 " not matched. Expected: " + numOwnedSyncs); 160 } 161 } 162 163 void checkThreadInfo(ThreadInfo info) throws Exception { 164 if (!getName().equals(info.getThreadName())) { 165 throw new RuntimeException("Name: " + info.getThreadName() + 166 " not matched. Expected: " + getName()); 167 } 168 LockInfo l = info.getLockInfo(); 169 if ((waitingLock != null || waitingSync != null) && l == null) { 170 throw new RuntimeException("LockInfo: " + l + 171 " not matched. Expected: non-null"); 172 } 173 if (waitingLock == null && waitingSync == null && l != null) { 174 throw new RuntimeException("LockInfo: " + l + 175 " not matched. Expected: null"); 176 } 177 178 String waitingLockName; 179 int hcode; 180 if (waitingLock != null) { 181 waitingLockName = waitingLock.getClass().getName(); 182 hcode = System.identityHashCode(waitingLock); 183 } else { 184 waitingLockName = waitingSync.getClass().getName(); 185 hcode = System.identityHashCode(waitingSync); 186 } 187 if (!waitingLockName.equals(l.getClassName())) { 188 throw new RuntimeException("LockInfo : " + l + 189 " class name not matched. Expected: " + waitingLockName); 190 } 191 if (hcode != l.getIdentityHashCode()) { 192 throw new RuntimeException("LockInfo: " + l + 193 " IdentityHashCode not matched. Expected: " + hcode); 194 } 195 196 String lockName = info.getLockName(); 197 String[] s = lockName.split("@"); 198 if (!waitingLockName.equals(s[0])) { 199 throw new RuntimeException("LockName: " + lockName + 200 " class name not matched. Expected: " + waitingLockName); 201 } 202 int i = Integer.parseInt(s[1], 16); 203 if (hcode != i) { 204 throw new RuntimeException("LockName: " + lockName + 205 " IdentityHashCode not matched. Expected: " + hcode); 206 } 207 } 208 209 void checkStackFrame(ThreadInfo info, StackTraceElement ste, int depth) { 210 StackTraceElement[] stacktrace = info.getStackTrace(); 211 if (!ste.equals(stacktrace[depth])) { 212 System.out.println("LockedStackFrame:- " + ste); 213 System.out.println("StackTrace at " + depth + " :-" + 214 stacktrace[depth]); 215 throw new RuntimeException("LockedStackFrame does not match " + 216 "stack frame in ThreadInfo.getStackTrace"); 217 } 218 } 219 void checkMonitor(MonitorInfo m, String methodName) { 220 for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) { 221 if (methodName.equals(e.getKey())) { 222 for (Lock l : e.getValue()) { 223 String className = l.getClass().getName(); 224 int hcode = System.identityHashCode(l); 225 if (className.equals(m.getClassName()) && 226 hcode == m.getIdentityHashCode()) { 227 // monitor matched the expected 228 return; 229 } 230 } 231 } 232 } 233 throw new RuntimeException("Monitor not expected" + m); 234 } 235 void checkMonitor(String methodName, Lock l, MonitorInfo[] monitors) { 236 String className = l.getClass().getName(); 237 int hcode = System.identityHashCode(l); 238 for (MonitorInfo m : monitors) { 239 if (className.equals(m.getClassName()) && 240 hcode == m.getIdentityHashCode() && 241 methodName.equals(m.getLockedStackFrame().getMethodName())) { 242 return; 243 } 244 } 245 throw new RuntimeException("Monitor not found in the returned list" + 246 " Method: " + methodName + " Lock: " + l); 247 248 } 249 250 static class Thread1 extends SynchronizerLockingThread { 251 public Thread1() { 252 super("t1"); 253 initExpectedResult(); 254 } 255 public void run() { 256 A(); 257 } 258 void A() { 259 lock1.lock(); 260 try { 261 lock2.lock(); 262 try { 263 lock3.lock(); 264 try { 265 B(); 266 } finally { 267 lock3.unlock(); 268 } 269 } finally { 270 lock2.unlock(); 271 } 272 } finally { 273 lock1.unlock(); 274 } 275 } 276 void B() { 277 lock4.lock(); 278 try { 279 synchronized(lock5) { 280 C(); 281 } 282 } finally { 283 lock4.unlock(); 284 } 285 } 286 void C() { 287 synchronized(lock6) { 288 D(); 289 } 290 } 291 void D() { 292 synchronized(lock7) { 293 try { 294 // signal to about to wait 295 count--; 296 lock7.wait(); 297 } catch (InterruptedException e) { 298 throw new RuntimeException(e); 299 } 300 } 301 } 302 303 Map<String, Lock[]> LOCKED_MONITORS; 304 Map<String, ReentrantLock[]> LOCKED_SYNCS; 305 Lock WAITING_LOCK = lock7; 306 int OWNED_MONITORS = 2; 307 int OWNED_SYNCS = 4; 308 void initExpectedResult() { 309 LOCKED_MONITORS = new HashMap<String, Lock[]>(); 310 LOCKED_MONITORS.put("D", new Lock[0]); // no monitored locked 311 LOCKED_MONITORS.put("C", new Lock[] {lock6}); 312 LOCKED_MONITORS.put("B", new Lock[] {lock5}); 313 LOCKED_MONITORS.put("A", new Lock[0]); 314 315 LOCKED_SYNCS = new HashMap<String, ReentrantLock[]>(); 316 LOCKED_SYNCS.put("D", new ReentrantLock[0]); // no sync locked 317 LOCKED_SYNCS.put("C", new ReentrantLock[0]); // no sync locked 318 LOCKED_SYNCS.put("B", new ReentrantLock[] {lock4}); 319 LOCKED_SYNCS.put("A", new ReentrantLock[] {lock3, lock2, lock1}); 320 this.setExpectedResult(WAITING_LOCK, 321 OWNED_MONITORS, LOCKED_MONITORS, 322 null, 323 OWNED_SYNCS, LOCKED_SYNCS); 324 } 325 326 } 327 328 static class Thread2 extends SynchronizerLockingThread { 329 Map<String, Lock[]> LOCKED_MONITORS = new HashMap<String, Lock[]>(); 330 Map<String, ReentrantLock[]> LOCKED_SYNCS = new HashMap<String, ReentrantLock[]>(); 331 Condition c = lock8.newCondition(); 332 Condition WAITING_LOCK = c; 333 int OWNED_MONITORS = 0; 334 int OWNED_SYNCS = 0; 335 public Thread2() { 336 super("t2"); 337 this.setExpectedResult(null, 338 OWNED_MONITORS, LOCKED_MONITORS, 339 WAITING_LOCK, 340 OWNED_SYNCS, LOCKED_SYNCS); 341 } 342 public void run() { 343 lock8.lock(); 344 try { 345 synchronized(lock7) { 346 count--; 347 } 348 c.await(); 349 } catch (InterruptedException e) { 350 throw new RuntimeException(e); 351 } finally { 352 lock8.unlock(); 353 } 354 throw new RuntimeException("should not reach here"); 355 } 356 } 357 358} 359