Skip to content

Commit 6f31817

Browse files
committed
fix: not allow change policy during a live debug session
1 parent e9bc5d4 commit 6f31817

File tree

10 files changed

+64
-95
lines changed

10 files changed

+64
-95
lines changed

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,26 @@ public class Breakpoint implements IBreakpoint {
4242
private String condition = null;
4343
private String logMessage = null;
4444
private HashMap<Object, Object> propertyMap = new HashMap<>();
45+
private final boolean suspendAllThreads;
4546

4647
private boolean async = false;
4748

48-
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) {
49-
this(vm, eventHub, className, lineNumber, 0, null);
49+
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) {
50+
this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads);
5051
}
5152

52-
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) {
53-
this(vm, eventHub, className, lineNumber, hitCount, null);
53+
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) {
54+
this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads);
5455
}
5556

56-
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) {
57-
this(vm, eventHub, className, lineNumber, hitCount, condition, null);
57+
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, boolean suspendAllThreads) {
58+
this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads);
5859
}
5960

60-
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) {
61+
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage, boolean suspendAllThreads) {
6162
this.vm = vm;
6263
this.eventHub = eventHub;
64+
this.suspendAllThreads = suspendAllThreads;
6365
String contextClass = className;
6466
String methodName = null;
6567
String methodSignature = null;
@@ -79,13 +81,14 @@ public class Breakpoint implements IBreakpoint {
7981
this.logMessage = logMessage;
8082
}
8183

82-
Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
84+
Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, boolean suspendAllThreads) {
8385
this.vm = vm;
8486
this.eventHub = eventHub;
8587
this.sourceLocation = sourceLocation;
8688
this.hitCount = hitCount;
8789
this.condition = condition;
8890
this.logMessage = logMessage;
91+
this.suspendAllThreads = suspendAllThreads;
8992
}
9093

9194
// IDebugResource
@@ -209,7 +212,11 @@ public void setSuspendPolicy(String policy) {
209212

210213
@Override
211214
public String getSuspendPolicy() {
212-
return DebugSettings.getCurrent().suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD";
215+
return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD";
216+
}
217+
218+
protected boolean suspendAllThreads() {
219+
return suspendAllThreads;
213220
}
214221

215222
@Override

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ public class DebugSession implements IDebugSession {
3636
private EventHub eventHub = new EventHub();
3737
private List<EventRequest> eventRequests = new ArrayList<>();
3838
private List<Disposable> subscriptions = new ArrayList<>();
39+
private final boolean suspendAllThreads;
3940

4041
public DebugSession(VirtualMachine virtualMachine) {
4142
vm = virtualMachine;
43+
// Capture suspend policy at session start - this persists for the session lifetime
44+
this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads;
4245
}
4346

4447
@Override
@@ -128,17 +131,17 @@ public void terminate() {
128131

129132
@Override
130133
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
131-
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
134+
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads);
132135
}
133136

134137
@Override
135138
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) {
136-
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);
139+
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads);
137140
}
138141

139142
@Override
140143
public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) {
141-
return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount);
144+
return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads);
142145
}
143146

144147
@Override
@@ -260,10 +263,15 @@ public VirtualMachine getVM() {
260263
return vm;
261264
}
262265

266+
@Override
267+
public boolean suspendAllThreads() {
268+
return suspendAllThreads;
269+
}
270+
263271
@Override
264272
public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition,
265273
int hitCount) {
266-
return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount);
274+
return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads);
267275
}
268276

269277
private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ private static StepRequest createStepRequest(ThreadReference thread, int stepSiz
394394
request.addClassExclusionFilter(exclusionFilter);
395395
}
396396
}
397-
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
398-
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
397+
// Note: suspend policy will be set by the caller (StepRequestHandler) based on session settings
398+
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
399399
request.addCountFilter(1);
400400

