1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package art; 18 19 import java.util.concurrent.Semaphore; 20 21 public class Test1932 { 22 public static final boolean PRINT_FULL_STACK_TRACE = false; 23 public static final boolean INCLUDE_ANDROID_ONLY_TESTS = false; 24 25 public static interface MonitorHandler { handleMonitorEnter(Thread thd, Object lock)26 public default void handleMonitorEnter(Thread thd, Object lock) {} handleMonitorEntered(Thread thd, Object lock)27 public default void handleMonitorEntered(Thread thd, Object lock) {} handleMonitorWait(Thread thd, Object lock, long timeout)28 public default void handleMonitorWait(Thread thd, Object lock, long timeout) {} handleMonitorWaited(Thread thd, Object lock, boolean timed_out)29 public default void handleMonitorWaited(Thread thd, Object lock, boolean timed_out) {} 30 } 31 32 public static volatile MonitorHandler HANDLER = null; 33 run()34 public static void run() throws Exception { 35 Monitors.setupMonitorEvents( 36 Test1932.class, 37 Test1932.class.getDeclaredMethod("handleMonitorEnter", Thread.class, Object.class), 38 Test1932.class.getDeclaredMethod("handleMonitorEntered", Thread.class, Object.class), 39 Test1932.class.getDeclaredMethod("handleMonitorWait", 40 Thread.class, Object.class, Long.TYPE), 41 Test1932.class.getDeclaredMethod("handleMonitorWaited", 42 Thread.class, Object.class, Boolean.TYPE), 43 Monitors.NamedLock.class, 44 null); 45 46 System.out.println("Testing contended locking where lock is released before callback ends."); 47 testLockUncontend(new Monitors.NamedLock("Lock testLockUncontend")); 48 49 System.out.println("Testing throwing exceptions in monitor_enter"); 50 testLockThrowEnter(new Monitors.NamedLock("Lock testLockThrowEnter")); 51 52 System.out.println("Testing throwing exceptions in monitor_entered"); 53 testLockThrowEntered(new Monitors.NamedLock("Lock testLockThrowEntered")); 54 55 System.out.println("Testing throwing exceptions in both monitorEnter & MonitorEntered"); 56 testLockThrowBoth(new Monitors.NamedLock("Lock testLockThrowBoth")); 57 58 // This exposes a difference between the RI and ART. On the RI this test will cause a 59 // JVMTI_EVENT_MONITOR_WAITED event to be sent even though we threw an exception during the 60 // JVMTI_EVENT_MONITOR_WAIT. See b/65558434. 61 System.out.println("Testing throwing exception in MonitorWait event"); 62 testThrowWait(new Monitors.NamedLock("Lock testThrowWait")); 63 64 System.out.println("Testing throwing exception in MonitorWait event with illegal aruments"); 65 testThrowIllegalWait(new Monitors.NamedLock("Lock testThrowIllegalWait")); 66 67 System.out.println("Testing throwing exception in MonitorWaited event"); 68 testThrowWaited(new Monitors.NamedLock("Lock testThrowWaited")); 69 70 System.out.println("Testing throwing exception in MonitorWaited event caused by timeout"); 71 testThrowWaitedTimeout(new Monitors.NamedLock("Lock testThrowWaitedTimeout")); 72 73 System.out.println("Testing throwing exception in MonitorWaited event caused by interrupt"); 74 testThrowWaitedInterrupt(new Monitors.NamedLock("Lock testThrowWaitedInterrupt")); 75 76 System.out.println("Testing ObjectMonitorInfo inside of events"); 77 testMonitorInfoInEvents(new Monitors.NamedLock("Lock testMonitorInfoInEvents")); 78 79 System.out.println("Testing that the monitor can be stolen during the MonitorWaited event."); 80 testWaitEnterInterleaving(new Monitors.NamedLock("test testWaitEnterInterleaving")); 81 82 // TODO We keep this here since it works on android but it's not clear it's behavior we want to 83 // support long term or at all. 84 if (INCLUDE_ANDROID_ONLY_TESTS) { 85 System.out.println( 86 "Testing that the monitor can be still held by notifier during the MonitorWaited " + 87 "event. NB This doesn't work on the RI."); 88 testWaitExitInterleaving(new Monitors.NamedLock("test testWaitExitInterleaving")); 89 } 90 91 System.out.println( 92 "Testing that we can lock and release the monitor in the MonitorWait event"); 93 testWaitMonitorEnter(new Monitors.NamedLock("test testWaitMonitorEnter")); 94 95 System.out.println( 96 "Testing that we can lock and release the monitor in the MonitorWaited event"); 97 testWaitedMonitorEnter(new Monitors.NamedLock("test testWaitedMonitorEnter")); 98 99 System.out.println("Testing we can perform recursive lock in MonitorEntered"); 100 testRecursiveMontiorEnteredLock(new Monitors.NamedLock("test testRecursiveMontiorEnteredLock")); 101 102 System.out.println("Testing the lock state if MonitorEnter throws in a native method"); 103 testNativeLockStateThrowEnter(new Monitors.NamedLock("test testNativeLockStateThrowEnter")); 104 105 System.out.println("Testing the lock state if MonitorEntered throws in a native method"); 106 testNativeLockStateThrowEntered(new Monitors.NamedLock("test testNativeLockStateThrowEntered")); 107 } 108 doNativeLockPrint(Monitors.NamedLock lk)109 public static native void doNativeLockPrint(Monitors.NamedLock lk); printLockState(Monitors.NamedLock lk, Object exception, int res)110 public static void printLockState(Monitors.NamedLock lk, Object exception, int res) { 111 System.out.println( 112 "MonitorEnter returned: " + res + "\n" + 113 "Lock state is: " + Monitors.getObjectMonitorUsage(lk)); 114 printExceptions((Throwable)exception); 115 } 116 testNativeLockStateThrowEnter(final Monitors.NamedLock lk)117 public static void testNativeLockStateThrowEnter(final Monitors.NamedLock lk) throws Exception { 118 final Monitors.LockController controller1 = new Monitors.LockController(lk); 119 HANDLER = new MonitorHandler() { 120 @Override public void handleMonitorEnter(Thread t, Object l) { 121 System.out.println("Unlocking controller1 in MonitorEnter"); 122 try { 123 controller1.DoUnlock(); 124 } catch (Exception e) { 125 throw new Monitors.TestException("Exception unlocking monitor in MonitorEnter " + l, e); 126 } 127 System.out.println("Throwing exception in MonitorEnter"); 128 throw new Monitors.TestException("throwing exception during monitorEnter of " + l); 129 } 130 }; 131 controller1.DoLock(); 132 controller1.waitForLockToBeHeld(); 133 Thread native_thd = new Thread(() -> { 134 try { 135 doNativeLockPrint(lk); 136 } catch (Throwable e) { 137 System.out.println("Unhandled exception: " + e); 138 e.printStackTrace(); 139 } 140 }, "NativeLockStateThrowEnter thread"); 141 native_thd.start(); 142 native_thd.join(); 143 } 144 testNativeLockStateThrowEntered(final Monitors.NamedLock lk)145 public static void testNativeLockStateThrowEntered(final Monitors.NamedLock lk) throws Exception { 146 final Monitors.LockController controller1 = new Monitors.LockController(lk); 147 HANDLER = new MonitorHandler() { 148 @Override public void handleMonitorEnter(Thread t, Object l) { 149 System.out.println("Unlocking controller1 in MonitorEnter"); 150 try { 151 controller1.DoUnlock(); 152 } catch (Exception e) { 153 throw new Monitors.TestException("Exception unlocking monitor in MonitorEnter " + l, e); 154 } 155 } 156 @Override public void handleMonitorEntered(Thread t, Object l) { 157 System.out.println("Throwing exception in MonitorEntered"); 158 throw new Monitors.TestException("throwing exception during monitorEntered of " + l); 159 } 160 }; 161 controller1.DoLock(); 162 controller1.waitForLockToBeHeld(); 163 Thread native_thd = new Thread(() -> { 164 try { 165 doNativeLockPrint(lk); 166 } catch (Throwable e) { 167 System.out.println("Unhandled exception: " + e); 168 e.printStackTrace(); 169 } 170 }, "NativeLockStateThrowEntered thread"); 171 native_thd.start(); 172 native_thd.join(); 173 } 174 testRecursiveMontiorEnteredLock(final Monitors.NamedLock lk)175 public static void testRecursiveMontiorEnteredLock(final Monitors.NamedLock lk) throws Exception { 176 Monitors.LockController controller1 = new Monitors.LockController(lk); 177 Monitors.LockController controller2 = new Monitors.LockController(lk); 178 HANDLER = new MonitorHandler() { 179 @Override public void handleMonitorEntered(Thread thd, Object l) { 180 try { 181 System.out.println("In MonitorEntered usage: " + Monitors.getObjectMonitorUsage(lk)); 182 synchronized (lk) { 183 System.out.println("In MonitorEntered sync: " + Monitors.getObjectMonitorUsage(lk)); 184 } 185 } catch (Exception e) { 186 throw new Monitors.TestException("error while recursive locking!", e); 187 } 188 } 189 }; 190 controller1.DoLock(); 191 controller1.waitForLockToBeHeld(); 192 controller2.DoLock(); 193 controller2.waitForContendedSleep(); 194 controller1.DoUnlock(); 195 controller2.waitForLockToBeHeld(); 196 controller2.DoUnlock(); 197 } 198 testWaitedMonitorEnter(final Monitors.NamedLock lk)199 public static void testWaitedMonitorEnter(final Monitors.NamedLock lk) throws Exception { 200 final Monitors.LockController controller1 = new Monitors.LockController(lk); 201 final Monitors.LockController controller2 = new Monitors.LockController(lk); 202 HANDLER = new MonitorHandler() { 203 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 204 try { 205 // make sure that controller2 has acutally unlocked everything, we can be sent earlier 206 // than that on ART. 207 while (controller2.IsLocked()) {} 208 System.out.println("In waited monitor usage: " + Monitors.getObjectMonitorUsage(lk)); 209 synchronized (lk) { 210 System.out.println( 211 "In waited monitor usage sync: " + Monitors.getObjectMonitorUsage(lk)); 212 } 213 } catch (Exception e) { 214 throw new Monitors.TestException("error while doing unlock in other thread!", e); 215 } 216 } 217 }; 218 controller1.DoLock(); 219 controller1.waitForLockToBeHeld(); 220 controller1.DoWait(); 221 controller1.waitForNotifySleep(); 222 try (AutoCloseable suppress = SuppressContention(controller2)) { 223 controller2.DoLock(); 224 controller2.waitForLockToBeHeld(); 225 controller2.DoNotifyAll(); 226 // See comment in testWaitMonitorEnter. 227 } 228 controller2.DoUnlock(); 229 controller1.waitForLockToBeHeld(); 230 controller1.DoUnlock(); 231 } 232 testWaitMonitorEnter(final Monitors.NamedLock lk)233 public static void testWaitMonitorEnter(final Monitors.NamedLock lk) throws Exception { 234 final Monitors.LockController controller1 = new Monitors.LockController(lk); 235 final Monitors.LockController controller2 = new Monitors.LockController(lk); 236 HANDLER = new MonitorHandler() { 237 @Override public void handleMonitorWait(Thread thd, Object l, long timeout) { 238 try { 239 System.out.println("In wait monitor usage: " + Monitors.getObjectMonitorUsage(lk)); 240 synchronized (lk) { 241 System.out.println("In wait monitor usage sync: " + Monitors.getObjectMonitorUsage(lk)); 242 } 243 } catch (Exception e) { 244 throw new Monitors.TestException("error while doing unlock in other thread!", e); 245 } 246 } 247 }; 248 controller1.DoLock(); 249 controller1.waitForLockToBeHeld(); 250 controller1.DoWait(); 251 controller1.waitForNotifySleep(); 252 // We've seen extra messages about contended locking here. They're OK if e.g. controller1 253 // wakes up spuriously before the notification, which is allowed. But in the normal case, 254 // we should not see contended locking here. And the extra messages seem rare enough that 255 // we can tolerate the spurious failures to catch more bugs. See b/149308087. 256 try (AutoCloseable suppress = SuppressContention(controller2)) { 257 controller2.DoLock(); 258 controller2.waitForLockToBeHeld(); 259 controller2.DoNotifyAll(); 260 } 261 controller2.DoUnlock(); 262 controller1.waitForLockToBeHeld(); 263 controller1.DoUnlock(); 264 } 265 266 // NB This test cannot be run on the RI. It deadlocks. Leaving for documentation. testWaitExitInterleaving(Monitors.NamedLock lk)267 public static void testWaitExitInterleaving(Monitors.NamedLock lk) throws Exception { 268 final Monitors.LockController controller1 = new Monitors.LockController(lk); 269 final Monitors.LockController controller2 = new Monitors.LockController(lk); 270 HANDLER = new MonitorHandler() { 271 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 272 System.out.println("un-locking controller1 in controller2 MonitorWaited event"); 273 try { 274 controller1.DoUnlock(); 275 } catch (Exception e) { 276 throw new Monitors.TestException("error while doing unlock in other thread!", e); 277 } 278 } 279 }; 280 controller2.DoLock(); 281 controller2.waitForLockToBeHeld(); 282 controller2.DoWait(); 283 controller2.waitForNotifySleep(); 284 try (AutoCloseable suppress = SuppressContention(controller1)) { 285 controller1.DoLock(); 286 controller1.waitForLockToBeHeld(); 287 controller1.DoNotifyAll(); 288 // See comment in testWaitMonitorEnter. 289 } 290 controller2.waitForLockToBeHeld(); 291 controller2.DoUnlock(); 292 } 293 testWaitEnterInterleaving(Monitors.NamedLock lk)294 public static void testWaitEnterInterleaving(Monitors.NamedLock lk) throws Exception { 295 final Monitors.LockController controller1 = new Monitors.LockController(lk); 296 final Monitors.LockController controller2 = new Monitors.LockController(lk); 297 final Monitors.LockController controller3 = new Monitors.LockController(lk); 298 final Semaphore unlocked_sem = new Semaphore(0); 299 final Semaphore continue_sem = new Semaphore(0); 300 HANDLER = new MonitorHandler() { 301 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 302 System.out.println("locking controller3 in controller2 MonitorWaited event"); 303 try { 304 unlocked_sem.acquire(); 305 controller3.DoLock(); 306 controller3.waitForLockToBeHeld(); 307 System.out.println( 308 "Controller3 now holds the lock the monitor wait will try to re-acquire"); 309 continue_sem.release(); 310 } catch (Exception e) { 311 throw new Monitors.TestException("error while doing unlock in other thread!", e); 312 } 313 } 314 }; 315 controller2.DoLock(); 316 controller2.waitForLockToBeHeld(); 317 controller2.DoWait(); 318 controller2.waitForNotifySleep(); 319 controller1.DoLock(); 320 controller1.waitForLockToBeHeld(); 321 controller1.DoNotifyAll(); 322 // See comment in testWaitMonitorEnter. 323 controller1.DoUnlock(); 324 // Wait for controller3 to have locked. 325 // We cannot use waitForLockToBeHeld since we could race with the HANDLER waitForLockToBeHeld 326 // function. 327 unlocked_sem.release(); 328 continue_sem.acquire(); 329 controller3.DoUnlock(); 330 controller2.waitForLockToBeHeld(); 331 controller2.DoUnlock(); 332 } 333 testMonitorInfoInEvents(Monitors.NamedLock lk)334 public static void testMonitorInfoInEvents(Monitors.NamedLock lk) throws Exception { 335 final Monitors.LockController controller1 = new Monitors.LockController(lk); 336 final Monitors.LockController controller2 = new Monitors.LockController(lk); 337 HANDLER = new MonitorHandler() { 338 @Override public void handleMonitorEnter(Thread thd, Object l) { 339 System.out.println("Monitor usage in MonitorEnter: " + Monitors.getObjectMonitorUsage(l)); 340 } 341 @Override public void handleMonitorEntered(Thread thd, Object l) { 342 System.out.println("Monitor usage in MonitorEntered: " + Monitors.getObjectMonitorUsage(l)); 343 } 344 @Override public void handleMonitorWait(Thread thd, Object l, long timeout) { 345 System.out.println("Monitor usage in MonitorWait: " + Monitors.getObjectMonitorUsage(l)); 346 } 347 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 348 // make sure that controller1 has acutally unlocked everything, we can be sent earlier than 349 // that on ART. 350 while (controller1.IsLocked()) {} 351 System.out.println("Monitor usage in MonitorWaited: " + Monitors.getObjectMonitorUsage(l)); 352 } 353 }; 354 controller1.DoLock(); 355 controller1.waitForLockToBeHeld(); 356 controller2.DoLock(); 357 controller2.waitForContendedSleep(); 358 controller1.DoUnlock(); 359 controller2.waitForLockToBeHeld(); 360 controller2.DoWait(); 361 controller2.waitForNotifySleep(); 362 controller1.DoLock(); 363 controller1.waitForLockToBeHeld(); 364 controller1.DoNotifyAll(); 365 // See comment in testWaitMonitorEnter. 366 controller1.DoUnlock(); 367 controller2.waitForLockToBeHeld(); 368 controller2.DoUnlock(); 369 } 370 testThrowWaitedInterrupt(Monitors.NamedLock lk)371 public static void testThrowWaitedInterrupt(Monitors.NamedLock lk) throws Exception { 372 final Monitors.LockController controller1 = new Monitors.LockController(lk); 373 HANDLER = new MonitorHandler() { 374 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 375 System.out.println("Throwing exception in MonitorWaited"); 376 throw new Monitors.TestException("throwing exception during monitorWaited of " + l); 377 } 378 }; 379 controller1.DoLock(); 380 controller1.waitForLockToBeHeld(); 381 try { 382 controller1.DoWait(); 383 controller1.waitForNotifySleep(); 384 controller1.interruptWorker(); 385 controller1.waitForLockToBeHeld(); 386 controller1.DoUnlock(); 387 System.out.println("No Exception thrown!"); 388 } catch (Monitors.TestException e) { 389 printExceptions(e); 390 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 391 controller1.DoCleanup(); 392 } 393 } 394 testThrowWaitedTimeout(Monitors.NamedLock lk)395 public static void testThrowWaitedTimeout(Monitors.NamedLock lk) throws Exception { 396 final Monitors.LockController controller1 = new Monitors.LockController(lk, 5 * 1000); 397 HANDLER = new MonitorHandler() { 398 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 399 System.out.println("Throwing exception in MonitorWaited"); 400 throw new Monitors.TestException("throwing exception during monitorWaited of " + l); 401 } 402 }; 403 controller1.DoLock(); 404 controller1.waitForLockToBeHeld(); 405 try { 406 controller1.DoTimedWait(); 407 controller1.waitForNotifySleep(); 408 controller1.waitForLockToBeHeld(); 409 controller1.DoUnlock(); 410 System.out.println("No Exception thrown!"); 411 } catch (Monitors.TestException e) { 412 printExceptions(e); 413 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 414 controller1.DoCleanup(); 415 } 416 } 417 testThrowWaited(Monitors.NamedLock lk)418 public static void testThrowWaited(Monitors.NamedLock lk) throws Exception { 419 final Monitors.LockController controller1 = new Monitors.LockController(lk); 420 final Monitors.LockController controller2 = new Monitors.LockController(lk); 421 HANDLER = new MonitorHandler() { 422 @Override public void handleMonitorWaited(Thread thd, Object l, boolean timeout) { 423 System.out.println("Throwing exception in MonitorWaited"); 424 throw new Monitors.TestException("throwing exception during monitorWaited of " + l); 425 } 426 }; 427 controller1.DoLock(); 428 controller1.waitForLockToBeHeld(); 429 controller1.DoWait(); 430 controller1.waitForNotifySleep(); 431 432 controller2.DoLock(); 433 controller2.waitForLockToBeHeld(); 434 controller2.DoNotifyAll(); 435 // See comment in testWaitMonitorEnter. 436 controller2.DoUnlock(); 437 try { 438 controller1.waitForLockToBeHeld(); 439 controller1.DoUnlock(); 440 System.out.println("No Exception thrown!"); 441 } catch (Monitors.TestException e) { 442 printExceptions(e); 443 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 444 controller1.DoCleanup(); 445 } 446 } 447 testThrowWait(final Monitors.NamedLock lk)448 public static void testThrowWait(final Monitors.NamedLock lk) throws Exception { 449 final Monitors.LockController controller1 = new Monitors.LockController(lk); 450 HANDLER = new MonitorHandler() { 451 @Override public void handleMonitorWait(Thread thd, Object l, long timeout) { 452 System.out.println("Throwing exception in MonitorWait"); 453 throw new Monitors.TestException("throwing exception during MonitorWait of " + l); 454 } 455 }; 456 controller1.DoLock(); 457 controller1.waitForLockToBeHeld(); 458 try { 459 controller1.DoWait(); 460 controller1.waitForNotifySleep(); 461 controller1.waitForLockToBeHeld(); 462 controller1.DoUnlock(); 463 System.out.println("No Exception thrown!"); 464 } catch (Monitors.TestException e) { 465 printExceptions(e); 466 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 467 controller1.DoCleanup(); 468 } 469 } 470 testThrowIllegalWait(final Monitors.NamedLock lk)471 public static void testThrowIllegalWait(final Monitors.NamedLock lk) throws Exception { 472 final Monitors.LockController controller1 = new Monitors.LockController(lk, -100000); 473 HANDLER = new MonitorHandler() { 474 @Override public void handleMonitorWait(Thread thd, Object l, long timeout) { 475 System.out.println("Throwing exception in MonitorWait timeout = " + timeout); 476 throw new Monitors.TestException("throwing exception during monitorWait of " + l); 477 } 478 }; 479 try { 480 controller1.DoLock(); 481 controller1.waitForLockToBeHeld(); 482 controller1.DoTimedWait(); 483 controller1.waitForLockToBeHeld(); 484 controller1.DoUnlock(); 485 System.out.println("No Exception thrown!"); 486 } catch (Monitors.TestException e) { 487 printExceptions(e); 488 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 489 controller1.DoCleanup(); 490 } 491 } 492 testLockUncontend(final Monitors.NamedLock lk)493 public static void testLockUncontend(final Monitors.NamedLock lk) throws Exception { 494 final Monitors.LockController controller1 = new Monitors.LockController(lk); 495 final Monitors.LockController controller2 = new Monitors.LockController(lk); 496 HANDLER = new MonitorHandler() { 497 @Override public void handleMonitorEnter(Thread thd, Object lock) { 498 if (controller1.IsLocked()) { 499 System.out.println("Releasing " + lk + " during monitorEnter event."); 500 try { 501 controller1.DoUnlock(); 502 } catch (Exception e) { 503 throw new Error("Unable to unlock controller1", e); 504 } 505 } else { 506 throw new Error("controller1 does not seem to hold the lock!"); 507 } 508 } 509 }; 510 controller1.DoLock(); 511 controller1.waitForLockToBeHeld(); 512 // This will call handleMonitorEnter but will release during the callback. 513 controller2.DoLock(); 514 controller2.waitForLockToBeHeld(); 515 if (controller1.IsLocked()) { 516 throw new Error("controller1 still holds the lock somehow!"); 517 } 518 controller2.DoUnlock(); 519 } 520 testLockThrowEnter(Monitors.NamedLock lk)521 public static void testLockThrowEnter(Monitors.NamedLock lk) throws Exception { 522 Monitors.LockController controller1 = new Monitors.LockController(lk); 523 Monitors.LockController controller2 = new Monitors.LockController(lk); 524 HANDLER = new MonitorHandler() { 525 @Override public void handleMonitorEnter(Thread t, Object l) { 526 System.out.println("Throwing exception in MonitorEnter"); 527 throw new Monitors.TestException("throwing exception during monitorEnter of " + l); 528 } 529 }; 530 controller1.DoLock(); 531 controller1.waitForLockToBeHeld(); 532 try { 533 controller2.DoLock(); 534 controller2.waitForContendedSleep(); 535 controller1.DoUnlock(); 536 controller2.waitForLockToBeHeld(); 537 controller2.DoUnlock(); 538 System.out.println("Did not get an exception!"); 539 } catch (Monitors.TestException e) { 540 printExceptions(e); 541 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 542 controller2.DoCleanup(); 543 } 544 } 545 testLockThrowEntered(Monitors.NamedLock lk)546 public static void testLockThrowEntered(Monitors.NamedLock lk) throws Exception { 547 Monitors.LockController controller1 = new Monitors.LockController(lk); 548 Monitors.LockController controller2 = new Monitors.LockController(lk); 549 HANDLER = new MonitorHandler() { 550 @Override public void handleMonitorEntered(Thread t, Object l) { 551 System.out.println("Throwing exception in MonitorEntered"); 552 throw new Monitors.TestException("throwing exception during monitorEntered of " + l); 553 } 554 }; 555 controller1.DoLock(); 556 controller1.waitForLockToBeHeld(); 557 try { 558 controller2.DoLock(); 559 controller2.waitForContendedSleep(); 560 controller1.DoUnlock(); 561 controller2.waitForLockToBeHeld(); 562 controller2.DoUnlock(); 563 System.out.println("Did not get an exception!"); 564 } catch (Monitors.TestException e) { 565 printExceptions(e); 566 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 567 controller2.DoCleanup(); 568 } 569 } 570 testLockThrowBoth(Monitors.NamedLock lk)571 public static void testLockThrowBoth(Monitors.NamedLock lk) throws Exception { 572 Monitors.LockController controller1 = new Monitors.LockController(lk); 573 Monitors.LockController controller2 = new Monitors.LockController(lk); 574 HANDLER = new MonitorHandler() { 575 @Override public void handleMonitorEnter(Thread t, Object l) { 576 System.out.println("Throwing exception in MonitorEnter"); 577 throw new Monitors.TestException("throwing exception during monitorEnter of " + l); 578 } 579 @Override public void handleMonitorEntered(Thread t, Object l) { 580 System.out.println("Throwing exception in MonitorEntered"); 581 throw new Monitors.TestException("throwing exception during monitorEntered of " + l); 582 } 583 }; 584 controller1.DoLock(); 585 controller1.waitForLockToBeHeld(); 586 try { 587 controller2.DoLock(); 588 controller2.waitForContendedSleep(); 589 controller1.DoUnlock(); 590 controller2.waitForLockToBeHeld(); 591 controller2.DoUnlock(); 592 System.out.println("Did not get an exception!"); 593 } catch (Monitors.TestException e) { 594 printExceptions(e); 595 System.out.println("lock state is: " + Monitors.getObjectMonitorUsage(lk)); 596 controller2.DoCleanup(); 597 } 598 } 599 printExceptions(Throwable t)600 public static void printExceptions(Throwable t) { 601 System.out.println("Caught exception: " + t); 602 for (Throwable c = t.getCause(); c != null; c = c.getCause()) { 603 System.out.println("\tCaused by: " + 604 (Test1932.class.getPackage().equals(c.getClass().getPackage()) 605 ? c.toString() : c.getClass().toString())); 606 } 607 if (PRINT_FULL_STACK_TRACE) { 608 t.printStackTrace(); 609 } 610 } 611 SuppressContention(Monitors.LockController controller)612 public static AutoCloseable SuppressContention(Monitors.LockController controller) { 613 if (CONTENTION_SUPPRESSED != null) { 614 throw new IllegalStateException("Only one contention suppression is possible at a time."); 615 } 616 CONTENTION_SUPPRESSED = controller; 617 return () -> { 618 CONTENTION_SUPPRESSED = null; 619 }; 620 } 621 622 private static Monitors.LockController CONTENTION_SUPPRESSED = null; 623 handleMonitorEnter(Thread thd, Object lock)624 public static void handleMonitorEnter(Thread thd, Object lock) { 625 if (CONTENTION_SUPPRESSED != null && CONTENTION_SUPPRESSED.IsWorkerThread(thd)) { 626 return; 627 } 628 System.out.println(thd.getName() + " contended-LOCKING " + lock); 629 if (HANDLER != null) { 630 HANDLER.handleMonitorEnter(thd, lock); 631 } 632 } 633 handleMonitorEntered(Thread thd, Object lock)634 public static void handleMonitorEntered(Thread thd, Object lock) { 635 if (CONTENTION_SUPPRESSED != null && CONTENTION_SUPPRESSED.IsWorkerThread(thd)) { 636 return; 637 } 638 System.out.println(thd.getName() + " LOCKED " + lock); 639 if (HANDLER != null) { 640 HANDLER.handleMonitorEntered(thd, lock); 641 } 642 } handleMonitorWait(Thread thd, Object lock, long timeout)643 public static void handleMonitorWait(Thread thd, Object lock, long timeout) { 644 System.out.println(thd.getName() + " start-monitor-wait " + lock + " timeout: " + timeout); 645 if (HANDLER != null) { 646 HANDLER.handleMonitorWait(thd, lock, timeout); 647 } 648 } 649 handleMonitorWaited(Thread thd, Object lock, boolean timed_out)650 public static void handleMonitorWaited(Thread thd, Object lock, boolean timed_out) { 651 System.out.println(thd.getName() + " monitor-waited " + lock + " timed_out: " + timed_out); 652 if (HANDLER != null) { 653 HANDLER.handleMonitorWaited(thd, lock, timed_out); 654 } 655 } 656 } 657