blob: dbe002e26b2304f92201f320f955001f030cf45f [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any 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 Semaphore
32 * @run main ThreadStackTrace
33 */
34
35import java.lang.management.*;
36
37public class ThreadStackTrace {
38 private static ThreadMXBean mbean
39 = ManagementFactory.getThreadMXBean();
40 private static boolean notified = false;
41 private static Object lockA = new Object();
42 private static Object lockB = new Object();
43 private static volatile boolean testFailed = false;
44 private static String[] blockedStack = {"run", "test", "A", "B", "C", "D"};
45 private static int bsDepth = 6;
46 private static int methodB = 4;
47 private static String[] examinerStack = {"run", "examine1", "examine2"};
48 private static int esDepth = 3;
49 private static int methodExamine1= 2;
50
51 private static void goSleep(long ms) {
52 try {
53 Thread.sleep(ms);
54 } catch (InterruptedException e) {
55 e.printStackTrace();
56 System.out.println("Unexpected exception.");
57 testFailed = true;
58 }
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}