Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java
41161 views
1
/*
2
* Copyright (c) 2000, 2020, 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.
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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* 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
import sun.jvm.hotspot.types.*;
43
44
import sun.jvm.hotspot.ui.action.*;
45
46
import com.sun.java.swing.ui.*;
47
import com.sun.java.swing.action.*;
48
import sun.jvm.hotspot.utilities.Observable;
49
import sun.jvm.hotspot.utilities.Observer;
50
51
/**
52
* This panel contains a JTable which displays the list of Java
53
* threads as their native thread identifiers combined with their
54
* Java names. It allows selection and examination of any of the
55
* threads.
56
*/
57
public class JavaThreadsPanel extends SAPanel implements ActionListener {
58
private JavaThreadsTableModel dataModel;
59
private StatusBar statusBar;
60
private JTable threadTable;
61
private java.util.List<CachedThread> cachedThreads = new ArrayList<>();
62
private static AddressField crashThread;
63
64
65
static {
66
VM.registerVMInitializedObserver(
67
(o, a) -> initialize(VM.getVM().getTypeDataBase()));
68
}
69
70
private static void initialize(TypeDataBase db) {
71
crashThread = db.lookupType("VMError").getAddressField("_thread");
72
}
73
74
/** Constructor assumes the threads panel is created while the VM is
75
suspended. Subsequent resume and suspend operations of the VM
76
will cause the threads panel to clear and fill itself back in,
77
respectively. */
78
public JavaThreadsPanel() {
79
VM.getVM().registerVMResumedObserver(new Observer() {
80
public void update(Observable o, Object data) {
81
decache();
82
}
83
});
84
85
VM.getVM().registerVMSuspendedObserver(new Observer() {
86
public void update(Observable o, Object data) {
87
cache();
88
}
89
});
90
91
cache();
92
93
setLayout(new BorderLayout());
94
95
dataModel = new JavaThreadsTableModel(cachedThreads);
96
statusBar = new StatusBar();
97
98
threadTable = new JTable(dataModel, new JavaThreadsColumnModel());
99
threadTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
100
threadTable.addMouseListener(new MouseAdapter() {
101
public void mouseClicked(MouseEvent evt) {
102
if (evt.getClickCount() == 2) {
103
// double clicking will display the oop inspector.
104
fireShowThreadOopInspector();
105
}
106
}
107
});
108
109
add(new JavaThreadsToolBar(statusBar), BorderLayout.NORTH);
110
add(new ThreadPanel(threadTable), BorderLayout.CENTER);
111
add(statusBar, BorderLayout.SOUTH);
112
113
registerActions();
114
}
115
116
/**
117
* A splitpane panel which contains the thread table and the Thread Info.
118
* the thread info is toggleable
119
*/
120
private class ThreadPanel extends JPanel {
121
122
private JSplitPane splitPane;
123
private JTable threadTable;
124
private ThreadInfoPanel threadInfo;
125
private int dividerSize;
126
private int dividerLocation = -1;
127
private boolean actionsEnabled = false;
128
129
public ThreadPanel(JTable table) {
130
setLayout(new BorderLayout());
131
this.threadInfo = new ThreadInfoPanel();
132
this.threadTable = table;
133
134
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
135
splitPane.setOneTouchExpandable(true);
136
splitPane.setTopComponent(new JScrollPane(table));
137
138
// Set the size of the divider to 0 but save it so it can be restored
139
dividerSize = splitPane.getDividerSize();
140
splitPane.setDividerSize(0);
141
142
add(splitPane, BorderLayout.CENTER);
143
144
// Register an ItemListener on the LogViewerAction which toggles
145
// the apearance of the ThreadInfoPanel
146
ActionManager manager = HSDBActionManager.getInstance();
147
StateChangeAction action = manager.getStateChangeAction(ThreadInfoAction.VALUE_COMMAND);
148
if (action != null) {
149
action.setItemListener(new ItemListener() {
150
public void itemStateChanged(ItemEvent evt) {
151
if (evt.getStateChange() == ItemEvent.SELECTED) {
152
showOutputPane();
153
} else {
154
hideOutputPane();
155
}
156
}
157
});
158
}
159
160
// A listener is added to listen to changes in row selection
161
// and changes the contents of the ThreadInfoPanel.
162
ListSelectionModel selModel = table.getSelectionModel();
163
selModel.addListSelectionListener(new ListSelectionListener() {
164
public void valueChanged(ListSelectionEvent evt) {
165
if (evt.getValueIsAdjusting() == false) {
166
setActionsEnabled(true);
167
if (isInfoVisible()) {
168
showCurrentThreadInfo();
169
}
170
}
171
}
172
});
173
}
174
175
/**
176
* Returns a flag to indicate if the thread info is visible
177
*/
178
private boolean isInfoVisible() {
179
return (splitPane.getBottomComponent() != null);
180
}
181
182
private void showOutputPane() {
183
if (splitPane.getBottomComponent() == null) {
184
splitPane.setBottomComponent(threadInfo);
185
186
if (dividerLocation == -1) {
187
// Calculate the divider location from the pref size.
188
Dimension pSize = this.getSize();
189
dividerLocation = pSize.height / 2;
190
}
191
192
splitPane.setDividerSize(dividerSize);
193
splitPane.setDividerLocation(dividerLocation);
194
showCurrentThreadInfo();
195
}
196
}
197
198
private void hideOutputPane() {
199
dividerLocation = splitPane.getDividerLocation();
200
splitPane.remove(threadInfo);
201
splitPane.setDividerSize(0);
202
}
203
204
private void showCurrentThreadInfo() {
205
int row = threadTable.getSelectedRow();
206
if (row >= 0) {
207
threadInfo.setJavaThread(dataModel.getJavaThread(row));
208
}
209
}
210
211
private void setActionsEnabled(boolean enabled) {
212
if (actionsEnabled != enabled) {
213
ActionManager manager = ActionManager.getInstance();
214
manager.setActionEnabled(InspectAction.VALUE_COMMAND, enabled);
215
manager.setActionEnabled(MemoryAction.VALUE_COMMAND, enabled);
216
manager.setActionEnabled(JavaStackTraceAction.VALUE_COMMAND, enabled);
217
actionsEnabled = enabled;
218
}
219
}
220
221
} // end ThreadPanel
222
223
private class JavaThreadsToolBar extends CommonToolBar {
224
public JavaThreadsToolBar(StatusBar status) {
225
super(HSDBActionManager.getInstance(), status);
226
}
227
228
protected void addComponents() {
229
addButton(manager.getAction(InspectAction.VALUE_COMMAND));
230
addButton(manager.getAction(MemoryAction.VALUE_COMMAND));
231
addButton(manager.getAction(JavaStackTraceAction.VALUE_COMMAND));
232
233
addToggleButton(manager.getStateChangeAction(ThreadInfoAction.VALUE_COMMAND));
234
addButton(manager.getAction(FindCrashesAction.VALUE_COMMAND));
235
}
236
}
237
238
private class JavaThreadsColumnModel extends DefaultTableColumnModel {
239
private String[] columnNames = { "OS Thread ID", "Java Thread Name" };
240
241
public JavaThreadsColumnModel() {
242
// Should actually get the line metrics for
243
int PREF_WIDTH = 80;
244
int MAX_WIDTH = 100;
245
int HUGE_WIDTH = 140;
246
247
TableColumn column;
248
249
// Thread ID
250
column = new TableColumn(0, MAX_WIDTH);
251
column.setHeaderValue(columnNames[0]);
252
column.setMaxWidth(MAX_WIDTH);
253
column.setResizable(false);
254
addColumn(column);
255
256
// Thread name
257
column = new TableColumn(1, HUGE_WIDTH);
258
column.setHeaderValue(columnNames[1]);
259
column.setResizable(false);
260
addColumn(column);
261
}
262
} // end class JavaThreadsColumnModel
263
264
/**
265
* Encapsulates the set of threads in a table model
266
*/
267
private class JavaThreadsTableModel extends AbstractTableModel {
268
private String[] columnNames = { "OS Thread ID", "Java Thread Name" };
269
270
private java.util.List<CachedThread> elements;
271
272
public JavaThreadsTableModel(java.util.List<CachedThread> threads) {
273
this.elements = threads;
274
}
275
276
public int getColumnCount() {
277
return columnNames.length;
278
}
279
280
public int getRowCount() {
281
return elements.size();
282
}
283
284
public String getColumnName(int col) {
285
return columnNames[col];
286
}
287
288
public Object getValueAt(int row, int col) {
289
CachedThread thread = getRow(row);
290
switch (col) {
291
case 0:
292
return thread.getThreadID();
293
case 1:
294
return thread.getThreadName();
295
default:
296
throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds");
297
}
298
}
299
300
/**
301
* Returns the selected Java Thread indexed by the row or null.
302
*/
303
public JavaThread getJavaThread(int index) {
304
return getRow(index).getThread();
305
}
306
307
private CachedThread getRow(int row) {
308
return elements.get(row);
309
}
310
311
private String threadIDAt(int index) {
312
return cachedThreads.get(index).getThreadID();
313
}
314
315
private String threadNameAt(int index) {
316
try {
317
return cachedThreads.get(index).getThreadName();
318
} catch (AddressException e) {
319
return "<Error: AddressException>";
320
} catch (NullPointerException e) {
321
return "<Error: NullPointerException>";
322
}
323
}
324
} // end class JavaThreadsTableModel
325
326
public void actionPerformed(ActionEvent evt) {
327
String command = evt.getActionCommand();
328
329
if (command.equals(InspectAction.VALUE_COMMAND)) {
330
fireShowThreadOopInspector();
331
} else if (command.equals(MemoryAction.VALUE_COMMAND)) {
332
fireShowThreadStackMemory();
333
} else if (command.equals(ThreadInfoAction.VALUE_COMMAND)) {
334
fireShowThreadInfo();
335
} else if (command.equals(FindCrashesAction.VALUE_COMMAND)) {
336
if (fireShowThreadCrashes()) {
337
statusBar.setMessage("Some thread crashes were encountered");
338
} else {
339
statusBar.setMessage("No thread crashes encountered");
340
}
341
} else if (command.equals(JavaStackTraceAction.VALUE_COMMAND)) {
342
fireShowJavaStackTrace();
343
}
344
}
345
346
// Cached data for a thread
347
private class CachedThread {
348
private JavaThread thread;
349
private String threadID;
350
private String threadName;
351
private boolean computed;
352
353
public CachedThread(JavaThread thread) {
354
this.thread = thread;
355
}
356
357
public JavaThread getThread() {
358
return thread;
359
}
360
361
public String getThreadID() {
362
if (!computed) {
363
compute();
364
}
365
366
return threadID;
367
}
368
369
public String getThreadName() {
370
if (!computed) {
371
compute();
372
}
373
374
return threadName;
375
}
376
377
private void compute() {
378
ByteArrayOutputStream bos = new ByteArrayOutputStream();
379
thread.printThreadIDOn(new PrintStream(bos));
380
threadID = bos.toString();
381
threadName = thread.getThreadName();
382
383
computed = true;
384
}
385
}
386
387
//--------------------------------------------------------------------------------
388
// Internals only below this point
389
//
390
391
protected void registerActions() {
392
registerAction(InspectAction.VALUE_COMMAND);
393
registerAction(MemoryAction.VALUE_COMMAND);
394
registerAction(FindCrashesAction.VALUE_COMMAND);
395
registerAction(JavaStackTraceAction.VALUE_COMMAND);
396
397
// disable Inspector, Memory and Java Stack trace action until a thread is selected
398
ActionManager manager = ActionManager.getInstance();
399
manager.setActionEnabled(InspectAction.VALUE_COMMAND, false);
400
manager.setActionEnabled(MemoryAction.VALUE_COMMAND, false);
401
manager.setActionEnabled(JavaStackTraceAction.VALUE_COMMAND, false);
402
}
403
404
private void registerAction(String actionName) {
405
ActionManager manager = ActionManager.getInstance();
406
DelegateAction action = manager.getDelegateAction(actionName);
407
action.addActionListener(this);
408
}
409
410
411
412
private void fireShowThreadOopInspector() {
413
int i = threadTable.getSelectedRow();
414
if (i < 0) {
415
return;
416
}
417
418
JavaThread t = dataModel.getJavaThread(i);
419
showThreadOopInspector(t);
420
}
421
422
private void fireShowThreadStackMemory() {
423
int i = threadTable.getSelectedRow();
424
if (i < 0) {
425
return;
426
}
427
showThreadStackMemory(dataModel.getJavaThread(i));
428
}
429
430
private void fireShowJavaStackTrace() {
431
int i = threadTable.getSelectedRow();
432
if (i < 0) {
433
return;
434
}
435
showJavaStackTrace(dataModel.getJavaThread(i));
436
}
437
438
private void fireShowThreadInfo() {
439
int i = threadTable.getSelectedRow();
440
if (i < 0) {
441
return;
442
}
443
showThreadInfo(dataModel.getJavaThread(i));
444
}
445
446
/**
447
* Shows stack memory for threads which have crashed (defined as
448
* having taken a signal above a Java frame)
449
*
450
* @return a flag which indicates if crashes were encountered.
451
*/
452
private boolean fireShowThreadCrashes() {
453
Optional<JavaThread> crashed =
454
cachedThreads.stream()
455
.map(t -> t.getThread())
456
.filter(t -> t.getAddress().equals(
457
crashThread.getValue()))
458
.findAny();
459
crashed.ifPresent(this::showThreadStackMemory);
460
return crashed.isPresent();
461
}
462
463
private void cache() {
464
Threads threads = VM.getVM().getThreads();
465
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
466
JavaThread t = threads.getJavaThreadAt(i);
467
if (t.isJavaThread()) {
468
cachedThreads.add(new CachedThread(t));
469
}
470
}
471
}
472
473
private void decache() {
474
cachedThreads.clear();
475
}
476
477
}
478
479