Skip to content

Commit 9e23f5b

Browse files
committed
Always disable pending step request before stopping thread
This should fix the errors of the kind: [error response][stepOut]: Only one step request allowed per thread
1 parent 36a426d commit 9e23f5b

11 files changed

Lines changed: 248 additions & 165 deletions

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class DebugAdapterContext implements IDebugAdapterContext {
6262
private IStackFrameManager stackFrameManager = new StackFrameManager();
6363
private IExceptionManager exceptionManager = new ExceptionManager();
6464
private IBreakpointManager breakpointManager;
65-
private IStepResultManager stepResultManager = new StepResultManager();
65+
private StepRequestManager stepRequestManager = new StepRequestManager();
6666

6767
public DebugAdapterContext(IProtocolServer server, IProviderContext providerContext, Logger logger) {
6868
this.providerContext = providerContext;
@@ -326,7 +326,7 @@ public IBreakpointManager getBreakpointManager() {
326326
}
327327

328328
@Override
329-
public IStepResultManager getStepResultManager() {
330-
return stepResultManager;
329+
public StepRequestManager getStepRequestManager() {
330+
return stepRequestManager;
331331
}
332332
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,5 @@ public interface IDebugAdapterContext {
127127

128128
IBreakpointManager getBreakpointManager();
129129

130-
IStepResultManager getStepResultManager();
130+
StepRequestManager getStepRequestManager();
131131
}

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

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2020 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.java.debug.core.adapter;
13+
14+
import java.util.Collections;
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
import com.microsoft.java.debug.core.DebugUtility;
19+
import com.microsoft.java.debug.core.JdiMethodResult;
20+
import com.microsoft.java.debug.core.protocol.Requests;
21+
import com.sun.jdi.IncompatibleThreadStateException;
22+
import com.sun.jdi.Location;
23+
import com.sun.jdi.ThreadReference;
24+
import com.sun.jdi.request.EventRequestManager;
25+
import com.sun.jdi.request.MethodExitRequest;
26+
import com.sun.jdi.request.StepRequest;
27+
import io.reactivex.disposables.Disposable;
28+
29+
public class StepRequestManager {
30+
private final Map<Long, ThreadState> threadStates = Collections.synchronizedMap(new HashMap<>());
31+
32+
public ThreadState setThreadState(Requests.Command stepType, ThreadReference thread) throws IncompatibleThreadStateException {
33+
long threadId = thread.uniqueID();
34+
int stackDepth = thread.frameCount();
35+
Location location = thread.frame(0).location();
36+
ThreadState threadState = new ThreadState(threadId, stepType, stackDepth, location);
37+
threadStates.put(threadId, threadState);
38+
return threadState;
39+
}
40+
41+
public ThreadState getThreadState(long threadId) {
42+
return threadStates.get(threadId);
43+
}
44+
45+
public void setMethodResult(long threadId, JdiMethodResult methodResult) {
46+
ThreadState threadState = getThreadState(threadId);
47+
threadState.methodResult = methodResult;
48+
}
49+
50+
public JdiMethodResult getMethodResult(long threadId) {
51+
ThreadState threadState = getThreadState(threadId);
52+
if (threadState == null) {
53+
return null;
54+
}
55+
return threadState.methodResult;
56+
}
57+
58+
public void deletePendingStep(long threadId, EventRequestManager manager) {
59+
ThreadState threadState = getThreadState(threadId);
60+
if (threadState != null) {
61+
threadState.deletePendingStep(manager);
62+
}
63+
}
64+
65+
public void deleteAllPendingSteps(EventRequestManager manager) {
66+
this.threadStates.forEach((threadId, threadState) -> threadState.deletePendingStep(manager));
67+
}
68+
69+
public void removeMethodResult(long threadId) {
70+
ThreadState threadState = getThreadState(threadId);
71+
if (threadState == null) {
72+
return;
73+
}
74+
threadState.methodResult = null;
75+
}
76+
77+
public void removeAllMethodResults() {
78+
this.threadStates.forEach((threadId, threadState) -> threadState.methodResult = null);
79+
}
80+
81+
public static class ThreadState {
82+
long threadId;
83+
Requests.Command stepType;
84+
StepRequest pendingStepRequest = null;
85+
MethodExitRequest pendingMethodExitRequest = null;
86+
int stackDepth;
87+
Location stepLocation;
88+
Disposable eventSubscription = null;
89+
JdiMethodResult methodResult = null;
90+
91+
public ThreadState(long threadId, Requests.Command stepType, int stackDepth, Location stepLocation) {
92+
this.threadId = threadId;
93+
this.stepType = stepType;
94+
this.stackDepth = stackDepth;
95+
this.stepLocation = stepLocation;
96+
}
97+
98+
public long getThreadId() {
99+
return threadId;
100+
}
101+
102+
public Requests.Command getStepType() {
103+
return stepType;
104+
}
105+
106+
public void setPendingMethodExitRequest(MethodExitRequest pendingMethodExitRequest) {
107+
this.pendingMethodExitRequest = pendingMethodExitRequest;
108+
}
109+
110+
public MethodExitRequest getPendingMethodExitRequest() {
111+
return pendingMethodExitRequest;
112+
}
113+
114+
public void setPendingStepRequest(StepRequest pendingStepRequest) {
115+
this.pendingStepRequest = pendingStepRequest;
116+
}
117+
118+
public int getStackDepth() {
119+
return stackDepth;
120+
}
121+
122+
public StepRequest getPendingStepRequest() {
123+
return pendingStepRequest;
124+
}
125+
126+
public Location getStepLocation() {
127+
return stepLocation;
128+
}
129+
130+
public void setEventSubscription(Disposable eventSubscription) {
131+
this.eventSubscription = eventSubscription;
132+
}
133+
134+
public void deletePendingStep(EventRequestManager manager) {
135+
deleteStepRequest(manager);
136+
deleteMethodExitRequest(manager);
137+
eventSubscription.dispose();
138+
}
139+
140+
public void deleteStepRequest(EventRequestManager manager) {
141+
if (this.pendingStepRequest == null) {
142+
return;
143+
}
144+
DebugUtility.deleteEventRequestSafely(manager, this.pendingStepRequest);
145+
this.pendingStepRequest = null;
146+
}
147+
148+
private void deleteMethodExitRequest(EventRequestManager manager) {
149+
if (this.pendingMethodExitRequest == null) {
150+
return;
151+
}
152+
DebugUtility.deleteEventRequestSafely(manager, this.pendingMethodExitRequest);
153+
this.pendingMethodExitRequest = null;
154+
}
155+
}
156+
}

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

Lines changed: 0 additions & 42 deletions
This file was deleted.

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.sun.jdi.event.VMDeathEvent;
4141
import com.sun.jdi.event.VMDisconnectEvent;
4242
import com.sun.jdi.event.VMStartEvent;
43+
import com.sun.jdi.request.EventRequestManager;
4344

4445
public class ConfigurationDoneRequestHandler implements IDebugRequestHandler {
4546
protected final Logger logger;
@@ -78,7 +79,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
7879
if (event instanceof VMStartEvent) {
7980
if (context.isVmStopOnEntry()) {
8081
DebugUtility.stopOnEntry(debugSession, context.getMainClass()).thenAccept(threadId -> {
81-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("entry", threadId));
82+
notifyStopEvent("entry", threadId, context);
8283
});
8384
}
8485
} else if (event instanceof VMDeathEvent) {
@@ -120,7 +121,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
120121
JdiExceptionReference jdiException = new JdiExceptionReference(((ExceptionEvent) event).exception(),
121122
((ExceptionEvent) event).catchLocation() == null);
122123
context.getExceptionManager().setException(thread.uniqueID(), jdiException);
123-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID()));
124+
notifyStopEvent("exception", thread.uniqueID(), context);
124125
debugEvent.shouldResume = false;
125126
} else {
126127
isImportantEvent = false;
@@ -134,4 +135,10 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
134135
}
135136
}
136137
}
138+
139+
private void notifyStopEvent(String reason, long threadId, IDebugAdapterContext context) {
140+
EventRequestManager eventRequestManager = context.getDebugSession().getVM().eventRequestManager();
141+
context.getStepRequestManager().deletePendingStep(threadId, eventRequestManager);
142+
context.getProtocolServer().sendEvent(new Events.StoppedEvent(reason, threadId));
143+
}
137144
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.logging.Level;
1919
import java.util.logging.Logger;
2020

