comparison agent/src/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2000-2004 Sun Microsystems, Inc. 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.ui;
26
27 import java.awt.BorderLayout;
28 import java.awt.Dimension;
29
30 import java.awt.event.*;
31
32 import java.io.*;
33 import java.util.*;
34
35 import javax.swing.*;
36 import javax.swing.event.ListSelectionEvent;
37 import javax.swing.event.ListSelectionListener;
38 import javax.swing.table.*;
39
40 import sun.jvm.hotspot.debugger.*;
41 import sun.jvm.hotspot.runtime.*;
42
43 import sun.jvm.hotspot.ui.action.*;
44
45 import com.sun.java.swing.ui.*;
46 import com.sun.java.swing.action.*;
47
48 /**
49 * This panel contains a JTable which displays the list of Java
50 * threads as their native thread identifiers combined with their
51 * Java names. It allows selection and examination of any of the
52 * threads.
53 */
54 public class JavaThreadsPanel extends SAPanel implements ActionListener {
55 private JavaThreadsTableModel dataModel;
56 private StatusBar statusBar;
57 private JTable threadTable;
58 private java.util.List cachedThreads = new ArrayList();
59
60
61 /** Constructor assumes the threads panel is created while the VM is
62 suspended. Subsequent resume and suspend operations of the VM
63 will cause the threads panel to clear and fill itself back in,
64 respectively. */
65 public JavaThreadsPanel() {
66 VM.getVM().registerVMResumedObserver(new Observer() {
67 public void update(Observable o, Object data) {
68 decache();
69 }
70 });
71
72 VM.getVM().registerVMSuspendedObserver(new Observer() {
73 public void update(Observable o, Object data) {
74 cache();
75 }
76 });
77
78 cache();
79
80 setLayout(new BorderLayout());
81
82 dataModel = new JavaThreadsTableModel(cachedThreads);
83 statusBar = new StatusBar();
84
85 threadTable = new JTable(dataModel, new JavaThreadsColumnModel());
86 threadTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
87 threadTable.addMouseListener(new MouseAdapter() {
88 public void mouseClicked(MouseEvent evt) {
89 if (evt.getClickCount() == 2) {
90 // double clicking will display the oop inspector.
91 fireShowThreadOopInspector();
92 }
93 }
94 });
95
96 add(new JavaThreadsToolBar(statusBar), BorderLayout.NORTH);
97 add(new ThreadPanel(threadTable), BorderLayout.CENTER);
98 add(statusBar, BorderLayout.SOUTH);
99
100 registerActions();
101 }
102
103 /**
104 * A splitpane panel which contains the thread table and the Thread Info.
105 * the thread info is toggleable
106 */
107 private class ThreadPanel extends JPanel {
108
109 private JSplitPane splitPane;
110 private JTable threadTable;
111 private ThreadInfoPanel threadInfo;
112 private int dividerSize;
113 private int dividerLocation = -1;
114 private boolean actionsEnabled = false;
115
116 public ThreadPanel(JTable table) {
117 setLayout(new BorderLayout());
118 this.threadInfo = new ThreadInfoPanel();
119 this.threadTable = table;
120
121 splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
122 splitPane.setOneTouchExpandable(true);
123 splitPane.setTopComponent(new JScrollPane(table));
124
125 // Set the size of the divider to 0 but save it so it can be restored
126 dividerSize = splitPane.getDividerSize();
127 splitPane.setDividerSize(0);
128
129 add(splitPane, BorderLayout.CENTER);
130
131 // Register an ItemListener on the LogViewerAction which toggles
132 // the apearance of the ThreadInfoPanel
133 ActionManager manager = HSDBActionManager.getInstance();
134 StateChangeAction action = manager.getStateChangeAction(ThreadInfoAction.VALUE_COMMAND);
135 if (action != null) {
136 action.setItemListener(new ItemListener() {
137 public void itemStateChanged(ItemEvent evt) {
138 if (evt.getStateChange() == ItemEvent.SELECTED) {
139 showOutputPane();
140 } else {
141 hideOutputPane();
142 }
143 }
144 });
145 }
146
147 // A listener is added to listen to changes in row selection
148 // and changes the contents of the ThreadInfoPanel.
149 ListSelectionModel selModel = table.getSelectionModel();
150 selModel.addListSelectionListener(new ListSelectionListener() {
151 public void valueChanged(ListSelectionEvent evt) {
152 if (evt.getValueIsAdjusting() == false) {
153 setActionsEnabled(true);
154 if (isInfoVisible()) {
155 showCurrentThreadInfo();
156 }
157 }
158 }
159 });
160 }
161
162 /**
163 * Returns a flag to indicate if the thread info is visible
164 */
165 private boolean isInfoVisible() {
166 return (splitPane.getBottomComponent() != null);
167 }
168
169 private void showOutputPane() {
170 if (splitPane.getBottomComponent() == null) {
171 splitPane.setBottomComponent(threadInfo);
172
173 if (dividerLocation == -1) {
174 // Calculate the divider location from the pref size.
175 Dimension pSize = this.getSize();
176 dividerLocation = pSize.height / 2;
177 }
178
179 splitPane.setDividerSize(dividerSize);
180 splitPane.setDividerLocation(dividerLocation);
181 showCurrentThreadInfo();
182 }
183 }
184
185 private void hideOutputPane() {
186 dividerLocation = splitPane.getDividerLocation();
187 splitPane.remove(threadInfo);
188 splitPane.setDividerSize(0);
189 }
190
191 private void showCurrentThreadInfo() {
192 int row = threadTable.getSelectedRow();
193 if (row >= 0) {
194 threadInfo.setJavaThread(dataModel.getJavaThread(row));
195 }
196 }
197
198 private void setActionsEnabled(boolean enabled) {
199 if (actionsEnabled != enabled) {
200 ActionManager manager = ActionManager.getInstance();
201 manager.setActionEnabled(InspectAction.VALUE_COMMAND, enabled);
202 manager.setActionEnabled(MemoryAction.VALUE_COMMAND, enabled);
203 manager.setActionEnabled(JavaStackTraceAction.VALUE_COMMAND, enabled);
204 actionsEnabled = enabled;
205 }
206 }
207
208 } // end ThreadPanel
209
210 private class JavaThreadsToolBar extends CommonToolBar {
211 public JavaThreadsToolBar(StatusBar status) {
212 super(HSDBActionManager.getInstance(), status);
213 }
214
215 protected void addComponents() {
216 addButton(manager.getAction(InspectAction.VALUE_COMMAND));
217 addButton(manager.getAction(MemoryAction.VALUE_COMMAND));
218 addButton(manager.getAction(JavaStackTraceAction.VALUE_COMMAND));
219
220 addToggleButton(manager.getStateChangeAction(ThreadInfoAction.VALUE_COMMAND));
221 addButton(manager.getAction(FindCrashesAction.VALUE_COMMAND));
222 }
223 }
224
225 private class JavaThreadsColumnModel extends DefaultTableColumnModel {
226 private String[] columnNames = { "OS Thread ID", "Java Thread Name" };
227
228 public JavaThreadsColumnModel() {
229 // Should actually get the line metrics for
230 int PREF_WIDTH = 80;
231 int MAX_WIDTH = 100;
232 int HUGE_WIDTH = 140;
233
234 TableColumn column;
235
236 // Thread ID
237 column = new TableColumn(0, MAX_WIDTH);
238 column.setHeaderValue(columnNames[0]);
239 column.setMaxWidth(MAX_WIDTH);
240 column.setResizable(false);
241 addColumn(column);
242
243 // Thread name
244 column = new TableColumn(1, HUGE_WIDTH);
245 column.setHeaderValue(columnNames[1]);
246 column.setResizable(false);
247 addColumn(column);
248 }
249 } // end class JavaThreadsColumnModel
250
251 /**
252 * Encapsulates the set of threads in a table model
253 */
254 private class JavaThreadsTableModel extends AbstractTableModel {
255 private String[] columnNames = { "OS Thread ID", "Java Thread Name" };
256
257 private java.util.List elements;
258
259 public JavaThreadsTableModel(java.util.List threads) {
260 this.elements = threads;
261 }
262
263 public int getColumnCount() {
264 return columnNames.length;
265 }
266
267 public int getRowCount() {
268 return elements.size();
269 }
270
271 public String getColumnName(int col) {
272 return columnNames[col];
273 }
274
275 public Object getValueAt(int row, int col) {
276 CachedThread thread = getRow(row);
277 switch (col) {
278 case 0:
279 return thread.getThreadID();
280 case 1:
281 return thread.getThreadName();
282 default:
283 throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds");
284 }
285 }
286
287 /**
288 * Returns the selected Java Thread indexed by the row or null.
289 */
290 public JavaThread getJavaThread(int index) {
291 return getRow(index).getThread();
292 }
293
294 private CachedThread getRow(int row) {
295 return (CachedThread)elements.get(row);
296 }
297
298 private String threadIDAt(int index) {
299 return ((CachedThread) cachedThreads.get(index)).getThreadID();
300 }
301
302 private String threadNameAt(int index) {
303 try {
304 return ((CachedThread) cachedThreads.get(index)).getThreadName();
305 } catch (AddressException e) {
306 return "<Error: AddressException>";
307 } catch (NullPointerException e) {
308 return "<Error: NullPointerException>";
309 }
310 }
311 } // end class JavaThreadsTableModel
312
313 public void actionPerformed(ActionEvent evt) {
314 String command = evt.getActionCommand();
315
316 if (command.equals(InspectAction.VALUE_COMMAND)) {
317 fireShowThreadOopInspector();
318 } else if (command.equals(MemoryAction.VALUE_COMMAND)) {
319 fireShowThreadStackMemory();
320 } else if (command.equals(ThreadInfoAction.VALUE_COMMAND)) {
321 fireShowThreadInfo();
322 } else if (command.equals(FindCrashesAction.VALUE_COMMAND)) {
323 if (fireShowThreadCrashes()) {
324 statusBar.setMessage("Some thread crashes were encountered");
325 } else {
326 statusBar.setMessage("No thread crashes encountered");
327 }
328 } else if (command.equals(JavaStackTraceAction.VALUE_COMMAND)) {
329 fireShowJavaStackTrace();
330 }
331 }
332
333 // Cached data for a thread
334 private class CachedThread {
335 private JavaThread thread;
336 private String threadID;
337 private String threadName;
338 private boolean computed;
339
340 public CachedThread(JavaThread thread) {
341 this.thread = thread;
342 }
343
344 public JavaThread getThread() {
345 return thread;
346 }
347
348 public String getThreadID() {
349 if (!computed) {
350 compute();
351 }
352
353 return threadID;
354 }
355
356 public String getThreadName() {
357 if (!computed) {
358 compute();
359 }
360
361 return threadName;
362 }
363
364 private void compute() {
365 ByteArrayOutputStream bos = new ByteArrayOutputStream();
366 thread.printThreadIDOn(new PrintStream(bos));
367 threadID = bos.toString();
368 threadName = thread.getThreadName();
369
370 computed = true;
371 }
372 }
373
374 //--------------------------------------------------------------------------------
375 // Internals only below this point
376 //
377
378 protected void registerActions() {
379 registerAction(InspectAction.VALUE_COMMAND);
380 registerAction(MemoryAction.VALUE_COMMAND);
381 registerAction(FindCrashesAction.VALUE_COMMAND);
382 registerAction(JavaStackTraceAction.VALUE_COMMAND);
383
384 // disable Inspector, Memory and Java Stack trace action until a thread is selected
385 ActionManager manager = ActionManager.getInstance();
386 manager.setActionEnabled(InspectAction.VALUE_COMMAND, false);
387 manager.setActionEnabled(MemoryAction.VALUE_COMMAND, false);
388 manager.setActionEnabled(JavaStackTraceAction.VALUE_COMMAND, false);
389 }
390
391 private void registerAction(String actionName) {
392 ActionManager manager = ActionManager.getInstance();
393 DelegateAction action = manager.getDelegateAction(actionName);
394 action.addActionListener(this);
395 }
396
397
398
399 private void fireShowThreadOopInspector() {
400 int i = threadTable.getSelectedRow();
401 if (i < 0) {
402 return;
403 }
404
405 JavaThread t = dataModel.getJavaThread(i);
406 showThreadOopInspector(t);
407 }
408
409 private void fireShowThreadStackMemory() {
410 int i = threadTable.getSelectedRow();
411 if (i < 0) {
412 return;
413 }
414 showThreadStackMemory(dataModel.getJavaThread(i));
415 }
416
417 private void fireShowJavaStackTrace() {
418 int i = threadTable.getSelectedRow();
419 if (i < 0) {
420 return;
421 }
422 showJavaStackTrace(dataModel.getJavaThread(i));
423 }
424
425 private void fireShowThreadInfo() {
426 int i = threadTable.getSelectedRow();
427 if (i < 0) {
428 return;
429 }
430 showThreadInfo(dataModel.getJavaThread(i));
431 }
432
433 /**
434 * Shows stack memory for threads which have crashed (defined as
435 * having taken a signal above a Java frame)
436 *
437 * @return a flag which indicates if crashes were encountered.
438 */
439 private boolean fireShowThreadCrashes() {
440 boolean crash = false;
441 for (Iterator iter = cachedThreads.iterator(); iter.hasNext(); ) {
442 JavaThread t = (JavaThread) ((CachedThread) iter.next()).getThread();
443 sun.jvm.hotspot.runtime.Frame tmpFrame = t.getCurrentFrameGuess();
444 RegisterMap tmpMap = t.newRegisterMap(false);
445 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
446 if (tmpFrame.isSignalHandlerFrameDbg()) {
447 showThreadStackMemory(t);
448 crash = true;
449 break;
450 }
451 tmpFrame = tmpFrame.sender(tmpMap);
452 }
453 }
454 return crash;
455 }
456
457 private void cache() {
458 Threads threads = VM.getVM().getThreads();
459 for (JavaThread t = threads.first(); t != null; t = t.next()) {
460 if (t.isJavaThread()) {
461 cachedThreads.add(new CachedThread(t));
462 }
463 }
464 }
465
466 private void decache() {
467 cachedThreads.clear();
468 }
469
470 }