service/dap: send continued event before step response (#2594)

* service/dap: send continued event before step response

Send the continued event before the step response to make sure that there is no time where the client believes that only a single thread is running.

Updates golang/vscode-go#1617

* move to helper
This commit is contained in:
Suzy Mueller 2021-07-20 10:51:08 -05:00 committed by GitHub
parent 38aaf274a9
commit 776b86ffc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 34 deletions

@ -39,16 +39,16 @@ func (c *Client) Expect{{.}}(t *testing.T) *dap.{{.}} {
// Check{{.}} fails the test if m is not *{{.}}.
func (c *Client) Check{{.}}(t *testing.T, m dap.Message) *dap.{{.}} {
t.Helper()
t.Helper(){{if or (or (eq . "StepInResponse") (eq . "StepOutResponse")) (eq . "NextResponse") }}
_, ok := m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
m = c.ExpectMessage(t){{end}}
r, ok := m.(*dap.{{.}})
if !ok {
t.Fatalf("got %#v, want *dap.{{.}}", m)
}{{if or (or (eq . "StepInResponse") (eq . "StepOutResponse")) (eq . "NextResponse") }}
m = c.ExpectMessage(t)
_, ok = m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}{{end}}
}
return r
}{{end}}
`))

@ -488,15 +488,15 @@ func (c *Client) ExpectNextResponse(t *testing.T) *dap.NextResponse {
// CheckNextResponse fails the test if m is not *NextResponse.
func (c *Client) CheckNextResponse(t *testing.T, m dap.Message) *dap.NextResponse {
t.Helper()
_, ok := m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
m = c.ExpectMessage(t)
r, ok := m.(*dap.NextResponse)
if !ok {
t.Fatalf("got %#v, want *dap.NextResponse", m)
}
m = c.ExpectMessage(t)
_, ok = m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
return r
}
@ -907,15 +907,15 @@ func (c *Client) ExpectStepInResponse(t *testing.T) *dap.StepInResponse {
// CheckStepInResponse fails the test if m is not *StepInResponse.
func (c *Client) CheckStepInResponse(t *testing.T, m dap.Message) *dap.StepInResponse {
t.Helper()
_, ok := m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
m = c.ExpectMessage(t)
r, ok := m.(*dap.StepInResponse)
if !ok {
t.Fatalf("got %#v, want *dap.StepInResponse", m)
}
m = c.ExpectMessage(t)
_, ok = m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
return r
}
@ -948,15 +948,15 @@ func (c *Client) ExpectStepOutResponse(t *testing.T) *dap.StepOutResponse {
// CheckStepOutResponse fails the test if m is not *StepOutResponse.
func (c *Client) CheckStepOutResponse(t *testing.T, m dap.Message) *dap.StepOutResponse {
t.Helper()
_, ok := m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
m = c.ExpectMessage(t)
r, ok := m.(*dap.StepOutResponse)
if !ok {
t.Fatalf("got %#v, want *dap.StepOutResponse", m)
}
m = c.ExpectMessage(t)
_, ok = m.(*dap.ContinuedEvent)
if !ok {
t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
}
return r
}

@ -1510,24 +1510,37 @@ func (s *Server) onAttachRequest(request *dap.AttachRequest) {
// onNextRequest handles 'next' request.
// This is a mandatory request to support.
func (s *Server) onNextRequest(request *dap.NextRequest, asyncSetupDone chan struct{}) {
s.send(&dap.NextResponse{Response: *newResponse(request.Request)})
s.sendStepResponse(request.Arguments.ThreadId, &dap.NextResponse{Response: *newResponse(request.Request)})
s.doStepCommand(api.Next, request.Arguments.ThreadId, asyncSetupDone)
}
// onStepInRequest handles 'stepIn' request
// This is a mandatory request to support.
func (s *Server) onStepInRequest(request *dap.StepInRequest, asyncSetupDone chan struct{}) {
s.send(&dap.StepInResponse{Response: *newResponse(request.Request)})
s.sendStepResponse(request.Arguments.ThreadId, &dap.StepInResponse{Response: *newResponse(request.Request)})
s.doStepCommand(api.Step, request.Arguments.ThreadId, asyncSetupDone)
}
// onStepOutRequest handles 'stepOut' request
// This is a mandatory request to support.
func (s *Server) onStepOutRequest(request *dap.StepOutRequest, asyncSetupDone chan struct{}) {
s.send(&dap.StepOutResponse{Response: *newResponse(request.Request)})
s.sendStepResponse(request.Arguments.ThreadId, &dap.StepOutResponse{Response: *newResponse(request.Request)})
s.doStepCommand(api.StepOut, request.Arguments.ThreadId, asyncSetupDone)
}
func (s *Server) sendStepResponse(threadId int, message dap.Message) {
// All of the threads will be continued by this request, so we need to send
// a continued event so the UI can properly reflect the current state.
s.send(&dap.ContinuedEvent{
Event: *newEvent("continued"),
Body: dap.ContinuedEventBody{
ThreadId: threadId,
AllThreadsContinued: true,
},
})
s.send(message)
}
func stoppedGoroutineID(state *api.DebuggerState) (id int) {
if state.SelectedGoroutine != nil {
id = state.SelectedGoroutine.ID
@ -1544,15 +1557,6 @@ func stoppedGoroutineID(state *api.DebuggerState) (id int) {
// due to an error, so the server is ready to receive new requests.
func (s *Server) doStepCommand(command string, threadId int, asyncSetupDone chan struct{}) {
defer s.asyncCommandDone(asyncSetupDone)
// All of the threads will be continued by this request, so we need to send
// a continued event so the UI can properly reflect the current state.
s.send(&dap.ContinuedEvent{
Event: *newEvent("continued"),
Body: dap.ContinuedEventBody{
ThreadId: threadId,
AllThreadsContinued: true,
},
})
_, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: threadId}, nil)
if err != nil {
s.log.Errorf("Error switching goroutines while stepping: %v", err)