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