1 /* 2 * Copyright (c) 2005, 2018, 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 7193302 8048215 27 * @summary Test type conversion when invoking ThreadMXBean.dumpAllThreads 28 * through proxy. 29 * @author Mandy Chung 30 * 31 * @run main ThreadMXBeanProxy 32 */ 33 34 import static java.lang.management.ManagementFactory.*; 35 import java.lang.management.*; 36 import java.util.*; 37 import java.util.concurrent.locks.*; 38 import java.util.concurrent.TimeUnit; 39 import java.io.*; 40 import javax.management.*; 41 42 public class ThreadMXBeanProxy { 43 private static MBeanServer server = 44 ManagementFactory.getPlatformMBeanServer(); 45 private static ThreadMXBean mbean; 46 static Mutex mutex = new Mutex(); 47 static Object lock = new Object(); 48 static Object waiter = new Object(); 49 static MyThread thread = new MyThread(); 50 public static void main(String[] argv) throws Exception { 51 mbean = newPlatformMXBeanProxy(server, 52 THREAD_MXBEAN_NAME, 53 ThreadMXBean.class); 54 55 if (!mbean.isSynchronizerUsageSupported()) { 56 System.out.println("Monitoring of synchronizer usage not supported"); 57 return; 58 } 59 60 thread.setDaemon(true); 61 thread.start(); 62 63 // wait until myThread acquires mutex and lock owner is set. 64 while (!(mutex.isLocked() && mutex.getLockOwner() == thread)) { 65 try { 66 Thread.sleep(100); 67 } catch (InterruptedException e) { 68 throw new RuntimeException(e); 69 } 70 } 71 72 // 'thread' holds the mutex, which means it must also have the monitor of 73 // 'waiter' at least until it does the wait(). So we acquire the monitor of 74 // 'waiter' here, which ensures that 'thread' must be in wait() 75 synchronized(waiter) { 76 } 77 78 long[] ids = new long[] { thread.getId() }; 79 80 // validate the local access 81 ThreadInfo[] infos = getThreadMXBean().getThreadInfo(ids, true, true); 82 if (infos.length != 1) { 83 throw new RuntimeException("Returned ThreadInfo[] of length=" + 84 infos.length + ". Expected to be 1."); 85 } 86 thread.checkThreadInfo(infos[0]); 87 88 // validate the remote access 89 infos = mbean.getThreadInfo(ids, true, true); 90 if (infos.length != 1) { 91 throw new RuntimeException("Returned ThreadInfo[] of length=" + 92 infos.length + ". Expected to be 1."); 93 } 94 thread.checkThreadInfo(infos[0]); 95 96 boolean found = false; 97 infos = mbean.dumpAllThreads(true, true); 98 for (ThreadInfo ti : infos) { 99 if (ti.getThreadId() == thread.getId()) { 100 thread.checkThreadInfo(ti); 101 found = true; 102 } 103 } 104 105 if (!found) { 106 throw new RuntimeException("No ThreadInfo found for MyThread"); 107 } 108 109 System.out.println("Test passed"); 110 } 111 112 static class MyThread extends Thread { 113 public MyThread() { 114 super("MyThread"); 115 } 116 public void run() { 117 synchronized (lock) { 118 synchronized(waiter) { 119 mutex.lock(); 120 try { 121 waiter.wait(); 122 } catch (InterruptedException e) { 123 throw new RuntimeException(e); 124 } 125 } 126 } 127 } 128 129 int OWNED_MONITORS = 1; 130 int OWNED_SYNCS = 1; 131 void checkThreadInfo(ThreadInfo info) { 132 if (!getName().equals(info.getThreadName())) { 133 throw new RuntimeException("Name: " + info.getThreadName() + 134 " not matched. Expected: " + getName()); 135 } 136 137 MonitorInfo[] monitors = info.getLockedMonitors(); 138 if (monitors.length != OWNED_MONITORS) { 139 throw new RuntimeException("Number of locked monitors = " + 140 monitors.length + 141 " not matched. Expected: " + OWNED_MONITORS); 142 } 143 MonitorInfo m = monitors[0]; 144 StackTraceElement ste = m.getLockedStackFrame(); 145 int depth = m.getLockedStackDepth(); 146 StackTraceElement[] stacktrace = info.getStackTrace(); 147 if (!ste.equals(stacktrace[depth])) { 148 System.out.println("LockedStackFrame:- " + ste); 149 System.out.println("StackTrace at " + depth + " :-" + 150 stacktrace[depth]); 151 throw new RuntimeException("LockedStackFrame does not match " + 152 "stack frame in ThreadInfo.getStackTrace"); 153 } 154 155 String className = lock.getClass().getName(); 156 int hcode = System.identityHashCode(lock); 157 if (!className.equals(m.getClassName()) || 158 hcode != m.getIdentityHashCode() || 159 !m.getLockedStackFrame().getMethodName().equals("run")) { 160 System.out.println(info); 161 throw new RuntimeException("MonitorInfo " + m + 162 " doesn't match."); 163 } 164 165 LockInfo[] syncs = info.getLockedSynchronizers(); 166 if (syncs.length != OWNED_SYNCS) { 167 throw new RuntimeException("Number of locked syncs = " + 168 syncs.length + " not matched. Expected: " + OWNED_SYNCS); 169 } 170 AbstractOwnableSynchronizer s = mutex.getSync(); 171 String lockName = s.getClass().getName(); 172 hcode = System.identityHashCode(s); 173 if (!lockName.equals(syncs[0].getClassName())) { 174 throw new RuntimeException("LockInfo : " + syncs[0] + 175 " class name not matched. Expected: " + lockName); 176 } 177 if (hcode != syncs[0].getIdentityHashCode()) { 178 throw new RuntimeException("LockInfo: " + syncs[0] + 179 " IdentityHashCode not matched. Expected: " + hcode); 180 } 181 LockInfo li = info.getLockInfo(); 182 if (li == null) { 183 throw new RuntimeException("Expected non-null LockInfo"); 184 } 185 } 186 } 187 static class Mutex implements Lock, java.io.Serializable { 188 189 // Our internal helper class 190 class Sync extends AbstractQueuedSynchronizer { 191 // Report whether in locked state 192 protected boolean isHeldExclusively() { 193 return getState() == 1; 194 } 195 196 // Acquire the lock if state is zero 197 public boolean tryAcquire(int acquires) { 198 assert acquires == 1; // Otherwise unused 199 if (compareAndSetState(0, 1)) { 200 setExclusiveOwnerThread(Thread.currentThread()); 201 return true; 202 } 203 return false; 204 } 205 206 // Release the lock by setting state to zero 207 protected boolean tryRelease(int releases) { 208 assert releases == 1; // Otherwise unused 209 if (getState() == 0) throw new IllegalMonitorStateException(); 210 setExclusiveOwnerThread(null); 211 setState(0); 212 return true; 213 } 214 215 // Provide a Condition 216 Condition newCondition() { return new ConditionObject(); } 217 218 // Deserialize properly 219 private void readObject(ObjectInputStream s) 220 throws IOException, ClassNotFoundException { 221 s.defaultReadObject(); 222 setState(0); // reset to unlocked state 223 } 224 225 protected Thread getLockOwner() { 226 return getExclusiveOwnerThread(); 227 } 228 } 229 230 // The sync object does all the hard work. We just forward to it. 231 private final Sync sync = new Sync(); 232 233 public void lock() { sync.acquire(1); } 234 public boolean tryLock() { return sync.tryAcquire(1); } 235 public void unlock() { sync.release(1); } 236 public Condition newCondition() { return sync.newCondition(); } 237 public boolean isLocked() { return sync.isHeldExclusively(); } 238 public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } 239 public void lockInterruptibly() throws InterruptedException { 240 sync.acquireInterruptibly(1); 241 } 242 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { 243 return sync.tryAcquireNanos(1, unit.toNanos(timeout)); 244 } 245 246 public Thread getLockOwner() { return sync.getLockOwner(); } 247 248 public AbstractOwnableSynchronizer getSync() { return sync; } 249 } 250 }