1 /*
   2  * Copyright (c) 2003, 2006, 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     4967283 5080203 8022208
  27  * @summary Basic unit test of thread states returned by
  28  *          ThreadMXBean.getThreadInfo.getThreadState().
  29  *          It also tests lock information returned by ThreadInfo.
  30  *
  31  * @author  Mandy Chung
  32  *
  33  * @library ../../Thread
  34  * @build ThreadMXBeanStateTest ThreadStateController
  35  * @run main ThreadMXBeanStateTest
  36  */
  37 
  38 import java.lang.management.ManagementFactory;
  39 import java.lang.management.ThreadMXBean;
  40 import java.lang.management.ThreadInfo;
  41 import static java.lang.Thread.State.*;
  42 
  43 public class ThreadMXBeanStateTest {
  44     private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean();
  45 
  46     static class Lock {
  47         private String name;
  48         Lock(String name) {
  49             this.name = name;
  50         }
  51         public String toString() {
  52             return name;
  53         }
  54     }
  55     private static Lock globalLock = new Lock("my lock");
  56 
  57     public static void main(String[] argv) throws Exception {
  58         // Force thread state initialization now before the test
  59         // verification begins.
  60         Thread.currentThread().getState();
  61         ThreadStateController thread = new ThreadStateController("StateChanger", globalLock);
  62         thread.setDaemon(true);
  63 
  64         // before myThread starts
  65         thread.checkThreadState(NEW);
  66 
  67         thread.start();
  68         thread.transitionTo(RUNNABLE);
  69         thread.checkThreadState(RUNNABLE);
  70         checkLockInfo(thread, RUNNABLE, null, null);
  71 
  72         thread.suspend();
  73         thread.goSleep(10);
  74         thread.checkThreadState(RUNNABLE);
  75         checkSuspendedThreadState(thread, RUNNABLE);
  76         thread.resume();
  77 
  78         synchronized (globalLock) {
  79             thread.transitionTo(BLOCKED);
  80             thread.checkThreadState(BLOCKED);
  81             checkLockInfo(thread, BLOCKED,
  82                           globalLock, Thread.currentThread());
  83         }
  84 
  85         thread.transitionTo(WAITING);
  86         thread.checkThreadState(WAITING);
  87         checkLockInfo(thread, Thread.State.WAITING,
  88                       globalLock, null);
  89 
  90         thread.transitionTo(TIMED_WAITING);
  91         thread.checkThreadState(TIMED_WAITING);
  92         checkLockInfo(thread, TIMED_WAITING,
  93                       globalLock, null);
  94 
  95 
  96         thread.transitionToPark(true /* timed park */);
  97         thread.checkThreadState(TIMED_WAITING);
  98         checkLockInfo(thread, TIMED_WAITING, null, null);
  99 
 100         thread.transitionToPark(false /* indefinite park */);
 101         thread.checkThreadState(WAITING);
 102         checkLockInfo(thread, WAITING, null, null);
 103 
 104         thread.transitionToSleep();
 105         thread.checkThreadState(TIMED_WAITING);
 106         checkLockInfo(thread, TIMED_WAITING, null, null);
 107 
 108         thread.transitionTo(TERMINATED);
 109         thread.checkThreadState(TERMINATED);
 110 
 111         try {
 112             thread.join();
 113         } catch (InterruptedException e) {
 114             e.printStackTrace();
 115             System.out.println("TEST FAILED: Unexpected exception.");
 116             throw new RuntimeException(e);
 117         }
 118         System.out.println("Test passed.");
 119     }
 120 
 121     private static void checkSuspendedThreadState(Thread t, Thread.State state) {
 122         ThreadInfo info = tm.getThreadInfo(t.getId());
 123         if (info == null) {
 124             throw new RuntimeException(t.getName() +
 125                " expected to have ThreadInfo " +
 126                " but got null.");
 127         }
 128 
 129         if (info.getThreadState() != state) {
 130             throw new RuntimeException(t.getName() + " expected to be in " +
 131                 state + " state but got " + info.getThreadState());
 132         }
 133 
 134         if (!info.isSuspended()) {
 135             throw new RuntimeException(t.getName() + " expected to be suspended " +
 136                 " but isSuspended() returns " + info.isSuspended());
 137         }
 138     }
 139 
 140     private static String getLockName(Object lock) {
 141         if (lock == null) return null;
 142 
 143         return lock.getClass().getName() + '@' +
 144             Integer.toHexString(System.identityHashCode(lock));
 145     }
 146 
 147     private static void checkLockInfo(Thread t, Thread.State state, Object lock, Thread owner) {
 148         ThreadInfo info = tm.getThreadInfo(t.getId());
 149         if (info == null) {
 150             throw new RuntimeException(t.getName() +
 151                " expected to have ThreadInfo " +
 152                " but got null.");
 153         }
 154 
 155         if (info.getThreadState() != state) {
 156             throw new RuntimeException(t.getName() + " expected to be in " +
 157                 state + " state but got " + info.getThreadState());
 158         }
 159 
 160         if (lock == null && info.getLockName() != null) {
 161             throw new RuntimeException(t.getName() +
 162                 " expected not to be blocked on any lock" +
 163                 " but got " + info.getLockName());
 164         }
 165         String expectedLockName = getLockName(lock);
 166         if (lock != null && info.getLockName() == null) {
 167             throw new RuntimeException(t.getName() +
 168                 " expected to be blocked on lock [" + expectedLockName +
 169                 "] but got null.");
 170         }
 171 
 172         if (lock != null && !expectedLockName.equals(info.getLockName())) {
 173             throw new RuntimeException(t.getName() +
 174                 " expected to be blocked on lock [" + expectedLockName +
 175                 "] but got [" + info.getLockName() + "].");
 176         }
 177 
 178         if (owner == null && info.getLockOwnerName() != null) {
 179             throw new RuntimeException("Lock owner is expected " +
 180                 " to be null but got " + info.getLockOwnerName());
 181         }
 182 
 183         if (owner != null && info.getLockOwnerName() == null) {
 184             throw new RuntimeException("Lock owner is expected to be " +
 185                 owner.getName() +
 186                 " but got null.");
 187         }
 188         if (owner != null && !info.getLockOwnerName().equals(owner.getName())) {
 189             throw new RuntimeException("Lock owner is expected to be " +
 190                 owner.getName() +
 191                 " but got " + owner.getName());
 192         }
 193         if (owner == null && info.getLockOwnerId() != -1) {
 194             throw new RuntimeException("Lock owner is expected " +
 195                 " to be -1 but got " + info.getLockOwnerId());
 196         }
 197 
 198         if (owner != null && info.getLockOwnerId() <= 0) {
 199             throw new RuntimeException("Lock owner is expected to be " +
 200                 owner.getName() + "(id = " + owner.getId() +
 201                 ") but got " + info.getLockOwnerId());
 202         }
 203         if (owner != null && info.getLockOwnerId() != owner.getId()) {
 204             throw new RuntimeException("Lock owner is expected to be " +
 205                 owner.getName() + "(id = " + owner.getId() +
 206                 ") but got " + info.getLockOwnerId());
 207         }
 208         if (info.isSuspended()) {
 209             throw new RuntimeException(t.getName() +
 210                 " isSuspended() returns " + info.isSuspended());
 211         }
 212     }
 213 }