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