401401
return request;
@@ -416,8 +416,7 @@ public static CompletableFuture<Long> stopOnEntry(IDebugSession debugSession, St
416416
EventRequestManager manager = debugSession.getVM().eventRequestManager();
417417
MethodEntryRequest request = manager.createMethodEntryRequest();
418418
request.addClassFilter(mainClass);
419-
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
420-
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
419+
request.setSuspendPolicy(debugSession.suspendAllThreads() ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
421420

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

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,28 @@ public class EvaluatableBreakpoint extends Breakpoint implements IEvaluatableBre
2929
private Object compiledLogpointExpression = null;
3030
private Map<Long, Object> compiledExpressions = new ConcurrentHashMap<>();
3131

32-
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) {
33-
this(vm, eventHub, className, lineNumber, 0, null);
32+
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) {
33+
this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads);
3434
}
3535

36-
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) {
37-
this(vm, eventHub, className, lineNumber, hitCount, null);
36+
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) {
37+
this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads);
3838
}
3939

4040
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount,
41-
String condition) {
42-
this(vm, eventHub, className, lineNumber, hitCount, condition, null);
41+
String condition, boolean suspendAllThreads) {
42+
this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads);
4343
}
4444

4545
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount,
46-
String condition, String logMessage) {
47-
super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage);
46+
String condition, String logMessage, boolean suspendAllThreads) {
47+
super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage, suspendAllThreads);
4848
this.eventHub = eventHub;
4949
}
5050

5151
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount,
52-
String condition, String logMessage) {
53-
super(vm, eventHub, sourceLocation, hitCount, condition, logMessage);
52+
String condition, String logMessage, boolean suspendAllThreads) {
53+
super(vm, eventHub, sourceLocation, hitCount, condition, logMessage, suspendAllThreads);
5454
this.eventHub = eventHub;
5555
}
5656

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,10 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, Strin
5252
IEventHub getEventHub();
5353

5454
VirtualMachine getVM();
55+
56+
/**
57+
* Returns whether breakpoints should suspend all threads or just the event thread.
58+
* This value is captured at session start and persists for the session lifetime.
59+
*/
60+
boolean suspendAllThreads();
5561
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi
4545
private String condition;
4646
private int hitCount;
4747
private boolean async = false;
48+
private final boolean suspendAllThreads;
4849

4950
private HashMap<Object, Object> propertyMap = new HashMap<>();
5051
private Object compiledConditionalExpression = null;
@@ -54,7 +55,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi
5455
private List<Disposable> subscriptions = new ArrayList<>();
5556

5657
public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, String functionName,
57-
String condition, int hitCount) {
58+
String condition, int hitCount, boolean suspendAllThreads) {
5859
Objects.requireNonNull(vm);
5960
Objects.requireNonNull(eventHub);
6061
Objects.requireNonNull(className);
@@ -65,6 +66,7 @@ public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className,
6566
this.functionName = functionName;
6667
this.condition = condition;
6768
this.hitCount = hitCount;
69+
this.suspendAllThreads = suspendAllThreads;
6870
}
6971

7072
@Override
@@ -263,8 +265,7 @@ private Optional<MethodEntryRequest> createMethodEntryRequest0(ReferenceType typ
263265
MethodEntryRequest request = vm.eventRequestManager().createMethodEntryRequest();
264266

265267
request.addClassFilter(type);
266-
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
267-
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
268+
request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
268269
if (hitCount > 0) {
269270
request.addCountFilter(hitCount);
270271
}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,21 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint {
4747
private HashMap<Object, Object> propertyMap = new HashMap<>();
4848
private Object compiledConditionalExpression = null;
4949
private Map<Long, Object> compiledExpressions = new ConcurrentHashMap<>();
50+
private final boolean suspendAllThreads;
5051

5152
// IDebugResource
5253
private List<EventRequest> requests = new ArrayList<>();
5354
private List<Disposable> subscriptions = new ArrayList<>();
5455

55-
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName) {
56-
this(vm, eventHub, className, fieldName, "write");
56+
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, boolean suspendAllThreads) {
57+
this(vm, eventHub, className, fieldName, "write", suspendAllThreads);
5758
}
5859

59-
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType) {
60-
this(vm, eventHub, className, fieldName, accessType, null, 0);
60+
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, boolean suspendAllThreads) {
61+
this(vm, eventHub, className, fieldName, accessType, null, 0, suspendAllThreads);
6162
}
6263

