Skip to content

Commit

Permalink
Virtual threads debug view update + JdiThread new API + unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SougandhS committed Oct 15, 2024
1 parent 6cab2be commit f9ee916
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 67 deletions.
25 changes: 25 additions & 0 deletions org.eclipse.jdt.debug.tests/java23/Main21.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation -- initial API and implementation
*******************************************************************************/
public class Main21 {
public static void main(String[] args) throws InterruptedException {
try {
Thread.startVirtualThread(() -> {
int p = 21;
System.out.println("From Virtual Thread");
}).join();
} catch (Exception e) {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ synchronized void assert23Project() {
jp.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_23);
cfgs.add(createLaunchConfiguration(jp, "Main1"));
cfgs.add(createLaunchConfiguration(jp, "Main2"));
cfgs.add(createLaunchConfiguration(jp, "Main21"));
loaded23 = true;
waitForBuild();
assertNoErrorMarkersExist(jp.getProject());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
import org.eclipse.jdt.debug.tests.ui.JavaSnippetEditorTest;
import org.eclipse.jdt.debug.tests.ui.OpenFromClipboardTests;
import org.eclipse.jdt.debug.tests.ui.ViewManagementTests;
import org.eclipse.jdt.debug.tests.ui.VirtualThreadsDebugViewTests;
import org.eclipse.jdt.debug.tests.ui.presentation.ModelPresentationTests;
import org.eclipse.jdt.debug.tests.ui.presentation.ModelPresentationTests18;
import org.eclipse.jdt.debug.tests.variables.DetailFormatterTests;
Expand Down Expand Up @@ -417,5 +418,8 @@ public AutomatedSuite() {
if (JavaProjectHelper.isJava16_Compatible()) {
addTest(new TestSuite(RecordBreakpointTests.class));
}
if (Runtime.version().feature() == 23 && JavaProjectHelper.isJava23_Compatible()) {
addTest(new TestSuite(VirtualThreadsDebugViewTests.class));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation -- initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.debug.tests.ui;

import org.eclipse.core.resources.IFile;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.IDebugView;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.tests.TestUtil;
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
import org.eclipse.jdt.internal.debug.core.model.JDIThread;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.test.OrderedTestSuite;

import junit.framework.Test;

/**
* Tests for debug view.
*/
public class VirtualThreadsDebugViewTests extends AbstractDebugUiTests {


public static Test suite() {
return new OrderedTestSuite(VirtualThreadsDebugViewTests.class);
}

private boolean showMonitorsOriginal;

public VirtualThreadsDebugViewTests(String name) {
super(name);
}

@Override
protected void setUp() throws Exception {
super.setUp();
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
showMonitorsOriginal = jdiUIPreferences.getBoolean(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO);
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, true);
resetPerspective(DebugViewPerspectiveFactory.ID);
processUiEvents(100);
}

@Override
protected void tearDown() throws Exception {
IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, showMonitorsOriginal);
sync(() -> getActivePage().closeAllEditors(false));
processUiEvents(100);
super.tearDown();
}

@Override
protected IJavaProject getProjectContext() {
return super.get23Project();
}

public void testVirtualThreadDebugView() throws Exception {
sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
final String typeName = "Main21";
final int bpLine = 19;

IJavaBreakpoint bp = createLineBreakpoint(bpLine, "", typeName + ".java", typeName);
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
IFile file = (IFile) bp.getMarker().getResource();
assertEquals(typeName + ".java", file.getName());

IJavaThread mainThread = null;
try {
mainThread = launchToBreakpoint(typeName);
assertNotNull("Launch unsuccessful", mainThread);
openEditorInDebug(file);
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
IDebugView debugViewer = (IDebugView) getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW);
ISelection currentSelection = debugViewer.getViewer().getSelection();
assertNotNull("Debug View is not available", debugViewer);
if (currentSelection instanceof IStructuredSelection) {
Object sel = ((IStructuredSelection) currentSelection).getFirstElement();
if (sel instanceof IStackFrame stackFrame) {
IThread thread = stackFrame.getThread();
JDIThread vThread = (JDIThread) stackFrame.getThread();
assertTrue("Not a Virtual thread", vThread.isVirtualThread());
StructuredSelection select = new StructuredSelection(thread);
debugViewer.getViewer().setSelection(select, true);
IDebugModelPresentation md = DebugUITools.newDebugModelPresentation();
String groupName = md.getText(thread);
assertTrue("Not a Virtual thread grouping", groupName.contains("Virtual"));
}
}
}
});
mainThread.resume();
} catch (Exception e) {
DebugPlugin.log(e);
} finally {
terminateAndRemove(mainThread);
removeAllBreakpoints();
}
}

private void openEditorInDebug(IFile file) throws Exception {
// Let now all pending jobs proceed, ignore console jobs
sync(() -> TestUtil.waitForJobs(getName(), 1000, 10000, ProcessConsole.class));
@SuppressWarnings("unused")
CompilationUnitEditor part = (CompilationUnitEditor) sync(() -> openEditor(file));
processUiEvents(100);
}

