Skip to content

Commit 4835ef5

Browse files
committed
Fix race between stopped thread retrieval and continued event
If the debug adapter sends continued right after stopped, before the client retrieved the threads the continued change was lost. Should fix #1365
1 parent 29d1f88 commit 4835ef5

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

lua/dap/session.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,8 @@ function Session:update_threads(cb)
657657
threads[thread.id] = thread
658658
local old_thread = self.threads[thread.id]
659659
if old_thread then
660-
thread.stopped = old_thread.stopped
660+
local stopped = old_thread.stopped == nil and false or old_thread.stopped
661+
thread.stopped = stopped
661662
thread.frames = old_thread.frames
662663
end
663664
end
@@ -689,12 +690,22 @@ function Session:event_stopped(stopped)
689690
local co = coroutine.running()
690691

691692
if self.dirty.threads or (stopped.threadId and self.threads[stopped.threadId] == nil) then
693+
local thread = {
694+
id = stopped.threadId,
695+
name = "Unknown",
696+
stopped = true
697+
}
698+
self.threads[thread.id] = thread
692699
self:update_threads(coresume(co))
693700
local err = coroutine.yield()
694701
if err then
695702
utils.notify('Error retrieving threads: ' .. utils.fmt_error(err), vim.log.levels.ERROR)
696703
return
697704
end
705+
if thread.stopped == false then
706+
log.debug("Thread resumed during stopped event handling", stopped, thread)
707+
return
708+
end
698709
end
699710

700711
local should_jump = stopped.reason ~= 'pause' or stopped.allThreadsStopped

spec/integration_spec.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,32 @@ describe('dap with fake server', function()
322322
})
323323
end)
324324

325+
it("Doesn't jump on stopped if continue is received before threads response", function()
326+
run_and_wait_until_initialized(config, server)
327+
server.client.threads = function(self, request)
328+
self:send_event("continued", {
329+
threadId = 1,
330+
})
331+
self:send_response(request, {
332+
threads = { { id = 1, name = 'thread1' }, }
333+
})
334+
end
335+
local log = require('dap.log').create_logger('dap.log')
336+
local debug = log.debug
337+
local messages = {}
338+
log.debug = function(...)
339+
table.insert(messages, {...})
340+
debug(...)
341+
end
342+
server.client:send_event('stopped', {
343+
threadId = 1,
344+
reason = 'unknown',
345+
})
346+
wait_for_response(server, "threads")
347+
wait(function() return #messages >= 5 end)
348+
assert.are.same("Thread resumed during stopped event handling", messages[6][1])
349+
end)
350+
325351
it("Clears stopped state on continued event", function()
326352
local buf = api.nvim_create_buf(true, false)
327353
local win = api.nvim_get_current_win()

0 commit comments

Comments
 (0)