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