Skip to content

Commit

Permalink
[DAP] Send thread started/exited events
Browse files Browse the repository at this point in the history
These events are needed to make sure that we don't list any stale
threads in the debugger, which produced some visual artifacts in LSP4E
(for instance, some threads still showing as available for resuming
after the program had completed).
  • Loading branch information
agarciadom committed Jun 26, 2024
1 parent b2d2231 commit 7467844
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
import org.eclipse.lsp4j.debug.TerminateArguments;
import org.eclipse.lsp4j.debug.TerminatedEventArguments;
import org.eclipse.lsp4j.debug.Thread;
import org.eclipse.lsp4j.debug.ThreadEventArguments;
import org.eclipse.lsp4j.debug.ThreadEventArgumentsReason;
import org.eclipse.lsp4j.debug.ThreadsResponse;
import org.eclipse.lsp4j.debug.Variable;
import org.eclipse.lsp4j.debug.VariablesArguments;
Expand Down Expand Up @@ -136,8 +138,8 @@ public void aboutToExecute(ModuleElement ast, IEolContext context) {
}

if (ast instanceof IEolModule) {
// Set up thread in our list if we don't have it yet
attachTo((IEolModule) ast);
ThreadState threadState = attachTo((IEolModule) ast);
sendThreadEvent(threadState.getThreadId(), ThreadEventArgumentsReason.STARTED);
}
}
}
Expand Down Expand Up @@ -171,7 +173,9 @@ public void finishedExecutingWithException(ModuleElement ast, EolRuntimeExceptio
protected void removeThreadFor(IEolModule module) {
synchronized (threads) {
for (Iterator<ThreadState> itThread = threads.values().iterator(); itThread.hasNext();) {
if (itThread.next().module == module) {
final ThreadState thread = itThread.next();
if (thread.module == module) {
sendThreadEvent(thread.getThreadId(), ThreadEventArgumentsReason.EXITED);
itThread.remove();
}
}
Expand Down Expand Up @@ -247,6 +251,10 @@ public ThreadState(int threadId, IEolModule module) {
}
}

public int getThreadId() {
return threadId;
}

@Override
public boolean isTerminated() {
return isTerminated;
Expand Down Expand Up @@ -286,19 +294,21 @@ protected BreakpointResult setBreakpoint(final String sourcePath, Integer localL
}
}

protected void attachTo(IEolModule module) {
protected ThreadState attachTo(IEolModule module) {
ThreadState thread;
synchronized (threads) {
for (ThreadState thread : threads.values()) {
if (thread.module == module) {
for (ThreadState t : threads.values()) {
if (t.module == module) {
// We already have attached to this module
return;
return t;
}
}

// Add a thread for this module
final int threadId = nextThread.getAndIncrement();
final ThreadState thread = new ThreadState(threadId, module);
thread = new ThreadState(threadId, module);
threads.put(threadId, thread);
sendThreadEvent(threadId, ThreadEventArgumentsReason.STARTED);
module.getContext().getExecutorFactory().setExecutionController(thread.debugger);
}

Expand All @@ -319,6 +329,8 @@ protected void attachTo(IEolModule module) {
module.getContext().setOutputStream(outStream);
final PrintStream errStream = createStream(module.getContext(), OutputEventArgumentsCategory.STDERR);
module.getContext().setErrorStream(errStream);

return thread;
}

public static final int FIRST_THREAD_ID = 1;
Expand Down Expand Up @@ -846,6 +858,16 @@ protected void sendStopped(int threadId, String reason) {
}
}

protected void sendThreadEvent(int threadId, String reason) {
if (client != null) {
ThreadEventArguments args = new ThreadEventArguments();
args.setReason(reason);
args.setThreadId(threadId);
client.thread(args);
}
}


public IEolModule getModule() {
return mainModule;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -40,6 +41,8 @@
import org.eclipse.lsp4j.debug.StackTraceArguments;
import org.eclipse.lsp4j.debug.StackTraceResponse;
import org.eclipse.lsp4j.debug.StoppedEventArguments;
import org.eclipse.lsp4j.debug.ThreadEventArguments;
import org.eclipse.lsp4j.debug.ThreadEventArgumentsReason;
import org.eclipse.lsp4j.debug.ThreadsResponse;
import org.eclipse.lsp4j.debug.Variable;
import org.eclipse.lsp4j.debug.VariablesArguments;
Expand All @@ -63,6 +66,7 @@ protected class TestClient implements IDebugProtocolClient {
private ExitedEventArguments exitedArgs;

private List<OutputEventArguments> outputs = new ArrayList<>();
private List<ThreadEventArguments> threadEvents = new ArrayList<>();

@Override
public void stopped(StoppedEventArguments args) {
Expand All @@ -81,6 +85,11 @@ public void output(OutputEventArguments args) {
this.outputs.add(args);
}

@Override
public void thread(ThreadEventArguments args) {
this.threadEvents.add(args);
}

public StoppedEventArguments getStoppedArgs() {
return stoppedArgs;
}
Expand All @@ -92,7 +101,10 @@ public ExitedEventArguments getExitedArgs() {
public List<OutputEventArguments> getOutputs() {
return outputs;
}


public List<ThreadEventArguments> getThreadEvents() {
return threadEvents;
}
}

protected static final File BASE_RESOURCE_FOLDER = new File("../org.eclipse.epsilon.eol.dap.test/epsilon/");
Expand Down Expand Up @@ -262,4 +274,22 @@ protected Map<String, Variable> getVariablesFromTopStackFrame() throws Exception
return variablesByName;
}

protected void assertThreadStarted(int threadId) {
assertThreadEventWithReasonExists(threadId, ThreadEventArgumentsReason.STARTED);
}

protected void assertThreadExited(int threadId) {
assertThreadEventWithReasonExists(threadId, ThreadEventArgumentsReason.EXITED);
}

protected void assertThreadEventWithReasonExists(int threadId, final String reason) {
for (ThreadEventArguments ev : client.getThreadEvents()) {
if (ev.getThreadId() == threadId && reason.equals(ev.getReason())) {
return;
}
}

fail(String.format("Expected thread %d to have a %s event", threadId, reason));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public void breakThenContinue() throws Exception {

// Wait for the client to be stopped at the breakpoint
assertStoppedBecauseOf(StoppedEventArgumentsReason.BREAKPOINT);
assertThreadStarted(EpsilonDebugAdapter.FIRST_THREAD_ID);
assertEquals("The debugger should mention the stopped thread",
(Integer) EpsilonDebugAdapter.FIRST_THREAD_ID, client.getStoppedArgs().getThreadId());

Expand Down Expand Up @@ -98,6 +99,7 @@ public void breakThenContinue() throws Exception {

// Execution should complete successfully
assertProgramCompletedSuccessfully();
assertThreadExited(EpsilonDebugAdapter.FIRST_THREAD_ID);

final String expected = "Hello Bob Someone"
+ System.lineSeparator()
Expand Down

0 comments on commit 7467844

Please sign in to comment.