Skip to content

Commit e9bc5d4

Browse files
committed
fix: handle stoppedEvent for suspend policy change
1 parent 845119b commit e9bc5d4

File tree

11 files changed

+95
-15
lines changed

11 files changed

+95
-15
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ private static StepRequest createStepRequest(ThreadReference thread, int stepSiz
394394
request.addClassExclusionFilter(exclusionFilter);
395395
}
396396
}
397-
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
397+
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
398+
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
398399
request.addCountFilter(1);
399400

400401
return request;
@@ -415,7 +416,8 @@ public static CompletableFuture<Long> stopOnEntry(IDebugSession debugSession, St
415416
EventRequestManager manager = debugSession.getVM().eventRequestManager();
416417
MethodEntryRequest request = manager.createMethodEntryRequest();
417418
request.addClassFilter(mainClass);
418-
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
419+
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
420+
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
419421

420422
debugSession.getEventHub().events().filter(debugEvent -> {
421423
return debugEvent.event instanceof MethodEntryEvent && request.equals(debugEvent.event.request());

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.sun.jdi.VirtualMachine;
2929
import com.sun.jdi.event.ClassPrepareEvent;
3030
import com.sun.jdi.event.ThreadDeathEvent;
31+
import com.sun.jdi.request.EventRequest;
3132
import com.sun.jdi.request.ClassPrepareRequest;
3233
import com.sun.jdi.request.EventRequest;
3334
import com.sun.jdi.request.MethodEntryRequest;
@@ -262,7 +263,8 @@ private Optional<MethodEntryRequest> createMethodEntryRequest0(ReferenceType typ
262263
MethodEntryRequest request = vm.eventRequestManager().createMethodEntryRequest();
263264

264265
request.addClassFilter(type);
265-
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
266+
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
267+
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
266268
if (hitCount > 0) {
267269
request.addCountFilter(hitCount);
268270
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.sun.jdi.VirtualMachine;
2929
import com.sun.jdi.event.ClassPrepareEvent;
3030
import com.sun.jdi.event.ThreadDeathEvent;
31+
import com.sun.jdi.request.EventRequest;
3132
import com.sun.jdi.request.ClassPrepareRequest;
3233
import com.sun.jdi.request.EventRequest;
3334
import com.sun.jdi.request.WatchpointRequest;
@@ -212,7 +213,8 @@ private List<WatchpointRequest> createWatchpointRequests(ReferenceType type) {
212213
}
213214

214215
watchpointRequests.forEach(request -> {
215-
request.setSuspendPolicy(WatchpointRequest.SUSPEND_EVENT_THREAD);
216+
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
217+
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
216218
if (hitCount > 0) {
217219
request.addCountFilter(hitCount);
218220
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/BreakpointManager.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@
2424
import java.util.logging.Logger;
2525

2626
import com.microsoft.java.debug.core.Configuration;
27+
import com.microsoft.java.debug.core.DebugSettings;
28+
import com.microsoft.java.debug.core.DebugSettings.IDebugSettingChangeListener;
2729
import com.microsoft.java.debug.core.IBreakpoint;
30+
import com.microsoft.java.debug.core.IDebugResource;
2831
import com.microsoft.java.debug.core.IMethodBreakpoint;
2932
import com.microsoft.java.debug.core.IWatchpoint;
33+
import com.sun.jdi.VMDisconnectedException;
3034

31-
public class BreakpointManager implements IBreakpointManager {
35+
public class BreakpointManager implements IBreakpointManager, IDebugSettingChangeListener {
3236
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
3337
/**
3438
* A collection of breakpoints registered with this manager.
@@ -47,6 +51,7 @@ public BreakpointManager() {
4751
this.sourceToBreakpoints = new HashMap<>();
4852
this.watchpoints = new HashMap<>();
4953
this.methodBreakpoints = new HashMap<>();
54+
DebugSettings.addDebugSettingChangeListener(this);
5055
}
5156

5257
@Override
@@ -268,4 +273,50 @@ public IMethodBreakpoint[] setMethodBreakpoints(IMethodBreakpoint[] breakpoints)
268273
private String getMethodBreakpointKey(IMethodBreakpoint breakpoint) {
269274
return breakpoint.className() + "#" + breakpoint.methodName();
270275
}
276+
277+
@Override
278+
public void update(DebugSettings oldSettings, DebugSettings newSettings) {
279+
// If suspend policy changed, recreate all breakpoints with new policy
280+
if (oldSettings.suspendAllThreads != newSettings.suspendAllThreads) {
281+
// Recreate all line breakpoints
282+
synchronized (breakpoints) {
283+
for (IBreakpoint bp : breakpoints) {
284+
reinstallBreakpoint(bp);
285+
}
286+
}
287+
288+
// Recreate all watchpoints
289+
for (IWatchpoint wp : watchpoints.values()) {
290+
if (wp != null) {
291+
reinstallBreakpoint(wp);
292+
}
293+
}
294+
295+
// Recreate all method breakpoints
296+
for (IMethodBreakpoint mbp : methodBreakpoints.values()) {
297+
if (mbp != null) {
298+
reinstallBreakpoint(mbp);
299+
}
300+
}
301+
}
302+
}
303+
304+
private void reinstallBreakpoint(IDebugResource resource) {
305+
try {
306+
// Close (delete) existing event requests
307+
resource.close();
308+
// Reinstall with new suspend policy (which will be read from DebugSettings)
309+
if (resource instanceof IBreakpoint) {
310+
((IBreakpoint) resource).install();
311+
} else if (resource instanceof IWatchpoint) {
312+
((IWatchpoint) resource).install();
313+
} else if (resource instanceof IMethodBreakpoint) {
314+
((IMethodBreakpoint) resource).install();
315+
}
316+
} catch (VMDisconnectedException ex) {
317+
// Ignore since reinstalling breakpoints is meaningless when JVM is disconnected.
318+
} catch (Exception e) {
319+
logger.log(Level.WARNING, String.format("Failed to reinstall breakpoint: %s", e.toString()), e);
320+
}
321+
}
271322
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.sun.jdi.event.ThreadStartEvent;
4141
import com.sun.jdi.event.VMDeathEvent;
4242
import com.sun.jdi.event.VMDisconnectEvent;
43+
import com.sun.jdi.request.EventRequest;
4344
import com.sun.jdi.event.VMStartEvent;
4445

4546
public class ConfigurationDoneRequestHandler implements IDebugRequestHandler {
@@ -119,7 +120,9 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
119120
((ExceptionEvent) event).catchLocation() == null);
120121
context.getExceptionManager().setException(thread.uniqueID(), jdiException);
121122
context.getThreadCache().addEventThread(thread, "exception");
122-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID()));
123+
boolean allThreadsStopped = event.request() != null
124+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
125+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), allThreadsStopped));
123126
debugEvent.shouldResume = false;
124127
} else {
125128
isImportantEvent = false;

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.sun.jdi.IncompatibleThreadStateException;
3434
import com.sun.jdi.StackFrame;
3535
import com.sun.jdi.ThreadReference;
36+
import com.sun.jdi.request.EventRequest;
3637
import com.sun.jdi.request.StepRequest;
3738

3839
/**
@@ -121,7 +122,8 @@ private void stepInto(IDebugAdapterContext context, ThreadReference thread) {
121122
debugEvent.shouldResume = false;
122123
// Have to send two events to keep the UI sync with the step in operations:
123124
context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID()));
124-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID()));
125+
boolean allThreadsStopped = request.suspendPolicy() == EventRequest.SUSPEND_ALL;
126+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID(), allThreadsStopped));
125127
context.getThreadCache().setThreadStoppedReason(thread.uniqueID(), "restartframe");
126128
});
127129
request.enable();

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,19 @@ private void registerBreakpointHandler(IDebugAdapterContext context) {
212212
debugEvent.eventSet.resume();
213213
} else {
214214
context.getThreadCache().addEventThread(bpThread, breakpointName);
215+
boolean allThreadsStopped = event.request() != null
216+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
215217
context.getProtocolServer().sendEvent(new Events.StoppedEvent(
216-
breakpointName, bpThread.uniqueID()));
218+
breakpointName, bpThread.uniqueID(), allThreadsStopped));
217219
}
218220
});
219221
});
220222
} else {
221223
context.getThreadCache().addEventThread(bpThread, breakpointName);
224+
boolean allThreadsStopped = event.request() != null
225+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
222226
context.getProtocolServer().sendEvent(new Events.StoppedEvent(
223-
breakpointName, bpThread.uniqueID()));
227+
breakpointName, bpThread.uniqueID(), allThreadsStopped));
224228
}
225229
debugEvent.shouldResume = false;
226230
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.sun.jdi.ThreadReference;
4242
import com.sun.jdi.event.Event;
4343
import com.sun.jdi.event.WatchpointEvent;
44+
import com.sun.jdi.request.EventRequest;
4445

4546
public class SetDataBreakpointsRequestHandler implements IDebugRequestHandler {
4647
private boolean registered = false;
@@ -152,13 +153,17 @@ private void registerWatchpointHandler(IDebugAdapterContext context) {
152153
debugEvent.eventSet.resume();
153154
} else {
154155
context.getThreadCache().addEventThread(bpThread, "data breakpoint");
155-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID()));
156+
boolean allThreadsStopped = event.request() != null
157+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
158+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped));
156159
}
157160
});
158161
});
159162
} else {
160163
context.getThreadCache().addEventThread(bpThread, "data breakpoint");
161-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID()));
164+
boolean allThreadsStopped = event.request() != null
165+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
166+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped));
162167
}
163168
debugEvent.shouldResume = false;
164169
});

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.microsoft.java.debug.core.protocol.Types.FunctionBreakpoint;
4141
import com.sun.jdi.ThreadReference;
4242
import com.sun.jdi.event.MethodEntryEvent;
43+
import com.sun.jdi.request.EventRequest;
4344

4445
public class SetFunctionBreakpointsRequestHandler implements IDebugRequestHandler {
4546
private boolean registered = false;
@@ -166,16 +167,20 @@ private void registerMethodBreakpointHandler(IDebugAdapterContext context) {
166167
debugEvent.eventSet.resume();
167168
} else {
168169
context.getThreadCache().addEventThread(bpThread, "function breakpoint");
170+
boolean allThreadsStopped = methodEntryEvent.request() != null
171+
&& methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
169172
context.getProtocolServer().sendEvent(new Events.StoppedEvent(
170-
"function breakpoint", bpThread.uniqueID()));
173+
"function breakpoint", bpThread.uniqueID(), allThreadsStopped));
171174
}
172175
});
173176
});
174177

175178
} else {
176179
context.getThreadCache().addEventThread(bpThread, "function breakpoint");
180+
boolean allThreadsStopped = methodEntryEvent.request() != null
181+
&& methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
177182
context.getProtocolServer()
178-
.sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID()));
183+
.sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID(), allThreadsStopped));
179184
}
180185

181186
debugEvent.shouldResume = false;

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,9 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
328328
threadState.eventSubscription.dispose();
329329
}
330330
context.getThreadCache().addEventThread(thread, "step");
331-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID()));
331+
boolean allThreadsStopped = event.request() != null
332+
&& event.request().suspendPolicy() == EventRequest.SUSPEND_ALL;
333+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID(), allThreadsStopped));
332334
debugEvent.shouldResume = false;
333335
} else if (event instanceof MethodExitEvent) {
334336
MethodExitEvent methodExitEvent = (MethodExitEvent) event;

0 commit comments

Comments
 (0)