21+
import com.sun.jdi.request.EventRequestManager;
2122
import org.apache.commons.io.FilenameUtils;
2223
import org.apache.commons.lang3.StringUtils;
2324

@@ -200,19 +201,25 @@ private void registerBreakpointHandler(IDebugAdapterContext context) {
200201
if (resume) {
201202
debugEvent.eventSet.resume();
202203
} else {
203-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID()));
204+
notifyStoppedThread(context, bpThread.uniqueID());
204205
}
205206
});
206207
});
207208
} else {
208-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID()));
209+
notifyStoppedThread(context, bpThread.uniqueID());
209210
}
210211
debugEvent.shouldResume = false;
211212
}
212213
});
213214
}
214215
}
215216

217+
private void notifyStoppedThread(IDebugAdapterContext context, long threadId) {
218+
EventRequestManager eventRequestManager = context.getDebugSession().getVM().eventRequestManager();
219+
context.getStepRequestManager().deletePendingStep(threadId, eventRequestManager);
220+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", threadId));
221+
}
222+
216223
/**
217224
* Check whether the condition expression is satisfied, and return a boolean value to determine to resume the thread or not.
218225
*/

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.logging.Logger;
2020
import java.util.stream.Stream;
2121

22+
import com.sun.jdi.request.EventRequestManager;
2223
import org.apache.commons.lang3.StringUtils;
2324

2425
import com.microsoft.java.debug.core.IDebugSession;
@@ -158,15 +159,21 @@ private void registerWatchpointHandler(IDebugAdapterContext context) {
158159
if (resume) {
159160
debugEvent.eventSet.resume();
160161
} else {
161-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID()));
162+
notifyStoppedThread(context, bpThread.uniqueID());
162163
}
163164
});
164165
});
165166
} else {
166-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID()));
167+
notifyStoppedThread(context, bpThread.uniqueID());
167168
}
168169
debugEvent.shouldResume = false;
169170
});
170171
}
171172
}
173+
174+
private void notifyStoppedThread(IDebugAdapterContext context, long threadId) {
175+
EventRequestManager eventRequestManager = context.getDebugSession().getVM().eventRequestManager();
176+
context.getStepRequestManager().deletePendingStep(threadId, eventRequestManager);
177+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", threadId));
178+
}
172179
}

0 commit comments

Comments
 (0)