From 84cac1499e8fd0ffeef52d0891de3db810b4965b Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 5 Aug 2019 16:17:58 -0700 Subject: [PATCH] Cancel wait for attach if IDE is disconnected (#1657) * Cancel wait for attach if IDE is disconnected * Remove cancel wait wrapper * cleanup --- src/ptvsd/_vendored/pydevd/pydevd.py | 13 +++++++++---- src/ptvsd/server/attach.py | 7 ++++++- src/ptvsd/server/multiproc.py | 13 +++---------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ptvsd/_vendored/pydevd/pydevd.py b/src/ptvsd/_vendored/pydevd/pydevd.py index 17fb86ae..65292576 100644 --- a/src/ptvsd/_vendored/pydevd/pydevd.py +++ b/src/ptvsd/_vendored/pydevd/pydevd.py @@ -543,8 +543,8 @@ class PyDB(object): ''' self._on_configuration_done_event.clear() - def block_until_configuration_done(self): - self._on_configuration_done_event.wait() + def block_until_configuration_done(self, timeout=None): + return self._on_configuration_done_event.wait(timeout) def add_fake_frame(self, thread_id, frame_id, frame): self.suspended_frames_manager.add_fake_frame(thread_id, frame_id, frame) @@ -1968,7 +1968,7 @@ def _enable_attach(address): return py_db._server_socket_name -def _wait_for_attach(): +def _wait_for_attach(cancel=None): ''' Meant to be called after _enable_attach() -- the current thread will only unblock after a connection is in place and the DAP (Debug Adapter Protocol) sends the ConfigurationDone @@ -1978,7 +1978,12 @@ def _wait_for_attach(): if py_db is None: raise AssertionError('Debugger still not created. Please use _enable_attach() before using _wait_for_attach().') - py_db.block_until_configuration_done() + if cancel is None: + py_db.block_until_configuration_done() + else: + while not cancel.is_set(): + if py_db.block_until_configuration_done(0.1): + break def _is_attached(): diff --git a/src/ptvsd/server/attach.py b/src/ptvsd/server/attach.py index f45b3324..aec86115 100644 --- a/src/ptvsd/server/attach.py +++ b/src/ptvsd/server/attach.py @@ -6,6 +6,7 @@ from __future__ import absolute_import, print_function, unicode_literals import sys import pydevd +import threading from ptvsd.common import log, options as common_opts from ptvsd.server import multiproc, options as server_opts @@ -13,6 +14,8 @@ from _pydevd_bundle.pydevd_constants import get_global_debugger from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame +_cancel_wait_for_attach = None + def wait_for_attach(timeout=None): """If a remote debugger is attached, returns immediately. Otherwise, blocks until a remote debugger attaches to this process, or until the @@ -30,7 +33,9 @@ def wait_for_attach(timeout=None): log.info(msg) raise AssertionError(msg) - pydevd._wait_for_attach() + global _cancel_wait_for_attach + _cancel_wait_for_attach = threading.Event() + pydevd._wait_for_attach(cancel=_cancel_wait_for_attach) def enable_attach( diff --git a/src/ptvsd/server/multiproc.py b/src/ptvsd/server/multiproc.py index 4756b297..edebfd5c 100644 --- a/src/ptvsd/server/multiproc.py +++ b/src/ptvsd/server/multiproc.py @@ -19,7 +19,7 @@ except ImportError: import Queue as queue from ptvsd.common import log, messaging, options as common_opts, socket, util -from ptvsd.server import options as server_opts +from ptvsd.server import options as server_opts, attach from _pydev_bundle import pydev_monkey from _pydevd_bundle.pydevd_comm import get_global_debugger @@ -205,15 +205,8 @@ def notify_root(port): if not response['incomingConnection']: log.debug('No IDE connection is expected for this subprocess; unpausing.') - # TODO: The code here exists to cancel any wait for attach in an indirect way. We need a cleaner - # way to cancel wait_for_attach. Ideally, a cancellable wait_for_attach, which ensures that it - # does not mess up the pydevd internal debugger states. - - # debugger = get_global_debugger() - # while debugger is None: - # time.sleep(0.1) - # debugger = get_global_debugger() - # debugger.ready_to_run = True + if attach._cancel_wait_for_attach is not None: + attach._cancel_wait_for_attach.is_set() def patch_args(args):