eclipse-theia / theia

Eclipse Theia is a cloud & desktop IDE framework implemented in TypeScript.
http://theia-ide.org
Eclipse Public License 2.0
19.99k stars 2.5k forks source link

Clicking "Continue" in debugger doesn't return to Running state #7691

Open DanTup opened 4 years ago

DanTup commented 4 years ago

I'm debugging an issue when running Flutter apps - when I resume from a breakpoint, the debugger UI often immediately goes back to the "paused" state so it looks like it has hit the breakpoint a second time when it hasn't.

I recorded the DAP traffic when this happens, and noticed there are stackTraceRequests also being sent immediately after resuming:


// Clicked Continue in debug side bar
[12:43:30 PM]: DAP-REQ: continueRequest: {"threadId":0}
[12:43:30 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":22,"command":"continue","success":true,"body":{"allThreadsContinued":false}}
// Debugger asks for stack traces, even though we're no longer paused
[12:43:31 PM]: DAP-REQ: stackTraceRequest: {"startFrame":0,"levels":1,"threadId":0}
[12:43:31 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":23,"command":"stackTrace","success":true,"body":{"stackFrames":[{"id":17,"source":{"name":"package:gitpod_flutter_web/main.dart","path":"/workspace/gitpod-flutter-web/lib/main.dart","sourceReference":0,"adapterData":{"type":"@Script","id":"353","uri":"package:gitpod_flutter_web/main.dart"}},"line":56,"column":7,"name":"<closure>"}],"totalFrames":15}}
[12:43:31 PM]: DAP-REQ: stackTraceRequest: {"startFrame":1,"levels":19,"threadId":0}
[12:43:31 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":24,"command":"stackTrace","success":false,"message":"-32603 Bad state: Invalid null response from service\n#0      VmServerConnection._delegateRequest (package:vm_service/src/vm_service.dart:1475:9)\n<asynchronous suspension>\n#1      _rootRunUnary (dart:async/zone.dart:1192:38)\n#2      _CustomZone.runUnary (dart:async/zone.dart:1085:19)\n#3      _CustomZone.runUnaryGuarded (dart:async/zone.dart:987:7)\n#4      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)\n#5      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:266:7)\n#6      _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:134:11)\n#7      _MapStream._handleData (dart:async/stream_pipe.dart:234:10)\n#8      _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:166:13)\n#9      _rootRunUnary (dart:async/zone.dart:1192:38)\n#10     _CustomZone.runUnary (dart:async/zone.dart:1085:19)\n#11     _CustomZone.runUnaryGuarded (dart:async/zone.dart:987:7)\n#12     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)\n#13     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:266:7)\n#14     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:779:19)\n#15     _StreamController._add (dart:async/stream_controller.dart:655:7)\n#16     _StreamController.add (dart:async/stream_controller.dart:597:5)\n#17     new WebSocketImpl.fromSocket.<anonymous closure> (package:web_socket_channel/src/copy/web_socket_impl.dart:719:21)\n#18     _rootRunUnary (dart:async/zone.dart:1192:38)\n#19     _CustomZone.runUnary (dart:async/zone.dart:1085:19)\n#20     _CustomZone.runUnaryGuarded (dart:async/zone.dart:987:7)\n#21     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)\n#22     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:266:7)\n#23     _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:7…
[12:43:31 PM]: DAP-REQ: scopesRequest: {"frameId":17}
[12:43:31 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":25,"command":"scopes","success":true,"body":{"scopes":[{"name":"Locals","variablesReference":18,"expensive":false}]}}
[12:44:29 PM]: DAP-REQ: stackTraceRequest: {"startFrame":0,"levels":1,"threadId":0}
[12:44:29 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":26,"command":"stackTrace","success":false,"message":"No thread with id 0"}
[12:44:29 PM]: DAP-REQ: stackTraceRequest: {"startFrame":0,"levels":19,"threadId":0}
[12:44:29 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":27,"command":"stackTrace","success":false,"message":"No thread with id 0"}

I don't know whether the stackTraceRequests are causing the UI to go back to looking like it's paused, or whether the debugger thinks it's not paused which is why it's sending stackTraceRequests, but this seems unexpected.

DanTup commented 4 years ago

I tried rejecting the requests when the thread is not paused, and that seemed to stop the UI getting into the wrong state:

[1:03:39 PM]: DAP-REQ: continueRequest: {"threadId":0}
[1:03:39 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":22,"command":"continue","success":true,"body":{"allThreadsContinued":false}}
[1:03:39 PM]: DAP-REQ: stackTraceRequest: {"startFrame":0,"levels":1,"threadId":0}
[1:03:39 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":23,"command":"stackTrace","success":false,"message":"Thread 0 is not paused"}
[1:03:39 PM]: DAP-REQ: stackTraceRequest: {"startFrame":0,"levels":19,"threadId":0}
[1:03:39 PM]: DAP-RESP: {"seq":0,"type":"response","request_seq":24,"command":"stackTrace","success":false,"message":"Thread 0 is not paused"}

However, I think this would be better handled here (either don't send the requests, or don't make the debugger look paused just because it got a stack trace response if it hasn't otherwise been told it's paused).

(it's also strange that the second stackTraceRequests is still sent if the first errors)