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