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 import java.util.Arrays;
21 
22 public class Test1930 {
23   public static final int NUM_RETRY = 100;
testSingleThread()24   private static void testSingleThread() {
25     Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testSingleThread");
26     executeLocked(() -> { printMonitorUsage(lk); }, lk);
27   }
testSingleThreadNative()28   private static void testSingleThreadNative() {
29     Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testSingleThread");
30     executeLockedNative(() -> { printMonitorUsage(lk); }, lk);
31   }
32 
testLockedTwice()33   private static void testLockedTwice() {
34     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testLockedTwice");
35     executeLocked(() -> { executeLocked(() -> { printMonitorUsage(lk); }, lk); }, lk);
36   }
37 
testLockedTwiceNJ()38   private static void testLockedTwiceNJ() {
39     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testLockedTwiceNJ");
40     executeLockedNative(() -> { executeLockedNative(() -> { printMonitorUsage(lk); }, lk); }, lk);
41   }
42 
testLockedTwiceJN()43   private static void testLockedTwiceJN() {
44     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testLockedTwiceJN");
45     executeLockedNative(() -> { executeLockedNative(() -> { printMonitorUsage(lk); }, lk); }, lk);
46   }
47 
testLockedTwiceNative()48   private static void testLockedTwiceNative() {
49     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testLockedTwiceNative");
50     executeLockedNative(() -> { executeLockedNative(() -> { printMonitorUsage(lk); }, lk); }, lk);
51   }
52 
53   public final static class ThreadSignaler {
54     public volatile boolean signal = false;
55   }
56 
testLockWait()57   private static void testLockWait() throws Exception {
58     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testLockWait");
59     final Semaphore sem = new Semaphore(0);
60     final Thread t = new Thread(() -> {
61       sem.release();
62       synchronized (lk) {
63         printMonitorUsage(lk);
64       }
65     }, "Test1930 Thread - testLockWait");
66     synchronized (lk) {
67       t.start();
68       // Wait for the other thread to actually start.
69       sem.acquire();
70       // Wait for the other thread to go to sleep trying to get the mutex. This might take a (short)
71       // time since we try spinning first for better performance.
72       boolean found_wait = false;
73       for (long i = 0; i < NUM_RETRY; i++) {
74         if (Arrays.asList(Monitors.getObjectMonitorUsage(lk).waiters).contains(t)) {
75           found_wait = true;
76           break;
77         } else {
78           Thread.sleep(500);
79           Thread.yield();
80         }
81       }
82       if (!found_wait) {
83         System.out.println("other thread doesn't seem to be waiting.");
84       }
85       printMonitorUsage(lk);
86     }
87     t.join();
88     printMonitorUsage(lk);
89   }
90 
testNotifyWait()91   private static void testNotifyWait() throws Exception {
92     final Monitors.NamedLock lk = new Monitors.NamedLock("Test1930 - testNotifyWait");
93     final Semaphore sem = new Semaphore(0);
94     Thread t = new Thread(() -> {
95       synchronized (lk) {
96         printMonitorUsage(lk);
97         sem.release();
98         try {
99           lk.DoWait();
100         } catch (Exception e) {
101           throw new Error("Error waiting!", e);
102         }
103         printMonitorUsage(lk);
104       }
105     }, "Test1930 Thread - testLockWait");
106     t.start();
107     sem.acquire();
108     synchronized (lk) {
109       printMonitorUsage(lk);
110       lk.DoNotifyAll();
111     }
112     t.join();
113     printMonitorUsage(lk);
114   }
115 
run()116   public static void run() throws Exception {
117     // Single threaded tests.
118     System.out.println("Running with single thread.");
119     testSingleThread();
120     System.out.println("Running with single thread in native.");
121     testSingleThreadNative();
122     System.out.println("Lock twice");
123     testLockedTwice();
124     System.out.println("Lock twice native");
125     testLockedTwiceNative();
126     System.out.println("Lock twice Java then native");
127     testLockedTwiceJN();
128     System.out.println("Lock twice native then Java");
129     testLockedTwiceNJ();
130 
131     // Mutli threaded tests.
132     System.out.println("lock with wait");
133     testLockWait();
134     System.out.println("Wait for notify.");
135     testNotifyWait();
136   }
137 
printPreLock(Object lock)138   public static void printPreLock(Object lock) {
139     System.out.println(String.format("Pre-lock[%s]: %s",
140           Thread.currentThread().getName(), Monitors.getObjectMonitorUsage(lock)));
141   }
142 
executeLocked(Runnable r, Object lock)143   public static void executeLocked(Runnable r, Object lock) {
144     printPreLock(lock);
145     synchronized (lock) {
146       r.run();
147     }
148   }
149 
executeLockedNative(Runnable r, Object m)150   public native static void executeLockedNative(Runnable r, Object m);
printMonitorUsage(Object m)151   public static void printMonitorUsage(Object m) {
152     System.out.println(String.format("Thread[%s]: %s",
153           Thread.currentThread().getName(), Monitors.getObjectMonitorUsage(m)));
154   }
155 }
156