diff --git a/src/ptvsd/adapter/servers.py b/src/ptvsd/adapter/servers.py index 0a2789b4..cf29a34c 100644 --- a/src/ptvsd/adapter/servers.py +++ b/src/ptvsd/adapter/servers.py @@ -86,16 +86,12 @@ if 'ptvsd' not in sys.modules: inject_ptvsd = fmt(inject_ptvsd, ptvsd_dir=ptvsd_dir) try: - self.channel.request( - "evaluate", {"expression": inject_ptvsd} - ) + self.channel.request("evaluate", {"expression": inject_ptvsd}) except messaging.MessageHandlingError: # Failure to inject is not a fatal error - such a subprocess can # still be debugged, it just won't support "import ptvsd" in user # code - so don't terminate the session. - log.exception( - "Failed to inject ptvsd into {0}:", self, level="warning" - ) + log.exception("Failed to inject ptvsd into {0}:", self, level="warning") with _lock: if any(conn.pid == self.pid for conn in _connections): @@ -343,7 +339,7 @@ def wait_for_connection(pid=any, timeout=None): wait_for_timeout.timed_out = timeout == 0 if timeout: thread = threading.Thread( - target=wait_for_timeout, name="server.wait_for_connection() timeout" + target=wait_for_timeout, name="servers.wait_for_connection() timeout" ) thread.daemon = True thread.start() @@ -404,15 +400,32 @@ def inject(pid, ptvsd_args): log.info("Spawning attach-to-PID debugger injector: {0!r}", cmdline) try: - subprocess.Popen( + injector = subprocess.Popen( cmdline, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + stderr=subprocess.STDOUT, ) except Exception as exc: log.exception("Failed to inject debug server into process with PID={0}", pid) raise messaging.MessageHandlingError( "Failed to inject debug server into process with PID={0}: {1}", pid, exc ) + + # We need to capture the output of the injector - otherwise it can get blocked + # on a write() syscall when it tries to print something. + + def capture_output(): + while True: + line = injector.stdout.readline() + if not line: + break + log.info("Injector[PID={0}] output:\n{1}", pid, line.rstrip()) + log.info("Injector[PID={0}] exited.", pid) + + thread = threading.Thread( + target=capture_output, name=fmt("Injector[PID={0}] output", pid) + ) + thread.daemon = True + thread.start() diff --git a/src/ptvsd/server/cli.py b/src/ptvsd/server/cli.py index 38708038..33982062 100644 --- a/src/ptvsd/server/cli.py +++ b/src/ptvsd/server/cli.py @@ -267,7 +267,7 @@ def run_code(): def attach_to_pid(): - log.info("Attaching to process with ID {0}", options.target) + log.info("Attaching to process with PID={0}", options.target) pid = options.target host = options.host @@ -324,7 +324,7 @@ attach_pid_injected.attach(port={port}, host=host, client={client}, log_dir=log_ import add_code_to_python_process # noqa show_debug_info_on_target_process = 0 # hard-coded (1 to debug) - log.info("Code injector begin") + log.info("Injecting code into process with PID={0} ...", pid) add_code_to_python_process.run_python_code( pid, python_code, @@ -332,8 +332,8 @@ attach_pid_injected.attach(port={port}, host=host, client={client}, log_dir=log_ show_debug_info=show_debug_info_on_target_process, ) except Exception: - raise log.exception() - log.info("Code injector exiting") + raise log.exception("Code injection into PID={0} failed:", pid) + log.info("Code injection into PID={0} completed.", pid) def main(): diff --git a/tests/debug/comms.py b/tests/debug/comms.py index 24b28427..89eea8a7 100644 --- a/tests/debug/comms.py +++ b/tests/debug/comms.py @@ -46,6 +46,11 @@ class BackChannel(object): sock, _ = server_socket.accept() except socket.timeout: raise log.exception("Timed out waiting for {0} to connect", self) + except Exception: + if self._server_socket is None: + return + else: + raise sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) log.info("Incoming connection from {0} accepted.", self) diff --git a/tests/debug/runners.py b/tests/debug/runners.py index 89d02a0b..4787f967 100644 --- a/tests/debug/runners.py +++ b/tests/debug/runners.py @@ -152,9 +152,7 @@ def _attach_common_config(session, target, cwd): @_runner def attach_by_pid(session, target, cwd=None, wait=True): - if platform.system() != "Windows": - pytest.skip("https://github.com/microsoft/ptvsd/issues/1810") - if sys.version_info < (3,): + if sys.version_info < (3,) and platform.system() == "Windows": pytest.skip("https://github.com/microsoft/ptvsd/issues/1811") log.info("Attaching {0} to {1} by PID.", session, target) @@ -172,9 +170,16 @@ def attach_by_pid(session, target, cwd=None, wait=True): if wait: debug_me = """ import sys -while not "ptvsd" in sys.modules: pass +import threading +import time + +while not "ptvsd" in sys.modules: + time.sleep(0.1) + import ptvsd -while not ptvsd.is_attached(): pass + +while not ptvsd.is_attached(): + time.sleep(0.1) """ else: debug_me = None