From 27e638846d39b70a9f15ef4e60f7ddf57d9defec Mon Sep 17 00:00:00 2001 From: Fabio Zadrozny Date: Wed, 3 Jul 2019 09:51:59 -0300 Subject: [PATCH] Send continued event when all threads resume. Fixes #1530. (#1554) * Send continued event when all threads resume. Fixes #1530. * Don't hide exception if connect_with_new_session fails. * Don't send resumed event if we haven't initialized first (fix test_reattach). --- src/ptvsd/wrapper.py | 17 +++++++++++++---- tests/func/test_step.py | 2 +- tests/func/test_tracing.py | 3 ++- tests/helpers/session.py | 11 ++++++++++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/ptvsd/wrapper.py b/src/ptvsd/wrapper.py index 9260b3d43..edfd15e9c 100644 --- a/src/ptvsd/wrapper.py +++ b/src/ptvsd/wrapper.py @@ -665,6 +665,7 @@ def __init__( # https://github.com/Microsoft/VSDebugAdapterHost/wiki/Differences-between-Visual-Studio-Code-and-the-Visual-Studio-Debug-Adapter-Host # noqa # VS expects a single stopped event in a multi-threaded scenario. self._client_id = None + self._initialize_received = False # adapter state self.start_reason = None @@ -730,6 +731,7 @@ def handle_exiting(self, exitcode=None, wait=None): def on_initialize(self, request, args): self._client_id = args.get('clientID', None) self._restart_debugger = False + self._initialize_received = True self.send_response(request, **INITIALIZE_RESPONSE) self.send_event('initialized') @@ -1312,10 +1314,17 @@ def on_pydevd_thread_suspend_single_notification(self, seq, args): @pydevd_events.handler(pydevd_comm_constants.CMD_THREAD_RESUME_SINGLE_NOTIFICATION) def on_pydevd_thread_resume_single_notification(self, seq, args): - tid = args['body']['threadId'] - - if os.getenv('PTVSD_USE_CONTINUED'): - self.send_event('continued', threadId=tid) + if not self._initialize_received: + return # This may happen when we disconnect and later reconnect too fast. + body = args['body'] + if self._client_id not in ('visualstudio', 'vsformac'): + # In visual studio any step/continue action already marks all the + # threads as running until a suspend, so, the continued is not + # needed (and can in fact break the UI in some cases -- see: + # https://github.com/microsoft/ptvsd/issues/1358). + # It is however needed in vscode -- see: + # https://github.com/microsoft/ptvsd/issues/1530. + self.send_event('continued', **body) @pydevd_events.handler(pydevd_comm.CMD_WRITE_TO_CONSOLE) def on_pydevd_cmd_write_to_console2(self, seq, args): diff --git a/tests/func/test_step.py b/tests/func/test_step.py index 471fc1d83..12ea1c1d7 100644 --- a/tests/func/test_step.py +++ b/tests/func/test_step.py @@ -34,7 +34,7 @@ def func(): target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], - env={'PTVSD_USE_CONTINUED': '1'}, + client_id='vscode', ) session.set_breakpoints(code_to_debug, [line_numbers['inner1']]) session.start_debugging() diff --git a/tests/func/test_tracing.py b/tests/func/test_tracing.py index 4d3d4877c..5df903f87 100644 --- a/tests/func/test_tracing.py +++ b/tests/func/test_tracing.py @@ -11,6 +11,7 @@ def test_tracing(pyfile, start_method, run_as): + @pyfile def code_to_debug(): from dbgimporter import import_and_enable_debugger @@ -61,7 +62,7 @@ def inner2(): target=(run_as, code_to_debug), start_method=start_method, ignore_unobserved=[Event('continued')], - env={'PTVSD_USE_CONTINUED': '1'}, + client_id='vscode', ) session.set_breakpoints(code_to_debug, line_numbers.values()) diff --git a/tests/helpers/session.py b/tests/helpers/session.py index 3b6e54054..fd011cf54 100644 --- a/tests/helpers/session.py +++ b/tests/helpers/session.py @@ -45,6 +45,9 @@ def __init__(self, start_method='launch', ptvsd_port=None, pid=None): print('New debug session with method %r' % str(start_method)) + # Note: with 'visualstudio' we don't send continued events. + self.client_id = 'visualstudio' + self.target = ('code', 'print("OK")') self.start_method = start_method self.start_method_args = {} @@ -271,6 +274,8 @@ def initialize(self, **kwargs): print('Initializing debug session for ptvsd#%d' % self.ptvsd_port) dbg_argv = [] usr_argv = [] + if 'client_id' in kwargs: + self.client_id = kwargs['client_id'] if self.start_method == 'launch': self._listen() dbg_argv += self._get_argv_for_launch() @@ -523,7 +528,10 @@ def handshake(self): to finalize the configuration stage, and start running code. """ - self.send_request('initialize', {'adapterID': 'test'}).wait_for_response() + self.send_request( + 'initialize', + {'adapterID': 'test', 'clientID': self.client_id} + ).wait_for_response() self.wait_for_next(Event('initialized', {})) request = 'launch' if self.start_method == 'launch' else 'attach' @@ -729,5 +737,6 @@ def connect_with_new_session(self, **kwargs): ns.handshake() except: ns.close() + raise else: return ns