Skip to content

Commit 956d668

Browse files
SougandhSjukzi
authored andcommitted
Virtual threads debug view update + JdiThread new API + unit tests
1 parent a3c0c22 commit 956d668

9 files changed

Lines changed: 271 additions & 67 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation -- initial API and implementation
13+
*******************************************************************************/
14+
public class Main21 {
15+
public static void main(String[] args) throws InterruptedException {
16+
try {
17+
Thread.startVirtualThread(() -> {
18+
int p = 21;
19+
System.out.println("From Virtual Thread");
20+
}).join();
21+
} catch (Exception e) {
22+
23+
}
24+
}
25+
}

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ synchronized void assert23Project() {
633633
jp.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_23);
634634
cfgs.add(createLaunchConfiguration(jp, "Main1"));
635635
cfgs.add(createLaunchConfiguration(jp, "Main2"));
636+
cfgs.add(createLaunchConfiguration(jp, "Main21"));
636637
loaded23 = true;
637638
waitForBuild();
638639
assertNoErrorMarkersExist(jp.getProject());

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
import org.eclipse.jdt.debug.tests.ui.JavaSnippetEditorTest;
151151
import org.eclipse.jdt.debug.tests.ui.OpenFromClipboardTests;
152152
import org.eclipse.jdt.debug.tests.ui.ViewManagementTests;
153+
import org.eclipse.jdt.debug.tests.ui.VirtualThreadsDebugViewTests;
153154
import org.eclipse.jdt.debug.tests.ui.presentation.ModelPresentationTests;
154155
import org.eclipse.jdt.debug.tests.ui.presentation.ModelPresentationTests18;
155156
import org.eclipse.jdt.debug.tests.variables.DetailFormatterTests;
@@ -417,5 +418,8 @@ public AutomatedSuite() {
417418
if (JavaProjectHelper.isJava16_Compatible()) {
418419
addTest(new TestSuite(RecordBreakpointTests.class));
419420
}
421+
if (Runtime.version().feature() == 23 && JavaProjectHelper.isJava23_Compatible()) {
422+
addTest(new TestSuite(VirtualThreadsDebugViewTests.class));
423+
}
420424
}
421425
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 IBM Corporation.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation -- initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.debug.tests.ui;
15+
16+
import org.eclipse.core.resources.IFile;
17+
import org.eclipse.debug.core.DebugPlugin;
18+
import org.eclipse.debug.core.model.IStackFrame;
19+
import org.eclipse.debug.core.model.IThread;
20+
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
21+
import org.eclipse.debug.ui.DebugUITools;
22+
import org.eclipse.debug.ui.IDebugModelPresentation;
23+
import org.eclipse.debug.ui.IDebugUIConstants;
24+
import org.eclipse.debug.ui.IDebugView;
25+
import org.eclipse.jdt.core.IJavaProject;
26+
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
27+
import org.eclipse.jdt.debug.core.IJavaThread;
28+
import org.eclipse.jdt.debug.tests.TestUtil;
29+
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
30+
import org.eclipse.jdt.internal.debug.core.model.JDIThread;
31+
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
32+
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
33+
import org.eclipse.jface.preference.IPreferenceStore;
34+
import org.eclipse.jface.viewers.ISelection;
35+
import org.eclipse.jface.viewers.IStructuredSelection;
36+
import org.eclipse.jface.viewers.StructuredSelection;
37+
import org.eclipse.swt.widgets.Display;
38+
import org.eclipse.test.OrderedTestSuite;
39+
40+
import junit.framework.Test;
41+
42+
/**
43+
* Tests for debug view.
44+
*/
45+
public class VirtualThreadsDebugViewTests extends AbstractDebugUiTests {
46+
47+
48+
public static Test suite() {
49+
return new OrderedTestSuite(VirtualThreadsDebugViewTests.class);
50+
}
51+
52+
private boolean showMonitorsOriginal;
53+
54+
public VirtualThreadsDebugViewTests(String name) {
55+
super(name);
56+
}
57+
58+
@Override
59+
protected void setUp() throws Exception {
60+
super.setUp();
61+
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
62+
showMonitorsOriginal = jdiUIPreferences.getBoolean(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO);
63+
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, true);
64+
resetPerspective(DebugViewPerspectiveFactory.ID);
65+
processUiEvents(100);
66+
}
67+
68+
@Override
69+
protected void tearDown() throws Exception {
70+
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
71+
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, showMonitorsOriginal);
72+
sync(() -> getActivePage().closeAllEditors(false));
73+
processUiEvents(100);
74+
super.tearDown();
75+
}
76+
77+
@Override
78+
protected IJavaProject getProjectContext() {
79+
return super.get23Project();
80+
}
81+
82+
public void testVirtualThreadDebugView() throws Exception {
83+
sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
84+
final String typeName = "Main21";
85+
final int bpLine = 19;
86+
87+
IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
88+
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
89+
IFile file = (IFile) bp.getMarker().getResource();
90+
assertEquals(typeName + ".java", file.getName());
91+
92+
IJavaThread mainThread = null;
93+
try {
94+
mainThread = launchToBreakpoint(typeName);
95+
assertNotNull("Launch unsuccessful", mainThread);
96+
openEditorInDebug(file);
97+
Display.getDefault().asyncExec(new Runnable() {
98+
@Override
99+
public void run() {
100+
IDebugView debugViewer = (IDebugView) getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW);
101+
ISelection currentSelection = debugViewer.getViewer().getSelection();
102+
assertNotNull("Debug View is not available", debugViewer);
103+
if (currentSelection instanceof IStructuredSelection) {
104+
Object sel = ((IStructuredSelection) currentSelection).getFirstElement();
105+
if (sel instanceof IStackFrame stackFrame) {
106+
IThread thread = stackFrame.getThread();
107+
JDIThread vThread = (JDIThread) stackFrame.getThread();
108+
assertTrue("Not a Virtual thread", vThread.isVirtualThread());
109+
StructuredSelection select = new StructuredSelection(thread);
110+
debugViewer.getViewer().setSelection(select, true);
111+
IDebugModelPresentation md = DebugUITools.newDebugModelPresentation();
112+
String groupName = md.getText(thread);
113+
assertTrue("Not a Virtual thread grouping", groupName.contains("Virtual"));
114+
}
115+
}
116+
}
117+
});
118+
mainThread.resume();
119+
} catch (Exception e) {
120+
DebugPlugin.log(e);
121+
} finally {
122+
terminateAndRemove(mainThread);
123+
removeAllBreakpoints();
124+
}
125+
}
126+
127+
private void openEditorInDebug(IFile file) throws Exception {
128+
// Let now all pending jobs proceed, ignore console jobs
129+
sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
130+
@SuppressWarnings("unused")
131+
CompilationUnitEditor part = (CompilationUnitEditor) sync(() -> openEditor(file));
132+
processUiEvents(100);
133+
}
134+
135+
@Override
136+
protected boolean enableUIEventLoopProcessingInWaiter() {
137+
return true;
138+
}
139+
140+
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2019 IBM Corporation and others.
2+
* Copyright (c) 2000, 2024 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -243,6 +243,23 @@ public class DebugUIMessages extends NLS {
243243
public static String thread_daemon_system_suspended_fieldmodification;
244244
public static String thread_daemon_system_suspended_runtoline;
245245
public static String thread_daemon_system_suspended_classprepare;
246+
247+
public static String thread_virtual_terminated;
248+
public static String thread_virtual_evaluating;
249+
public static String thread_virtual_running;
250+
public static String thread_virtual_stepping;
251+
public static String thread_virtual_suspended;
252+
public static String thread_virtual_suspended_problem;
253+
public static String thread_virtual_suspended_fieldaccess;
254+
public static String thread_virtual_suspended_linebreakpoint;
255+
public static String thread_virtual_suspended_methodentry;
256+
public static String thread_virtual_suspended_exception;
257+
public static String thread_virtual_suspended_exception_uncaught;
258+
public static String thread_virtual_suspended_methodexit;
259+
public static String thread_virtual_suspended_fieldmodification;
260+
public static String thread_virtual_suspended_runtoline;
261+
public static String thread_virtual_suspended_classprepare;
262+
246263
public static String SuspendTimeoutHandler_suspend;
247264
public static String SuspendTimeoutHandler_timeout_occurred;
248265
public static String JDIDebugUIPlugin_Searching_1;

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
###############################################################################
2-
# Copyright (c) 2000, 2022 IBM Corporation and others.
2+
# Copyright (c) 2000, 2024 IBM Corporation and others.
33
#
44
# This program and the accompanying materials
55
# are made available under the terms of the Eclipse Public License 2.0
@@ -184,6 +184,21 @@ thread_daemon_system_suspended_fieldmodification=Daemon System Thread [{0}] (Sus
184184
thread_daemon_system_suspended_runtoline=Daemon System Thread [{0}] (Suspended (run to line {1} in {2}))
185185
thread_daemon_system_suspended_classprepare=Daemon System Thread [{0}] (Class load: {1})
186186

187+
thread_virtual_terminated=Virtual Thread [{0}] (Terminated)
188+
thread_virtual_evaluating=Virtual Thread [{0}] (Evaluating)
189+
thread_virtual_running=Virtual Thread [{0}] (Running)
190+
thread_virtual_stepping=Virtual Thread [{0}] (Stepping)
191+
thread_virtual_suspended=Virtual Thread [{0}] (Suspended)
192+
thread_virtual_suspended_problem=Virtual Thread [{0}] (Suspended ({1}))
193+
thread_virtual_suspended_fieldaccess=Virtual Thread [{0}] (Suspended (access of field {1} in {2}))
194+
thread_virtual_suspended_linebreakpoint=Virtual Thread [{0}] (Suspended (breakpoint at line {1} in {2}))
195+
thread_virtual_suspended_methodentry=Virtual Thread [{0}] (Suspended (entry into method {1} in {2}))
196+
thread_virtual_suspended_exception=Virtual Thread [{0}] (Suspended (exception {1}))
197+
thread_virtual_suspended_exception_uncaught=Virtual Thread [{0}] (Suspended (uncaught exception {1}))
198+
thread_virtual_suspended_methodexit=Virtual Thread [{0}] (Suspended (exit of method {1} in {2}))
199+
thread_virtual_suspended_fieldmodification=Virtual Thread [{0}] (Suspended (modification of field {1} in {2}))
200+
thread_virtual_suspended_runtoline=Virtual Thread [{0}] (Suspended (run to line {1} in {2}))
201+
thread_virtual_suspended_classprepare=Virtual Thread [{0}] (Class load: {1})
187202
###############################################################################
188203

189204
JDIModelPresentation_target_suspended=\ (Suspended)

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2022 IBM Corporation and others.
2+
* Copyright (c) 2000, 2024 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -318,14 +318,19 @@ protected String getThreadText(IJavaThread thread, boolean qualified) throws Cor
318318
}
319319
if (thread.isSystemThread()) {
320320
key.append("system_"); //$NON-NLS-1$
321+
} else if (thread instanceof JDIThread jdi) {
322+
if (jdi.isVirtualThread()) {
323+
key.append("virtual_"); //$NON-NLS-1$
324+
}
321325
}
322326
if (thread.isTerminated()) {
323327
key.append("terminated"); //$NON-NLS-1$
324328
args = new String[] {thread.getName()};
325329
} else if (thread.isStepping()) {
326330
key.append("stepping"); //$NON-NLS-1$
327331
args = new String[] {thread.getName()};
328-
} else if ((thread instanceof JDIThread && ((JDIThread)thread).isSuspendVoteInProgress()) && !thread.getDebugTarget().isSuspended()) {
332+
} else if ((thread instanceof JDIThread jdi && jdi.isSuspendVoteInProgress()) && !thread.getDebugTarget().isSuspended()
333+
&& !jdi.isVirtualThread()) {
329334
// show running when listener notification is in progress
330335
key.append("running"); //$NON-NLS-1$
331336
args = new String[] {thread.getName()};
@@ -415,8 +420,15 @@ protected String getThreadText(IJavaThread thread, boolean qualified) throws Cor
415420
args = new String[] {thread.getName()};
416421
}
417422
}
423+
if (args[0].isEmpty() && thread instanceof JDIThread jdi && jdi.isVirtualThread()) { // Virtual Thread
424+
long virtualThreadID = thread.getThreadObject().getUniqueId();
425+
String id = "ID#" + virtualThreadID; //$NON-NLS-1$
426+
args[0] = id;
427+
}
418428
try {
419-
return getFormattedString((String)DebugUIMessages.class.getDeclaredField(key.toString()).get(null), args);
429+
430+
return getFormattedString((String) DebugUIMessages.class.getDeclaredField(key.toString()).get(null), args);
431+
420432
} catch (IllegalArgumentException e) {
421433
JDIDebugUIPlugin.log(e);
422434
} catch (SecurityException e) {

0 commit comments

Comments
 (0)