1 /*
2  * Copyright (c) 2005, 2013, 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  * @test
26  * @bug     5086470 6358247
27  * @summary Basic Test for ThreadMXBean.dumpAllThreads(false, true)
28  *          and getThreadInfo of customized JSR-166 synchronizers.
29  * @author  Mandy Chung
30  *
31  * @build Barrier
32  * @build ThreadDump
33  * @run main/othervm MyOwnSynchronizer
34  */
35 
36 import java.lang.management.*;
37 import java.util.*;
38 import java.util.concurrent.locks.*;
39 import java.util.concurrent.TimeUnit;
40 import java.io.*;
41 
42 public class MyOwnSynchronizer {
43     static ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
44     static Mutex mutex = new Mutex();
45     static MyThread thread = new MyThread();
main(String[] argv)46     public static void main(String[] argv) throws Exception {
47         if (!mbean.isSynchronizerUsageSupported()) {
48             System.out.println("Monitoring of synchronizer usage not supported");
49             return;
50         }
51 
52         thread.setDaemon(true);
53         thread.start();
54 
55         // wait until myThread acquires mutex
56         while (!mutex.isLocked()) {
57            try {
58                Thread.sleep(100);
59            } catch (InterruptedException e) {
60                throw new RuntimeException(e);
61            }
62         }
63 
64         ThreadDump.threadDump();
65         // Test dumpAllThreads with locked synchronizers
66         ThreadInfo[] tinfos = mbean.dumpAllThreads(false, true);
67         for (ThreadInfo ti : tinfos) {
68            MonitorInfo[] monitors = ti.getLockedMonitors();
69            if (monitors.length != 0) {
70                throw new RuntimeException("Name: " + ti.getThreadName() +
71                    " has non-empty locked monitors = " + monitors.length);
72            }
73            LockInfo[] syncs = ti.getLockedSynchronizers();
74            if (ti.getThreadId() == thread.getId()) {
75                thread.checkLockedSyncs(ti, syncs);
76            }
77         }
78 
79         // Test getThreadInfo with locked synchronizers
80         tinfos = mbean.getThreadInfo(new long[] {thread.getId()}, false, true);
81         if (tinfos.length != 1) {
82             throw new RuntimeException("getThreadInfo() returns " +
83                 tinfos.length + " ThreadInfo objects. Expected 0.");
84         }
85         ThreadInfo ti = tinfos[0];
86         if (ti.getLockedMonitors().length != 0) {
87             throw new RuntimeException("Name: " + ti.getThreadName() +
88                " has non-empty locked monitors = " +
89                ti.getLockedMonitors().length);
90         }
91         thread.checkLockedSyncs(ti, ti.getLockedSynchronizers());
92 
93         System.out.println("Test passed");
94     }
95 
96     static class Mutex implements Lock, java.io.Serializable {
97 
98         // Our internal helper class
99         class Sync extends AbstractQueuedSynchronizer {
100             // Report whether in locked state
isHeldExclusively()101             protected boolean isHeldExclusively() {
102                 return getState() == 1;
103             }
104 
105             // Acquire the lock if state is zero
tryAcquire(int acquires)106             public boolean tryAcquire(int acquires) {
107                 assert acquires == 1; // Otherwise unused
108                 if (compareAndSetState(0, 1)) {
109                   setExclusiveOwnerThread(Thread.currentThread());
110                   return true;
111                 }
112                 return false;
113             }
114 
115             // Release the lock by setting state to zero
tryRelease(int releases)116             protected boolean tryRelease(int releases) {
117                 assert releases == 1; // Otherwise unused
118                 if (getState() == 0) throw new IllegalMonitorStateException();
119                 setExclusiveOwnerThread(null);
120                 setState(0);
121                 return true;
122             }
123 
124             // Provide a Condition
newCondition()125             Condition newCondition() { return new ConditionObject(); }
126 
127             // Deserialize properly
readObject(ObjectInputStream s)128             private void readObject(ObjectInputStream s)
129                 throws IOException, ClassNotFoundException {
130                 s.defaultReadObject();
131                 setState(0); // reset to unlocked state
132             }
133         }
134 
135         // The sync object does all the hard work. We just forward to it.
136         private final Sync sync = new Sync();
137 
lock()138         public void lock()                { sync.acquire(1); }
tryLock()139         public boolean tryLock()          { return sync.tryAcquire(1); }
unlock()140         public void unlock()              { sync.release(1); }
newCondition()141         public Condition newCondition()   { return sync.newCondition(); }
isLocked()142         public boolean isLocked()         { return sync.isHeldExclusively(); }
hasQueuedThreads()143         public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
lockInterruptibly()144         public void lockInterruptibly() throws InterruptedException {
145             sync.acquireInterruptibly(1);
146         }
tryLock(long timeout, TimeUnit unit)147         public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
148             return sync.tryAcquireNanos(1, unit.toNanos(timeout));
149         }
150 
getSync()151         public AbstractOwnableSynchronizer getSync() { return sync; }
152     }
153 
154     static class MyThread extends Thread {
MyThread()155         public MyThread() {
156             super("MyThread");
157         }
run()158         public void run() {
159             mutex.lock();
160             Object o = new Object();
161             synchronized(o) {
162                 try {
163                     o.wait();
164                 } catch (InterruptedException e) {
165                     throw new RuntimeException(e);
166                 }
167             }
168         }
169         int OWNED_SYNCS = 1;
checkLockedSyncs(ThreadInfo info, LockInfo[] syncs)170         void checkLockedSyncs(ThreadInfo info, LockInfo[] syncs) {
171             if (!getName().equals(info.getThreadName())) {
172                 throw new RuntimeException("Name: " + info.getThreadName() +
173                     " not matched. Expected: " + getName());
174             }
175 
176             if (syncs.length != OWNED_SYNCS) {
177                 throw new RuntimeException("Number of locked syncs = " +
178                     syncs.length +
179                     " not matched. Expected: " + OWNED_SYNCS);
180             }
181             AbstractOwnableSynchronizer s = mutex.getSync();
182             String lockName = s.getClass().getName();
183             int hcode = System.identityHashCode(s);
184             if (!lockName.equals(syncs[0].getClassName())) {
185                 throw new RuntimeException("LockInfo : " + syncs[0] +
186                     " class name not matched. Expected: " + lockName);
187             }
188             if (hcode != syncs[0].getIdentityHashCode()) {
189                 throw new RuntimeException("LockInfo: " + syncs[0] +
190                     " IdentityHashCode not matched. Expected: " + hcode);
191             }
192 
193         }
194     }
195 }
196