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