mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Fix #1810: tests using attach_by_pid fail on Linux and macOS
Add time.sleep() to attach_by_pid spinning loop to give the injected code a better chance to execute. Read and log injector output to prevent it from blocking on prints. Improve code injection logging. Fix race between socket.accept() backchannel listener thread, and debug.Session.close().
This commit is contained in:
parent
672c310905
commit
646981e4af
4 changed files with 41 additions and 18 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue