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