287 lines · 9.0 KB · Java
RawDownload
/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.example.debug.tty; import com.sun.jdi.ThreadReference;import com.sun.jdi.ThreadGroupReference;import com.sun.jdi.IncompatibleThreadStateException;import com.sun.jdi.StackFrame;import java.util.List;import java.util.ArrayList;import java.util.Collections; class ThreadInfo {    // This is a list of all known ThreadInfo objects. It survives    // ThreadInfo.invalidateAll, unlike the other static fields below.    private static List<ThreadInfo> threads = Collections.synchronizedList(new ArrayList<ThreadInfo>());    private static boolean gotInitialThreads = false;     private static ThreadInfo current = null;    private static ThreadGroupReference group = null;     private final ThreadReference thread;    private int currentFrameIndex = 0;     private ThreadInfo(ThreadReference thread) {        this.thread = thread;        if (thread == null) {            MessageOutput.fatalError("Internal error: null ThreadInfo created");        }    }     private static void initThreads() {        if (!gotInitialThreads) {            for (ThreadReference thread : Env.vm().allThreads()) {                threads.add(new ThreadInfo(thread));            }            gotInitialThreads = true;        }    }     static void addThread(ThreadReference thread) {        synchronized (threads) {            initThreads();            ThreadInfo ti = new ThreadInfo(thread);            // Guard against duplicates. Duplicates can happen during            // initialization when a particular thread might be added both            // by a thread start event and by the initial call to threads()            if (getThreadInfo(thread) == null) {                threads.add(ti);            }        }    }     static void removeThread(ThreadReference thread) {        if (thread.equals(ThreadInfo.current)) {            // Current thread has died.             // Be careful getting the thread name. If its death happens            // as part of VM termination, it may be too late to get the            // information, and an exception will be thrown.            String currentThreadName;            try {               currentThreadName = "\"" + thread.name() + "\"";            } catch (Exception e) {               currentThreadName = "";            }             setCurrentThread(null);             MessageOutput.println();            MessageOutput.println("Current thread died. Execution continuing...",                                  currentThreadName);        }        threads.remove(getThreadInfo(thread));    }     static List<ThreadInfo> threads() {        synchronized(threads) {            initThreads();            // Make a copy to allow iteration without synchronization            return new ArrayList<ThreadInfo>(threads);        }    }     static void invalidateAll() {        current = null;        group = null;        synchronized (threads) {            for (ThreadInfo ti : threads()) {                ti.invalidate();            }        }    }     static void setThreadGroup(ThreadGroupReference tg) {        group = tg;    }     static void setCurrentThread(ThreadReference tr) {        if (tr == null) {            setCurrentThreadInfo(null);        } else {            ThreadInfo tinfo = getThreadInfo(tr);            setCurrentThreadInfo(tinfo);        }    }     static void setCurrentThreadInfo(ThreadInfo tinfo) {        current = tinfo;        if (current != null) {            current.invalidate();        }    }     /**     * Get the current ThreadInfo object.     *     * @return the ThreadInfo for the current thread.     */    static ThreadInfo getCurrentThreadInfo() {        return current;    }     /**     * Get the thread from this ThreadInfo object.     *     * @return the Thread wrapped by this ThreadInfo.     */    ThreadReference getThread() {        return thread;    }     static ThreadGroupReference group() {        if (group == null) {            // Current thread group defaults to the first top level            // thread group.            setThreadGroup(Env.vm().topLevelThreadGroups().get(0));        }        return group;    }     static ThreadInfo getThreadInfo(long id) {        ThreadInfo retInfo = null;         synchronized (threads) {            for (ThreadInfo ti : threads()) {                if (ti.thread.uniqueID() == id) {                   retInfo = ti;                   break;                }            }        }        return retInfo;    }     static ThreadInfo getThreadInfo(ThreadReference tr) {        return getThreadInfo(tr.uniqueID());    }     static ThreadInfo getThreadInfo(String idToken) {        ThreadInfo tinfo = null;        if (idToken.startsWith("t@")) {            idToken = idToken.substring(2);        }        try {            long threadId = Long.decode(idToken).longValue();            tinfo = getThreadInfo(threadId);        } catch (NumberFormatException e) {            tinfo = null;        }        return tinfo;    }     /**     * Get the thread stack frames.     *     * @return a <code>List</code> of the stack frames.     */    List<StackFrame> getStack() throws IncompatibleThreadStateException {        return thread.frames();    }     /**     * Get the current stackframe.     *     * @return the current stackframe.     */    StackFrame getCurrentFrame() throws IncompatibleThreadStateException {        if (thread.frameCount() == 0) {            return null;        }        return thread.frame(currentFrameIndex);    }     /**     * Invalidate the current stackframe index.     */    void invalidate() {        currentFrameIndex = 0;    }     /* Throw IncompatibleThreadStateException if not suspended */    private void assureSuspended() throws IncompatibleThreadStateException {        if (!thread.isSuspended()) {            throw new IncompatibleThreadStateException();        }    }     /**     * Get the current stackframe index.     *     * @return the number of the current stackframe.  Frame zero is the     * closest to the current program counter     */    int getCurrentFrameIndex() {        return currentFrameIndex;    }     /**     * Set the current stackframe to a specific frame.     *     * @param nFrame    the number of the desired stackframe.  Frame zero is the     * closest to the current program counter     * @exception IllegalAccessError when the thread isn't     * suspended or waiting at a breakpoint     * @exception ArrayIndexOutOfBoundsException when the     * requested frame is beyond the stack boundary     */    void setCurrentFrameIndex(int nFrame) throws IncompatibleThreadStateException {        assureSuspended();        if ((nFrame < 0) || (nFrame >= thread.frameCount())) {            throw new ArrayIndexOutOfBoundsException();        }        currentFrameIndex = nFrame;    }     /**     * Change the current stackframe to be one or more frames higher     * (as in, away from the current program counter).     *     * @param nFrames   the number of stackframes     * @exception IllegalAccessError when the thread isn't     * suspended or waiting at a breakpoint     * @exception ArrayIndexOutOfBoundsException when the     * requested frame is beyond the stack boundary     */    void up(int nFrames) throws IncompatibleThreadStateException {        setCurrentFrameIndex(currentFrameIndex + nFrames);    }     /**     * Change the current stackframe to be one or more frames lower     * (as in, toward the current program counter).     *     * @param nFrames   the number of stackframes     * @exception IllegalAccessError when the thread isn't     * suspended or waiting at a breakpoint     * @exception ArrayIndexOutOfBoundsException when the     * requested frame is beyond the stack boundary     */    void down(int nFrames) throws IncompatibleThreadStateException {        setCurrentFrameIndex(currentFrameIndex - nFrames);    } }