@Override
protected boolean enableUIEventLoopProcessingInWaiter() {
return true;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -243,6 +243,23 @@ public class DebugUIMessages extends NLS {
public static String thread_daemon_system_suspended_fieldmodification;
public static String thread_daemon_system_suspended_runtoline;
public static String thread_daemon_system_suspended_classprepare;

public static String thread_virtual_terminated;
public static String thread_virtual_evaluating;
public static String thread_virtual_running;
public static String thread_virtual_stepping;
public static String thread_virtual_suspended;
public static String thread_virtual_suspended_problem;
public static String thread_virtual_suspended_fieldaccess;
public static String thread_virtual_suspended_linebreakpoint;
public static String thread_virtual_suspended_methodentry;
public static String thread_virtual_suspended_exception;
public static String thread_virtual_suspended_exception_uncaught;
public static String thread_virtual_suspended_methodexit;
public static String thread_virtual_suspended_fieldmodification;
public static String thread_virtual_suspended_runtoline;
public static String thread_virtual_suspended_classprepare;

public static String SuspendTimeoutHandler_suspend;
public static String SuspendTimeoutHandler_timeout_occurred;
public static String JDIDebugUIPlugin_Searching_1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2000, 2022 IBM Corporation and others.
# Copyright (c) 2000, 2024 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -184,6 +184,21 @@ thread_daemon_system_suspended_fieldmodification=Daemon System Thread [{0}] (Sus
thread_daemon_system_suspended_runtoline=Daemon System Thread [{0}] (Suspended (run to line {1} in {2}))
thread_daemon_system_suspended_classprepare=Daemon System Thread [{0}] (Class load: {1})

thread_virtual_terminated=Virtual Thread [{0}] (Terminated)
thread_virtual_evaluating=Virtual Thread [{0}] (Evaluating)
thread_virtual_running=Virtual Thread [{0}] (Running)
thread_virtual_stepping=Virtual Thread [{0}] (Stepping)
thread_virtual_suspended=Virtual Thread [{0}] (Suspended)
thread_virtual_suspended_problem=Virtual Thread [{0}] (Suspended ({1}))
thread_virtual_suspended_fieldaccess=Virtual Thread [{0}] (Suspended (access of field {1} in {2}))
thread_virtual_suspended_linebreakpoint=Virtual Thread [{0}] (Suspended (breakpoint at line {1} in {2}))
thread_virtual_suspended_methodentry=Virtual Thread [{0}] (Suspended (entry into method {1} in {2}))
thread_virtual_suspended_exception=Virtual Thread [{0}] (Suspended (exception {1}))
thread_virtual_suspended_exception_uncaught=Virtual Thread [{0}] (Suspended (uncaught exception {1}))
thread_virtual_suspended_methodexit=Virtual Thread [{0}] (Suspended (exit of method {1} in {2}))
thread_virtual_suspended_fieldmodification=Virtual Thread [{0}] (Suspended (modification of field {1} in {2}))
thread_virtual_suspended_runtoline=Virtual Thread [{0}] (Suspended (run to line {1} in {2}))
thread_virtual_suspended_classprepare=Virtual Thread [{0}] (Class load: {1})
###############################################################################

JDIModelPresentation_target_suspended=\ (Suspended)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2022 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -318,14 +318,19 @@ protected String getThreadText(IJavaThread thread, boolean qualified) throws Cor
}
if (thread.isSystemThread()) {
key.append("system_"); //$NON-NLS-1$
} else if (thread instanceof JDIThread jdi) {
if (jdi.isVirtualThread()) {
key.append("virtual_"); //$NON-NLS-1$
}
}
if (thread.isTerminated()) {
key.append("terminated"); //$NON-NLS-1$
args = new String[] {thread.getName()};
} else if (thread.isStepping()) {
key.append("stepping"); //$NON-NLS-1$
args = new String[] {thread.getName()};
} else if ((thread instanceof JDIThread && ((JDIThread)thread).isSuspendVoteInProgress()) && !thread.getDebugTarget().isSuspended()) {
} else if ((thread instanceof JDIThread jdi && jdi.isSuspendVoteInProgress()) && !thread.getDebugTarget().isSuspended()
&& !jdi.isVirtualThread()) {
// show running when listener notification is in progress
key.append("running"); //$NON-NLS-1$
args = new String[] {thread.getName()};
Expand Down Expand Up @@ -415,8 +420,15 @@ protected String getThreadText(IJavaThread thread, boolean qualified) throws Cor
args = new String[] {thread.getName()};
}
}
if (args[0].isEmpty() && thread instanceof JDIThread jdi && jdi.isVirtualThread()) { // Virtual Thread
long virtualThreadID = thread.getThreadObject().getUniqueId();
String id = "ID#" + virtualThreadID; //$NON-NLS-1$
args[0] = id;
}
try {
return getFormattedString((String)DebugUIMessages.class.getDeclaredField(key.toString()).get(null), args);

return getFormattedString((String) DebugUIMessages.class.getDeclaredField(key.toString()).get(null), args);

} catch (IllegalArgumentException e) {
JDIDebugUIPlugin.log(e);
} catch (SecurityException e) {
Expand Down
Loading

0 comments on commit f9ee916

Please sign in to comment.