History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/gui/ThreadTreeTool.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/gui/ThreadTreeTool.java+346−0
@@ -0,0 +1,346 @@
1+/*
2+ * Copyright (c) 1998, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.tools.example.debug.gui;
27+
28+import java.util.*;
29+import java.util.List; // Must import explicitly due to conflict with javax.awt.List
30+
31+import javax.swing.*;
32+import javax.swing.tree.*;
33+import java.awt.*;
34+import java.awt.event.*;
35+
36+import com.sun.jdi.*;
37+import com.sun.tools.example.debug.event.*;
38+import com.sun.tools.example.debug.bdi.*;
39+
40+//### Bug: If the name of a thread is changed via Thread.setName(), the
41+//### thread tree view does not reflect this. The name of the thread at
42+//### the time it is created is used throughout its lifetime.
43+
44+public class ThreadTreeTool extends JPanel {
45+
46+ private static final long serialVersionUID = 4168599992853038878L;
47+
48+ private Environment env;
49+
50+ private ExecutionManager runtime;
51+ private SourceManager sourceManager;
52+ private ClassManager classManager;
53+
54+ private JTree tree;
55+ private DefaultTreeModel treeModel;
56+ private ThreadTreeNode root;
57+ private SearchPath sourcePath;
58+
59+ private CommandInterpreter interpreter;
60+
61+ private static String HEADING = "THREADS";
62+
63+ public ThreadTreeTool(Environment env) {
64+
65+ super(new BorderLayout());
66+
67+ this.env = env;
68+ this.runtime = env.getExecutionManager();
69+ this.sourceManager = env.getSourceManager();
70+
71+ this.interpreter = new CommandInterpreter(env);
72+
73+ root = createThreadTree(HEADING);
74+ treeModel = new DefaultTreeModel(root);
75+
76+ // Create a tree that allows one selection at a time.
77+
78+ tree = new JTree(treeModel);
79+ tree.setSelectionModel(new SingleLeafTreeSelectionModel());
80+
81+ MouseListener ml = new MouseAdapter() {
82+ @Override
83+ public void mouseClicked(MouseEvent e) {
84+ int selRow = tree.getRowForLocation(e.getX(), e.getY());
85+ TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
86+ if(selRow != -1) {
87+ if(e.getClickCount() == 1) {
88+ ThreadTreeNode node =
89+ (ThreadTreeNode)selPath.getLastPathComponent();
90+ // If user clicks on leaf, select it, and issue 'thread' command.
91+ if (node.isLeaf()) {
92+ tree.setSelectionPath(selPath);
93+ interpreter.executeCommand("thread " +
94+ node.getThreadId() +
95+ " (\"" +
96+ node.getName() + "\")");
97+ }
98+ }
99+ }
100+ }
101+ };
102+
103+ tree.addMouseListener(ml);
104+
105+ JScrollPane treeView = new JScrollPane(tree);
106+ add(treeView);
107+
108+ // Create listener.
109+ ThreadTreeToolListener listener = new ThreadTreeToolListener();
110+ runtime.addJDIListener(listener);
111+ runtime.addSessionListener(listener);
112+
113+ //### remove listeners on exit!
114+ }
115+
116+ HashMap<ThreadReference, List<String>> threadTable = new HashMap<ThreadReference, List<String>>();
117+
118+ private List<String> threadPath(ThreadReference thread) {
119+ // May exit abnormally if VM disconnects.
120+ List<String> l = new ArrayList<String>();
121+ l.add(0, thread.name());
122+ ThreadGroupReference group = thread.threadGroup();
123+ while (group != null) {
124+ l.add(0, group.name());
125+ group = group.parent();
126+ }
127+ return l;
128+ }
129+
130+ private class ThreadTreeToolListener extends JDIAdapter
131+ implements JDIListener, SessionListener {
132+
133+ // SessionListener
134+
135+ @Override
136+ public void sessionStart(EventObject e) {
137+ try {
138+ for (ThreadReference thread : runtime.allThreads()) {
139+ root.addThread(thread);
140+ }
141+ } catch (VMDisconnectedException ee) {
142+ // VM went away unexpectedly.
143+ } catch (NoSessionException ee) {
144+ // Ignore. Should not happen.
145+ }
146+ }
147+
148+ @Override
149+ public void sessionInterrupt(EventObject e) {}
150+ @Override
151+ public void sessionContinue(EventObject e) {}
152+
153+
154+ // JDIListener
155+
156+ @Override
157+ public void threadStart(ThreadStartEventSet e) {
158+ root.addThread(e.getThread());
159+ }
160+
161+ @Override
162+ public void threadDeath(ThreadDeathEventSet e) {
163+ root.removeThread(e.getThread());
164+ }
165+
166+ @Override
167+ public void vmDisconnect(VMDisconnectEventSet e) {
168+ // Clear the contents of this view.
169+ root = createThreadTree(HEADING);
170+ treeModel = new DefaultTreeModel(root);
171+ tree.setModel(treeModel);
172+ threadTable = new HashMap<ThreadReference, List<String>>();
173+ }
174+
175+ }
176+
177+ ThreadTreeNode createThreadTree(String label) {
178+ return new ThreadTreeNode(label, null);
179+ }
180+
181+ class ThreadTreeNode extends DefaultMutableTreeNode {
182+
183+ String name;
184+ ThreadReference thread; // null if thread group
185+ long uid;
186+ String description;
187+
188+ ThreadTreeNode(String name, ThreadReference thread) {
189+ if (name == null) {
190+ name = "<unnamed>";
191+ }
192+ this.name = name;
193+ this.thread = thread;
194+ if (thread == null) {
195+ this.uid = -1;
196+ this.description = name;
197+ } else {
198+ this.uid = thread.uniqueID();
199+ this.description = name + " (t@" + Long.toHexString(uid) + ")";
200+ }
201+ }
202+
203+ @Override
204+ public String toString() {
205+ return description;
206+ }
207+
208+ public String getName() {
209+ return name;
210+ }
211+
212+ public ThreadReference getThread() {
213+ return thread;
214+ }
215+
216+ public String getThreadId() {
217+ return "t@" + Long.toHexString(uid);
218+ }
219+
220+ private boolean isThreadGroup() {
221+ return (thread == null);
222+ }
223+
224+ @Override
225+ public boolean isLeaf() {
226+ return !isThreadGroup();
227+ }
228+
229+ public void addThread(ThreadReference thread) {
230+ // This can fail if the VM disconnects.
231+ // It is important to do all necessary JDI calls
232+ // before modifying the tree, so we don't abort
233+ // midway through!
234+ if (threadTable.get(thread) == null) {
235+ // Add thread only if not already present.
236+ try {
237+ List<String> path = threadPath(thread);
238+ // May not get here due to exception.
239+ // If we get here, we are committed.
240+ // We must not leave the tree partially updated.
241+ try {
242+ threadTable.put(thread, path);
243+ addThread(path, thread);
244+ } catch (Throwable tt) {
245+ //### Assertion failure.
246+ throw new RuntimeException("ThreadTree corrupted");
247+ }
248+ } catch (VMDisconnectedException ee) {
249+ // Ignore. Thread will not be added.
250+ }
251+ }
252+ }
253+
254+ private void addThread(List<String> threadPath, ThreadReference thread) {
255+ int size = threadPath.size();
256+ if (size == 0) {
257+ return;
258+ } else if (size == 1) {
259+ String name = threadPath.get(0);
260+ insertNode(name, thread);
261+ } else {
262+ String head = threadPath.get(0);
263+ List<String> tail = threadPath.subList(1, size);
264+ ThreadTreeNode child = insertNode(head, null);
265+ child.addThread(tail, thread);
266+ }
267+ }
268+
269+ private ThreadTreeNode insertNode(String name, ThreadReference thread) {
270+ for (int i = 0; i < getChildCount(); i++) {
271+ ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
272+ int cmp = name.compareTo(child.getName());
273+ if (cmp == 0 && thread == null) {
274+ // A like-named interior node already exists.
275+ return child;
276+ } else if (cmp < 0) {
277+ // Insert new node before the child.
278+ ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
279+ treeModel.insertNodeInto(newChild, this, i);
280+ return newChild;
281+ }
282+ }
283+ // Insert new node after last child.
284+ ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
285+ treeModel.insertNodeInto(newChild, this, getChildCount());
286+ return newChild;
287+ }
288+
289+ public void removeThread(ThreadReference thread) {
290+ List<String> threadPath = threadTable.get(thread);
291+ // Only remove thread if we recorded it in table.
292+ // Original add may have failed due to VM disconnect.
293+ if (threadPath != null) {
294+ removeThread(threadPath, thread);
295+ }
296+ }
297+
298+ private void removeThread(List<String> threadPath, ThreadReference thread) {
299+ int size = threadPath.size();
300+ if (size == 0) {
301+ return;
302+ } else if (size == 1) {
303+ String name = threadPath.get(0);
304+ ThreadTreeNode child = findLeafNode(thread, name);
305+ treeModel.removeNodeFromParent(child);
306+ } else {
307+ String head = threadPath.get(0);
308+ List<String> tail = threadPath.subList(1, size);
309+ ThreadTreeNode child = findInternalNode(head);
310+ child.removeThread(tail, thread);
311+ if (child.isThreadGroup() && child.getChildCount() < 1) {
312+ // Prune non-leaf nodes with no children.
313+ treeModel.removeNodeFromParent(child);
314+ }
315+ }
316+ }
317+
318+ private ThreadTreeNode findLeafNode(ThreadReference thread, String name) {
319+ for (int i = 0; i < getChildCount(); i++) {
320+ ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
321+ if (child.getThread() == thread) {
322+ if (!name.equals(child.getName())) {
323+ //### Assertion failure.
324+ throw new RuntimeException("name mismatch");
325+ }
326+ return child;
327+ }
328+ }
329+ //### Assertion failure.
330+ throw new RuntimeException("not found");
331+ }
332+
333+ private ThreadTreeNode findInternalNode(String name) {
334+ for (int i = 0; i < getChildCount(); i++) {
335+ ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
336+ if (name.equals(child.getName())) {
337+ return child;
338+ }
339+ }
340+ //### Assertion failure.
341+ throw new RuntimeException("not found");
342+ }
343+
344+ }
345+
346+}