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