Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java @ 10229:f6a055fcf47d
8005038: remove crufty '_g' support from SA
Reviewed-by: coleenp, mgronlun, rbackman
author | sla |
---|---|
date | Tue, 07 May 2013 14:33:09 +0200 |
parents | c18cbe5936b8 |
children |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 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 } |