ThreadStackTrace.java revision 11884:b45c81ca8671
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 4530538 27 * @summary Basic unit test of ThreadInfo.getStackTrace() and 28 * ThreadInfo.getThreadState() 29 * @author Mandy Chung 30 * 31 * @modules java.management 32 * @run build Utils 33 * @run main ThreadStackTrace 34 */ 35 36import java.lang.management.*; 37import java.util.concurrent.Phaser; 38 39public class ThreadStackTrace { 40 private static final ThreadMXBean mbean 41 = ManagementFactory.getThreadMXBean(); 42 private static boolean notified = false; 43 private static final Object lockA = new Object(); 44 private static final Object lockB = new Object(); 45 private static volatile boolean testFailed = false; 46 private static final String[] blockedStack = {"run", "test", "A", "B", "C", "D"}; 47 private static final int bsDepth = 6; 48 private static final int methodB = 4; 49 private static final String[] examinerStack = {"run", "examine1", "examine2"}; 50 private static final int esDepth = 3; 51 private static final int methodExamine1= 2; 52 53 private static void checkNullThreadInfo(Thread t) throws Exception { 54 ThreadInfo ti = mbean.getThreadInfo(t.getId()); 55 if (ti != null) { 56 ThreadInfo info = 57 mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE); 58 System.out.println(INDENT + "TEST FAILED:"); 59 if (info != null) { 60 printStack(t, info.getStackTrace()); 61 System.out.println(INDENT + "Thread state: " + info.getThreadState()); 62 } 63 throw new RuntimeException("TEST FAILED: " + 64 "getThreadInfo() is expected to return null for " + t); 65 } 66 } 67 68 private static boolean trace = false; 69 public static void main(String args[]) throws Exception { 70 if (args.length > 0 && args[0].equals("trace")) { 71 trace = true; 72 } 73 74 final Phaser p = new Phaser(2); 75 76 Examiner examiner = new Examiner("Examiner", p); 77 BlockedThread blocked = new BlockedThread("BlockedThread", p); 78 examiner.setThread(blocked); 79 80 checkNullThreadInfo(examiner); 81 checkNullThreadInfo(blocked); 82 83 // Start the threads and check them in Blocked and Waiting states 84 examiner.start(); 85 86 // #1 - block until examiner begins doing its real work 87 p.arriveAndAwaitAdvance(); 88 89 System.out.println("Checking stack trace for the examiner thread " + 90 "is waiting to begin."); 91 92 // The Examiner should be waiting to be notified by the BlockedThread 93 Utils.checkThreadState(examiner, Thread.State.WAITING); 94 95 // Check that the stack is returned correctly for a new thread 96 checkStack(examiner, examinerStack, esDepth); 97 98 System.out.println("Now starting the blocked thread"); 99 blocked.start(); 100 101 try { 102 examiner.join(); 103 blocked.join(); 104 } catch (InterruptedException e) { 105 e.printStackTrace(); 106 System.out.println("Unexpected exception."); 107 testFailed = true; 108 } 109 110 // Check that the stack is returned correctly for a terminated thread 111 checkNullThreadInfo(examiner); 112 checkNullThreadInfo(blocked); 113 114 if (testFailed) 115 throw new RuntimeException("TEST FAILED."); 116 117 System.out.println("Test passed."); 118 } 119 120 private static String INDENT = " "; 121 private static void printStack(Thread t, StackTraceElement[] stack) { 122 System.out.println(INDENT + t + 123 " stack: (length = " + stack.length + ")"); 124 if (t != null) { 125 for (int j = 0; j < stack.length; j++) { 126 System.out.println(INDENT + stack[j]); 127 } 128 System.out.println(); 129 } 130 } 131 132 private static void checkStack(Thread t, String[] expectedStack, 133 int depth) throws Exception { 134 ThreadInfo ti = mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE); 135 StackTraceElement[] stack = ti.getStackTrace(); 136 137 if (trace) { 138 printStack(t, stack); 139 } 140 int frame = stack.length - 1; 141 for (int i = 0; i < depth; i++) { 142 if (! stack[frame].getMethodName().equals(expectedStack[i])) { 143 throw new RuntimeException("TEST FAILED: " + 144 "Expected " + expectedStack[i] + " in frame " + frame + 145 " but got " + stack[frame].getMethodName()); 146 } 147 frame--; 148 } 149 } 150 151 static class BlockedThread extends Thread { 152 private final Phaser phaser; 153 154 BlockedThread(String name, Phaser phaser) { 155 super(name); 156 this.phaser = phaser; 157 } 158 159 private void test() { 160 A(); 161 } 162 private void A() { 163 B(); 164 } 165 private void B() { 166 C(); 167 168 // #4 - notify the examiner about to block on lockB 169 phaser.arriveAndAwaitAdvance(); 170 171 synchronized (lockB) {}; 172 } 173 private void C() { 174 D(); 175 } 176 private void D() { 177 // #2 - Notify that examiner about to enter lockA 178 phaser.arriveAndAwaitAdvance(); 179 180 synchronized (lockA) { 181 notified = false; 182 while (!notified) { 183 try { 184 // #3 - notify the examiner about to release lockA 185 phaser.arriveAndAwaitAdvance(); 186 // Wait and let examiner thread check the mbean 187 lockA.wait(); 188 } catch (InterruptedException e) { 189 e.printStackTrace(); 190 System.out.println("Unexpected exception."); 191 testFailed = true; 192 } 193 } 194 System.out.println("BlockedThread notified"); 195 } 196 } 197 198 @Override 199 public void run() { 200 test(); 201 } // run() 202 } // BlockedThread 203 204 static class Examiner extends Thread { 205 private static BlockedThread blockedThread; 206 private final Phaser phaser; 207 208 Examiner(String name, Phaser phaser) { 209 super(name); 210 this.phaser = phaser; 211 } 212 213 public void setThread(BlockedThread thread) { 214 blockedThread = thread; 215 } 216 217 private Thread itself; 218 private void examine1() { 219 synchronized (lockB) { 220 examine2(); 221 try { 222 System.out.println("Checking examiner's its own stack trace"); 223 Utils.checkThreadState(itself, Thread.State.RUNNABLE); 224 checkStack(itself, examinerStack, methodExamine1); 225 226 // #4 - wait until blockedThread is blocked on lockB 227 phaser.arriveAndAwaitAdvance(); 228 Utils.waitForThreadState(blockedThread, State.BLOCKED); 229 230 System.out.println("Checking stack trace for " + 231 "BlockedThread - should be blocked on lockB."); 232 Utils.checkThreadState(blockedThread, Thread.State.BLOCKED); 233 checkStack(blockedThread, blockedStack, methodB); 234 } catch (Exception e) { 235 e.printStackTrace(); 236 System.out.println("Unexpected exception."); 237 testFailed = true; 238 } 239 } 240 } 241 242 private void examine2() { 243 synchronized (lockA) { 244 // #1 - examiner ready to do the real work 245 phaser.arriveAndAwaitAdvance(); 246 try { 247 // #2 - Wait until BlockedThread is about to block on lockA 248 phaser.arriveAndAwaitAdvance(); 249 Utils.waitForThreadState(blockedThread, State.BLOCKED); 250 251 System.out.println("Checking examiner's its own stack trace"); 252 Utils.checkThreadState(itself, Thread.State.RUNNABLE); 253 checkStack(itself, examinerStack, esDepth); 254 255 System.out.println("Checking stack trace for " + 256 "BlockedThread - should be blocked on lockA."); 257 Utils.checkThreadState(blockedThread, Thread.State.BLOCKED); 258 checkStack(blockedThread, blockedStack, bsDepth); 259 260 } catch (Exception e) { 261 e.printStackTrace(); 262 System.out.println("Unexpected exception."); 263 testFailed = true; 264 } 265 } 266 267 // #3 - release lockA and let BlockedThread to get the lock 268 // and wait on lockA 269 phaser.arriveAndAwaitAdvance(); 270 Utils.waitForThreadState(blockedThread, State.WAITING); 271 272 synchronized (lockA) { 273 try { 274 System.out.println("Checking stack trace for " + 275 "BlockedThread - should be waiting on lockA."); 276 Utils.checkThreadState(blockedThread, Thread.State.WAITING); 277 checkStack(blockedThread, blockedStack, bsDepth); 278 279 // Let the blocked thread go 280 notified = true; 281 lockA.notify(); 282 } catch (Exception e) { 283 e.printStackTrace(); 284 System.out.println("Unexpected exception."); 285 testFailed = true; 286 } 287 } 288 // give some time for BlockedThread to proceed 289 Utils.goSleep(50); 290 } // examine2() 291 292 @Override 293 public void run() { 294 itself = Thread.currentThread(); 295 examine1(); 296 } // run() 297 } // Examiner 298} 299