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