63-
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount) {
64+
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount, boolean suspendAllThreads) {
6465
Objects.requireNonNull(vm);
6566
Objects.requireNonNull(eventHub);
6667
Objects.requireNonNull(className);
@@ -72,6 +73,7 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint {
7273
this.accessType = accessType;
7374
this.condition = condition;
7475
this.hitCount = hitCount;
76+
this.suspendAllThreads = suspendAllThreads;
7577
}
7678

7779
@Override
@@ -213,8 +215,7 @@ private List<WatchpointRequest> createWatchpointRequests(ReferenceType type) {
213215
}
214216

215217
watchpointRequests.forEach(request -> {
216-
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
217-
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
218+
request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
218219
if (hitCount > 0) {
219220
request.addCountFilter(hitCount);
220221
}

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

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,11 @@
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;
2927
import com.microsoft.java.debug.core.IBreakpoint;
30-
import com.microsoft.java.debug.core.IDebugResource;
3128
import com.microsoft.java.debug.core.IMethodBreakpoint;
3229
import com.microsoft.java.debug.core.IWatchpoint;
33-
import com.sun.jdi.VMDisconnectedException;
3430

35-
public class BreakpointManager implements IBreakpointManager, IDebugSettingChangeListener {
31+
public class BreakpointManager implements IBreakpointManager {
3632
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
3733
/**
3834
* A collection of breakpoints registered with this manager.
@@ -51,7 +47,6 @@ public BreakpointManager() {
5147
this.sourceToBreakpoints = new HashMap<>();
5248
this.watchpoints = new HashMap<>();
5349
this.methodBreakpoints = new HashMap<>();
54-
DebugSettings.addDebugSettingChangeListener(this);
5550
}
5651

5752
@Override
@@ -273,50 +268,4 @@ public IMethodBreakpoint[] setMethodBreakpoints(IMethodBreakpoint[] breakpoints)
273268
private String getMethodBreakpointKey(IMethodBreakpoint breakpoint) {
274269
return breakpoint.className() + "#" + breakpoint.methodName();
275270
}
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-
}
322271
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
import com.microsoft.java.debug.core.AsyncJdwpUtils;
2424
import com.microsoft.java.debug.core.DebugEvent;
25-
import com.microsoft.java.debug.core.DebugSettings;
2625
import com.microsoft.java.debug.core.DebugUtility;
2726
import com.microsoft.java.debug.core.IDebugSession;
2827
import com.microsoft.java.debug.core.JdiExceptionReference;
@@ -114,12 +113,12 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
114113
threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null);
115114
}
116115

117-
if (DebugSettings.getCurrent().suspendAllThreads) {
116+
if (context.getDebugSession().suspendAllThreads()) {
118117
threadState.pendingStepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
119118
}
120119

121120
threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest();
122-
if (DebugSettings.getCurrent().suspendAllThreads) {
121+
if (context.getDebugSession().suspendAllThreads()) {
123122
threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
124123
} else {
125124
threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
@@ -199,7 +198,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
199198
}
200199

201200
context.getThreadCache().removeEventThread(thread.uniqueID());
202-
if (DebugSettings.getCurrent().suspendAllThreads) {
201+
if (context.getDebugSession().suspendAllThreads()) {
203202
try {
204203
context.getDebugSession().resume();
205204
} catch (VMDisconnectedException e) {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.apache.commons.lang3.StringUtils;
2424

2525
import com.microsoft.java.debug.core.AsyncJdwpUtils;
26-
import com.microsoft.java.debug.core.DebugSettings;
2726
import com.microsoft.java.debug.core.DebugUtility;
2827
import com.microsoft.java.debug.core.adapter.AdapterUtils;
2928
import com.microsoft.java.debug.core.adapter.ErrorCode;
@@ -151,7 +150,7 @@ private CompletableFuture<Response> resume(Requests.ContinueArguments arguments,
151150
thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId);
152151
}
153152

154-
if (DebugSettings.getCurrent().suspendAllThreads) {
153+
if (context.getDebugSession().suspendAllThreads()) {
155154
thread = null;
156155
}
157156

0 commit comments

Comments
 (0)