/* * Copyright 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 4919105 * @summary Generified basic unit test of Thread.getAllStackTraces() * @author Mandy Chung */ import java.util.*; public class GenerifyStackTraces { private static Object go = new Object(); private static Object dumpObj = new Object(); private static String[] methodNames = {"run", "A", "B", "C", "Done"}; private static int DONE_DEPTH = 5; private static boolean testFailed = false; private static Thread one; private static boolean trace = false; public static void main(String[] args) throws Exception { if (args.length > 0 && args[0].equals("trace")) { trace = true; } one = new ThreadOne(); one.start(); Thread dt = new DumpThread(); dt.setDaemon(true); dt.start(); if (testFailed) { throw new RuntimeException("Test Failed."); } } static class DumpThread extends Thread { public void run() { int depth = 2; while (true) { // At each iterator, wait until ThreadOne blocks // to wait for thread dump. // Then dump stack trace and notify ThreadOne to continue. try { sleep(2000); dumpStacks(depth); depth++; finishDump(); } catch (Exception e) { e.printStackTrace(); testFailed = true; } } } } static class ThreadOne extends Thread { public void run() { A(); } private void A() { waitForDump(); B(); } private void B() { waitForDump(); C(); } private void C() { waitForDump(); Done(); } private void Done() { waitForDump(); // Get stack trace of current thread StackTraceElement[] stack = getStackTrace(); try { checkStack(this, stack, DONE_DEPTH); } catch (Exception e) { e.printStackTrace(); testFailed = true; } } } static private void waitForDump() { synchronized(go) { try { go.wait(); } catch (Exception e) { throw new RuntimeException("Unexpected exception" + e); } } } static private void finishDump() { synchronized(go) { try { go.notifyAll(); } catch (Exception e) { throw new RuntimeException("Unexpected exception" + e); } } } public static void dumpStacks(int depth) throws Exception { // Get stack trace of another thread StackTraceElement[] stack = one.getStackTrace(); checkStack(one, stack, depth); // Get stack traces of all Threads for (Map.Entry entry : Thread.getAllStackTraces().entrySet()) { Thread t = entry.getKey(); stack = entry.getValue(); if (t == null || stack == null) { throw new RuntimeException("Null thread or stacktrace returned"); } if (t == one) { checkStack(t, stack, depth); } } } private static void checkStack(Thread t, StackTraceElement[] stack, int depth) throws Exception { if (trace) { printStack(t, stack); } int frame = stack.length - 1; for (int i = 0; i < depth; i++) { if (! stack[frame].getMethodName().equals(methodNames[i])) { throw new RuntimeException("Expected " + methodNames[i] + " in frame " + frame + " but got " + stack[frame].getMethodName()); } frame--; } } private static void printStack(Thread t, StackTraceElement[] stack) { System.out.println(t + " stack: (length = " + stack.length + ")"); if (t != null) { for (int j = 0; j < stack.length; j++) { System.out.println(stack[j]); } System.out.println(); } } }