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 * @author Mandy Chung 31 * 32 * @library ../../Thread 33 * @library /lib/testlibrary 34 * 35 * @build jdk.testlibrary.* 36 * @build ThreadMXBeanStateTest ThreadStateController 37 * @run main ThreadMXBeanStateTest 38 */ 39 40 import java.lang.management.ManagementFactory; 41 import java.lang.management.ThreadMXBean; 42 import java.lang.management.ThreadInfo; 43 import static java.lang.Thread.State.*; 44 45 public class ThreadMXBeanStateTest { 46 private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean(); 47 48 static class Lock { 49 private final String name; 50 Lock(String name) { 51 this.name = name; 52 } 53 @Override 54 public String toString() { 55 return name; 56 } 57 } 58 59 private static final Lock globalLock = new Lock("my lock"); 60 61 public static void main(String[] argv) throws Exception { 62 // Force thread state initialization now before the test 63 // verification begins. 64 Thread.currentThread().getState(); 65 ThreadStateController thread = new ThreadStateController("StateChanger", globalLock); 66 thread.setDaemon(true); 67 try { 68 // before myThread starts 69 thread.checkThreadState(NEW); 70 71 thread.start(); 72 thread.transitionTo(RUNNABLE); 73 thread.checkThreadState(RUNNABLE); 74 checkLockInfo(thread, RUNNABLE, null, null); 75 76 thread.suspend(); 77 ThreadStateController.pause(10); 78 thread.checkThreadState(RUNNABLE); 79 checkSuspendedThreadState(thread, RUNNABLE); 80 thread.resume(); 81 82 synchronized (globalLock) { 83 thread.transitionTo(BLOCKED); 84 thread.checkThreadState(BLOCKED); 85 checkLockInfo(thread, BLOCKED, 86 globalLock, Thread.currentThread()); 87 } 88 89 thread.transitionTo(WAITING); 90 thread.checkThreadState(WAITING); 91 checkLockInfo(thread, Thread.State.WAITING, 92 globalLock, null); 93 94 thread.transitionTo(TIMED_WAITING); 95 thread.checkThreadState(TIMED_WAITING); 96 checkLockInfo(thread, TIMED_WAITING, 97 globalLock, null); 98 99 100 thread.transitionToPark(true /* timed park */); 101 thread.checkThreadState(TIMED_WAITING); 102 checkLockInfo(thread, TIMED_WAITING, null, null); 103 104 thread.transitionToPark(false /* indefinite park */); 105 thread.checkThreadState(WAITING); 106 checkLockInfo(thread, WAITING, null, null); 107 108 thread.transitionToSleep(); 109 thread.checkThreadState(TIMED_WAITING); 110 checkLockInfo(thread, TIMED_WAITING, null, null); 111 112 thread.transitionTo(TERMINATED); 113 thread.checkThreadState(TERMINATED); 114 } finally { 115 try { 116 System.out.println(thread.getLog()); 117 } catch (InterruptedException e) { 118 e.printStackTrace(); 119 System.out.println("TEST FAILED: Unexpected exception."); 120 throw new RuntimeException(e); 121 } 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 }