--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/management/ThreadMXBean/ThreadStackTrace.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4530538
+ * @summary Basic unit test of ThreadInfo.getStackTrace() and
+ * ThreadInfo.getThreadState()
+ * @author Mandy Chung
+ *
+ * @run build Semaphore
+ * @run main ThreadStackTrace
+ */
+
+import java.lang.management.*;
+
+public class ThreadStackTrace {
+ private static ThreadMXBean mbean
+ = ManagementFactory.getThreadMXBean();
+ private static boolean notified = false;
+ private static Object lockA = new Object();
+ private static Object lockB = new Object();
+ private static volatile boolean testFailed = false;
+ private static String[] blockedStack = {"run", "test", "A", "B", "C", "D"};
+ private static int bsDepth = 6;
+ private static int methodB = 4;
+ private static String[] examinerStack = {"run", "examine1", "examine2"};
+ private static int esDepth = 3;
+ private static int methodExamine1= 2;
+
+ private static void goSleep(long ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+ }
+
+ private static void checkNullThreadInfo(Thread t) throws Exception {
+ ThreadInfo ti = mbean.getThreadInfo(t.getId());
+ if (ti != null) {
+ ThreadInfo info =
+ mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE);
+ System.out.println(INDENT + "TEST FAILED:");
+ if (info != null) {
+ printStack(t, info.getStackTrace());
+ System.out.println(INDENT + "Thread state: " + info.getThreadState());
+ }
+ throw new RuntimeException("TEST FAILED: " +
+ "getThreadInfo() is expected to return null for " + t);
+ }
+ }
+
+ private static boolean trace = false;
+ public static void main(String args[]) throws Exception {
+ if (args.length > 0 && args[0].equals("trace")) {
+ trace = true;
+ }
+
+ Examiner examiner = new Examiner("Examiner");
+ BlockedThread blocked = new BlockedThread("BlockedThread");
+ examiner.setThread(blocked);
+
+ checkNullThreadInfo(examiner);
+ checkNullThreadInfo(blocked);
+
+ // Start the threads and check them in Blocked and Waiting states
+ examiner.start();
+
+ // block until examiner begins doing its real work
+ examiner.waitForStarted();
+
+ System.out.println("Checking stack trace for the examiner thread " +
+ "is waiting to begin.");
+
+ // The Examiner should be waiting to be notified by the BlockedThread
+ checkThreadState(examiner, Thread.State.WAITING);
+
+ // Check that the stack is returned correctly for a new thread
+ checkStack(examiner, examinerStack, esDepth);
+
+ System.out.println("Now starting the blocked thread");
+ blocked.start();
+
+ try {
+ examiner.join();
+ blocked.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+
+ // Check that the stack is returned correctly for a terminated thread
+ checkNullThreadInfo(examiner);
+ checkNullThreadInfo(blocked);
+
+ if (testFailed)
+ throw new RuntimeException("TEST FAILED.");
+
+ System.out.println("Test passed.");
+ }
+
+ private static String INDENT = " ";
+ private static void printStack(Thread t, StackTraceElement[] stack) {
+ System.out.println(INDENT + t +
+ " stack: (length = " + stack.length + ")");
+ if (t != null) {
+ for (int j = 0; j < stack.length; j++) {
+ System.out.println(INDENT + stack[j]);
+ }
+ System.out.println();
+ }
+ }
+
+ private static void checkThreadState(Thread thread, Thread.State s)
+ throws Exception {
+
+ ThreadInfo ti = mbean.getThreadInfo(thread.getId());
+ if (ti.getThreadState() != s) {
+ ThreadInfo info =
+ mbean.getThreadInfo(thread.getId(), Integer.MAX_VALUE);
+ System.out.println(INDENT + "TEST FAILED:");
+ printStack(thread, info.getStackTrace());
+ System.out.println(INDENT + "Thread state: " + info.getThreadState());
+
+ throw new RuntimeException("TEST FAILED: " +
+ "Thread state for " + thread + " returns " + ti.getThreadState() +
+ ". Expected to be " + s);
+ }
+ }
+
+ private static void checkThreadState(Thread thread,
+ Thread.State s1, Thread.State s2)
+ throws Exception {
+
+ ThreadInfo ti = mbean.getThreadInfo(thread.getId());
+ if (ti.getThreadState() != s1 && ti.getThreadState() != s2) {
+ throw new RuntimeException("TEST FAILED: " +
+ "Thread state for " + thread + " returns " + ti.getThreadState() +
+ ". Expected to be " + s1 + " or " + s2);
+ }
+ }
+
+ private static void checkStack(Thread t, String[] expectedStack,
+ int depth) throws Exception {
+ ThreadInfo ti = mbean.getThreadInfo(t.getId(), Integer.MAX_VALUE);
+ StackTraceElement[] stack = ti.getStackTrace();
+
+ if (trace) {
+ printStack(t, stack);
+ }
+ int frame = stack.length - 1;
+ for (int i = 0; i < depth; i++) {
+ if (! stack[frame].getMethodName().equals(expectedStack[i])) {
+ throw new RuntimeException("TEST FAILED: " +
+ "Expected " + expectedStack[i] + " in frame " + frame +
+ " but got " + stack[frame].getMethodName());
+ }
+ frame--;
+ }
+ }
+
+ static class BlockedThread extends Thread {
+ private Semaphore handshake = new Semaphore();
+
+ BlockedThread(String name) {
+ super(name);
+ }
+ boolean hasWaitersForBlocked() {
+ return (handshake.getWaiterCount() > 0);
+ }
+
+ void waitUntilBlocked() {
+ handshake.semaP();
+
+ // give a chance for the examiner thread to really wait
+ goSleep(20);
+ }
+
+ void waitUntilLockAReleased() {
+ handshake.semaP();
+
+ // give a chance for the examiner thread to really wait
+ goSleep(50);
+ }
+
+ private void notifyWaiter() {
+ // wait until the examiner waits on the semaphore
+ while (handshake.getWaiterCount() == 0) {
+ goSleep(20);
+ }
+ handshake.semaV();
+ }
+
+ private void test() {
+ A();
+ }
+ private void A() {
+ B();
+ }
+ private void B() {
+ C();
+
+ // notify the examiner about to block on lockB
+ notifyWaiter();
+
+ synchronized (lockB) {
+ };
+ }
+ private void C() {
+ D();
+ }
+ private void D() {
+ // Notify that examiner about to enter lockA
+ notifyWaiter();
+
+ synchronized (lockA) {
+ notified = false;
+ while (!notified) {
+ try {
+ // notify the examiner about to release lockA
+ notifyWaiter();
+ // Wait and let examiner thread check the mbean
+ lockA.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+ }
+ System.out.println("BlockedThread notified");
+ }
+ }
+
+ public void run() {
+ test();
+ } // run()
+ } // BlockedThread
+
+ static class Examiner extends Thread {
+ private static BlockedThread blockedThread;
+ private Semaphore handshake = new Semaphore();
+
+ Examiner(String name) {
+ super(name);
+ }
+
+ public void setThread(BlockedThread thread) {
+ blockedThread = thread;
+ }
+
+ public synchronized void waitForStarted() {
+ // wait until the examiner is about to block
+ handshake.semaP();
+
+ // wait until the examiner is waiting for blockedThread's notification
+ while (!blockedThread.hasWaitersForBlocked()) {
+ goSleep(50);
+ }
+ // give a chance for the examiner thread to really wait
+ goSleep(20);
+ }
+
+ private Thread itself;
+ private void examine1() {
+ synchronized (lockB) {
+ examine2();
+ try {
+ System.out.println("Checking examiner's its own stack trace");
+ checkThreadState(itself, Thread.State.RUNNABLE);
+ checkStack(itself, examinerStack, methodExamine1);
+
+ // wait until blockedThread is blocked on lockB
+ blockedThread.waitUntilBlocked();
+
+ System.out.println("Checking stack trace for " +
+ "BlockedThread - should be blocked on lockB.");
+ checkThreadState(blockedThread, Thread.State.BLOCKED);
+ checkStack(blockedThread, blockedStack, methodB);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+ }
+ }
+
+ private void examine2() {
+ synchronized (lockA) {
+ // wait until main thread gets signalled of the semaphore
+ while (handshake.getWaiterCount() == 0) {
+ goSleep(20);
+ }
+
+ handshake.semaV(); // notify the main thread
+ try {
+ // Wait until BlockedThread is about to block on lockA
+ blockedThread.waitUntilBlocked();
+
+ System.out.println("Checking examiner's its own stack trace");
+ checkThreadState(itself, Thread.State.RUNNABLE);
+ checkStack(itself, examinerStack, esDepth);
+
+ System.out.println("Checking stack trace for " +
+ "BlockedThread - should be blocked on lockA.");
+ checkThreadState(blockedThread, Thread.State.BLOCKED);
+ checkStack(blockedThread, blockedStack, bsDepth);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+ }
+
+ // release lockA and let BlockedThread to get the lock
+ // and wait on lockA
+ blockedThread.waitUntilLockAReleased();
+
+ synchronized (lockA) {
+ try {
+ System.out.println("Checking stack trace for " +
+ "BlockedThread - should be waiting on lockA.");
+ checkThreadState(blockedThread, Thread.State.WAITING);
+ checkStack(blockedThread, blockedStack, bsDepth);
+
+ // Let the blocked thread go
+ notified = true;
+ lockA.notify();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("Unexpected exception.");
+ testFailed = true;
+ }
+ }
+ // give some time for BlockedThread to proceed
+ goSleep(50);
+ } // examine2()
+
+ public void run() {
+ itself = Thread.currentThread();
+ examine1();
+ } // run()
+ } // Examiner
+}