ThreadStackTrace.java revision 0:37a05a11f281
1112918Sjeff/* 2112918Sjeff * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. 3112918Sjeff * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4112918Sjeff * 5112918Sjeff * This code is free software; you can redistribute it and/or modify it 6112918Sjeff * under the terms of the GNU General Public License version 2 only, as 7176763Sdavidxu * published by the Free Software Foundation. 8112918Sjeff * 9126000Smtm * This code is distributed in the hope that it will be useful, but WITHOUT 10126000Smtm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11112918Sjeff * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12112918Sjeff * version 2 for more details (a copy is included in the LICENSE file that 13113729Sjdp * accompanied this code). 14112918Sjeff * 15144518Sdavidxu * You should have received a copy of the GNU General Public License version 16112918Sjeff * 2 along with this work; if not, write to the Free Software Foundation, 17112918Sjeff * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18112918Sjeff * 19144921Sdavidxu * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20112918Sjeff * CA 95054 USA or visit www.sun.com if you need additional information or 21144518Sdavidxu * have any questions. 22112918Sjeff */ 23177494Sdavidxu 24144518Sdavidxu/* 25218414Sjkim * @test 26154130Sdavidxu * @bug 4530538 27112918Sjeff * @summary Basic unit test of ThreadInfo.getStackTrace() and 28112918Sjeff * ThreadInfo.getThreadState() 29144518Sdavidxu * @author Mandy Chung 30112918Sjeff * 31144518Sdavidxu * @run build Semaphore 32112918Sjeff * @run main ThreadStackTrace 33112918Sjeff */ 34112918Sjeff 35144518Sdavidxuimport java.lang.management.*; 36112918Sjeff 37112918Sjeffpublic class ThreadStackTrace { 38144518Sdavidxu private static ThreadMXBean mbean 39112918Sjeff = ManagementFactory.getThreadMXBean(); 40157112Sdavidxu private static boolean notified = false; 41112918Sjeff private static Object lockA = new Object(); 42112918Sjeff private static Object lockB = new Object(); 43112918Sjeff private static volatile boolean testFailed = false; 44112918Sjeff private static String[] blockedStack = {"run", "test", "A", "B", "C", "D"}; 45112918Sjeff private static int bsDepth = 6; 46112918Sjeff private static int methodB = 4; 47112918Sjeff private static String[] examinerStack = {"run", "examine1", "examine2"}; 48144518Sdavidxu private static int esDepth = 3; 49216641Sdavidxu private static int methodExamine1= 2; 50112918Sjeff 51112918Sjeff private static void goSleep(long ms) { 52112918Sjeff try { 53144518Sdavidxu Thread.sleep(ms); 54112918Sjeff } catch (InterruptedException e) { 55144518Sdavidxu e.printStackTrace(); 56144518Sdavidxu System.out.println("Unexpected exception."); 57144518Sdavidxu testFailed = true; 58112918Sjeff } 59 } 60 61 private static void checkNullThreadInfo(Thread t) throws Exception { 62 ThreadInfo ti = mbean.getThreadInfo(t.getId()); 63 if (ti != null) { 64 ThreadInfo info = 65 mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE); 66 System.out.println(INDENT + "TEST FAILED:"); 67 if (info != null) { 68 printStack(t, info.getStackTrace()); 69 System.out.println(INDENT + "Thread state: " + info.getThreadState()); 70 } 71 throw new RuntimeException("TEST FAILED: " + 72 "getThreadInfo() is expected to return null for " + t); 73 } 74 } 75 76 private static boolean trace = false; 77 public static void main(String args[]) throws Exception { 78 if (args.length > 0 && args[0].equals("trace")) { 79 trace = true; 80 } 81 82 Examiner examiner = new Examiner("Examiner"); 83 BlockedThread blocked = new BlockedThread("BlockedThread"); 84 examiner.setThread(blocked); 85 86 checkNullThreadInfo(examiner); 87 checkNullThreadInfo(blocked); 88 89 // Start the threads and check them in Blocked and Waiting states 90 examiner.start(); 91 92 // block until examiner begins doing its real work 93 examiner.waitForStarted(); 94 95 System.out.println("Checking stack trace for the examiner thread " + 96 "is waiting to begin."); 97 98 // The Examiner should be waiting to be notified by the BlockedThread 99 checkThreadState(examiner, Thread.State.WAITING); 100 101 // Check that the stack is returned correctly for a new thread 102 checkStack(examiner, examinerStack, esDepth); 103 104 System.out.println("Now starting the blocked thread"); 105 blocked.start(); 106 107 try { 108 examiner.join(); 109 blocked.join(); 110 } catch (InterruptedException e) { 111 e.printStackTrace(); 112 System.out.println("Unexpected exception."); 113 testFailed = true; 114 } 115 116 // Check that the stack is returned correctly for a terminated thread 117 checkNullThreadInfo(examiner); 118 checkNullThreadInfo(blocked); 119 120 if (testFailed) 121 throw new RuntimeException("TEST FAILED."); 122 123 System.out.println("Test passed."); 124 } 125 126 private static String INDENT = " "; 127 private static void printStack(Thread t, StackTraceElement[] stack) { 128 System.out.println(INDENT + t + 129 " stack: (length = " + stack.length + ")"); 130 if (t != null) { 131 for (int j = 0; j < stack.length; j++) { 132 System.out.println(INDENT + stack[j]); 133 } 134 System.out.println(); 135 } 136 } 137 138 private static void checkThreadState(Thread thread, Thread.State s) 139 throws Exception { 140 141 ThreadInfo ti = mbean.getThreadInfo(thread.getId()); 142 if (ti.getThreadState() != s) { 143 ThreadInfo info = 144 mbean.getThreadInfo(thread.getId(), Integer.MAX_VALUE); 145 System.out.println(INDENT + "TEST FAILED:"); 146 printStack(thread, info.getStackTrace()); 147 System.out.println(INDENT + "Thread state: " + info.getThreadState()); 148 149 throw new RuntimeException("TEST FAILED: " + 150 "Thread state for " + thread + " returns " + ti.getThreadState() + 151 ". Expected to be " + s); 152 } 153 } 154 155 private static void checkThreadState(Thread thread, 156 Thread.State s1, Thread.State s2) 157 throws Exception { 158 159 ThreadInfo ti = mbean.getThreadInfo(thread.getId()); 160 if (ti.getThreadState() != s1 && ti.getThreadState() != s2) { 161 throw new RuntimeException("TEST FAILED: " + 162 "Thread state for " + thread + " returns " + ti.getThreadState() + 163 ". Expected to be " + s1 + " or " + s2); 164 } 165 } 166 167 private static void checkStack(Thread t, String[] expectedStack, 168 int depth) throws Exception { 169 ThreadInfo ti = mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE); 170 StackTraceElement[] stack = ti.getStackTrace(); 171 172 if (trace) { 173 printStack(t, stack); 174 } 175 int frame = stack.length - 1; 176 for (int i = 0; i < depth; i++) { 177 if (! stack[frame].getMethodName().equals(expectedStack[i])) { 178 throw new RuntimeException("TEST FAILED: " + 179 "Expected " + expectedStack[i] + " in frame " + frame + 180 " but got " + stack[frame].getMethodName()); 181 } 182 frame--; 183 } 184 } 185 186 static class BlockedThread extends Thread { 187 private Semaphore handshake = new Semaphore(); 188 189 BlockedThread(String name) { 190 super(name); 191 } 192 boolean hasWaitersForBlocked() { 193 return (handshake.getWaiterCount() > 0); 194 } 195 196 void waitUntilBlocked() { 197 handshake.semaP(); 198 199 // give a chance for the examiner thread to really wait 200 goSleep(20); 201 } 202 203 void waitUntilLockAReleased() { 204 handshake.semaP(); 205 206 // give a chance for the examiner thread to really wait 207 goSleep(50); 208 } 209 210 private void notifyWaiter() { 211 // wait until the examiner waits on the semaphore 212 while (handshake.getWaiterCount() == 0) { 213 goSleep(20); 214 } 215 handshake.semaV(); 216 } 217 218 private void test() { 219 A(); 220 } 221 private void A() { 222 B(); 223 } 224 private void B() { 225 C(); 226 227 // notify the examiner about to block on lockB 228 notifyWaiter(); 229 230 synchronized (lockB) { 231 }; 232 } 233 private void C() { 234 D(); 235 } 236 private void D() { 237 // Notify that examiner about to enter lockA 238 notifyWaiter(); 239 240 synchronized (lockA) { 241 notified = false; 242 while (!notified) { 243 try { 244 // notify the examiner about to release lockA 245 notifyWaiter(); 246 // Wait and let examiner thread check the mbean 247 lockA.wait(); 248 } catch (InterruptedException e) { 249 e.printStackTrace(); 250 System.out.println("Unexpected exception."); 251 testFailed = true; 252 } 253 } 254 System.out.println("BlockedThread notified"); 255 } 256 } 257 258 public void run() { 259 test(); 260 } // run() 261 } // BlockedThread 262 263 static class Examiner extends Thread { 264 private static BlockedThread blockedThread; 265 private Semaphore handshake = new Semaphore(); 266 267 Examiner(String name) { 268 super(name); 269 } 270 271 public void setThread(BlockedThread thread) { 272 blockedThread = thread; 273 } 274 275 public synchronized void waitForStarted() { 276 // wait until the examiner is about to block 277 handshake.semaP(); 278 279 // wait until the examiner is waiting for blockedThread's notification 280 while (!blockedThread.hasWaitersForBlocked()) { 281 goSleep(50); 282 } 283 // give a chance for the examiner thread to really wait 284 goSleep(20); 285 } 286 287 private Thread itself; 288 private void examine1() { 289 synchronized (lockB) { 290 examine2(); 291 try { 292 System.out.println("Checking examiner's its own stack trace"); 293 checkThreadState(itself, Thread.State.RUNNABLE); 294 checkStack(itself, examinerStack, methodExamine1); 295 296 // wait until blockedThread is blocked on lockB 297 blockedThread.waitUntilBlocked(); 298 299 System.out.println("Checking stack trace for " + 300 "BlockedThread - should be blocked on lockB."); 301 checkThreadState(blockedThread, Thread.State.BLOCKED); 302 checkStack(blockedThread, blockedStack, methodB); 303 } catch (Exception e) { 304 e.printStackTrace(); 305 System.out.println("Unexpected exception."); 306 testFailed = true; 307 } 308 } 309 } 310 311 private void examine2() { 312 synchronized (lockA) { 313 // wait until main thread gets signalled of the semaphore 314 while (handshake.getWaiterCount() == 0) { 315 goSleep(20); 316 } 317 318 handshake.semaV(); // notify the main thread 319 try { 320 // Wait until BlockedThread is about to block on lockA 321 blockedThread.waitUntilBlocked(); 322 323 System.out.println("Checking examiner's its own stack trace"); 324 checkThreadState(itself, Thread.State.RUNNABLE); 325 checkStack(itself, examinerStack, esDepth); 326 327 System.out.println("Checking stack trace for " + 328 "BlockedThread - should be blocked on lockA."); 329 checkThreadState(blockedThread, Thread.State.BLOCKED); 330 checkStack(blockedThread, blockedStack, bsDepth); 331 332 } catch (Exception e) { 333 e.printStackTrace(); 334 System.out.println("Unexpected exception."); 335 testFailed = true; 336 } 337 } 338 339 // release lockA and let BlockedThread to get the lock 340 // and wait on lockA 341 blockedThread.waitUntilLockAReleased(); 342 343 synchronized (lockA) { 344 try { 345 System.out.println("Checking stack trace for " + 346 "BlockedThread - should be waiting on lockA."); 347 checkThreadState(blockedThread, Thread.State.WAITING); 348 checkStack(blockedThread, blockedStack, bsDepth); 349 350 // Let the blocked thread go 351 notified = true; 352 lockA.notify(); 353 } catch (Exception e) { 354 e.printStackTrace(); 355 System.out.println("Unexpected exception."); 356 testFailed = true; 357 } 358 } 359 // give some time for BlockedThread to proceed 360 goSleep(50); 361 } // examine2() 362 363 public void run() { 364 itself = Thread.currentThread(); 365 examine1(); 366 } // run() 367 } // Examiner 368} 369