From 845119b06180e707279159b083487cd02b4d7d4e Mon Sep 17 00:00:00 2001 From: Changyong Gong Date: Wed, 21 Jan 2026 14:53:04 +0800 Subject: [PATCH] feat: support suspend all setting --- .../microsoft/java/debug/core/Breakpoint.java | 15 ++++++++++++- .../java/debug/core/DebugSettings.java | 1 + .../java/debug/core/IBreakpoint.java | 7 ++++++ .../adapter/handler/StepRequestHandler.java | 22 +++++++++++++++++-- .../handler/ThreadsRequestHandler.java | 6 +++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index 82859b268..46bf676d8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -203,6 +203,15 @@ public void setAsync(boolean async) { this.async = async; } + @Override + public void setSuspendPolicy(String policy) { + } + + @Override + public String getSuspendPolicy() { + return DebugSettings.getCurrent().suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD"; + } + @Override public CompletableFuture install() { // It's possible that different class loaders create new class with the same name. @@ -412,7 +421,11 @@ private CompletableFuture> createBreakpointRequests(List newLocations.forEach(location -> { BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location); - request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); + if ("SUSPEND_ALL".equals(getSuspendPolicy())) { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); + } else { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); + } if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index 0a3e05ec8..b422f6801 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -45,6 +45,7 @@ public final class DebugSettings { public int jdwpRequestTimeout = 3000; public AsyncMode asyncJDWP = AsyncMode.OFF; public Switch debugSupportOnDecompiledSource = Switch.OFF; + public boolean suspendAllThreads = false; public static DebugSettings getCurrent() { return current; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java index 40995e9dd..ec3ea818a 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java @@ -55,4 +55,11 @@ default void setAsync(boolean async) { default boolean async() { return false; } + + default void setSuspendPolicy(String policy) { + } + + default String getSuspendPolicy() { + return null; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index e8f782668..ba5d086d5 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -22,6 +22,7 @@ import com.microsoft.java.debug.core.AsyncJdwpUtils; import com.microsoft.java.debug.core.DebugEvent; +import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.DebugUtility; import com.microsoft.java.debug.core.IDebugSession; import com.microsoft.java.debug.core.JdiExceptionReference; @@ -48,6 +49,7 @@ import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; import com.sun.jdi.Value; +import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VoidValue; import com.sun.jdi.event.BreakpointEvent; import com.sun.jdi.event.Event; @@ -112,8 +114,16 @@ public CompletableFuture handle(Command command, Arguments arguments, threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null); } + if (DebugSettings.getCurrent().suspendAllThreads) { + threadState.pendingStepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); + } + threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest(); - threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + if (DebugSettings.getCurrent().suspendAllThreads) { + threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); + } else { + threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + } threadState.targetStepIn = targetId > 0 ? (MethodInvocation) context.getRecyclableIdPool().getObjectById(targetId) : null; @@ -189,7 +199,15 @@ public CompletableFuture handle(Command command, Arguments arguments, } context.getThreadCache().removeEventThread(thread.uniqueID()); - DebugUtility.resumeThread(thread); + if (DebugSettings.getCurrent().suspendAllThreads) { + try { + context.getDebugSession().resume(); + } catch (VMDisconnectedException e) { + // ignore + } + } else { + DebugUtility.resumeThread(thread); + } ThreadsRequestHandler.checkThreadRunningAndRecycleIds(thread, context); } catch (IncompatibleThreadStateException ex) { // Roll back the Exception info if stepping fails. diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java index 6573f11da..5abc48900 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; import com.microsoft.java.debug.core.AsyncJdwpUtils; +import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.DebugUtility; import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.ErrorCode; @@ -149,6 +150,11 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, if (thread == null) { thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId); } + + if (DebugSettings.getCurrent().suspendAllThreads) { + thread = null; + } + /** * See the jdi doc https://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/ThreadReference.html#resume(), * suspends of both the virtual machine and individual threads are counted. Before a thread will run again, it must