From 8b5eeee7e0b1678e701b07d94e6c3cf07b923597 Mon Sep 17 00:00:00 2001 From: Pavel Minaev Date: Thu, 11 Aug 2022 11:03:15 -0700 Subject: [PATCH] Fix #1008: Re-attaching continuously creates 'accept_worker' threads in debugpy Don't recreate the server socket needlessly. --- setup.cfg | 4 ++-- src/debugpy/adapter/clients.py | 6 +++++- src/debugpy/adapter/servers.py | 12 +++++++++++- src/debugpy/common/log.py | 6 ++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/setup.cfg b/setup.cfg index 88336d05d..a109d40d6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [metadata] -license_file = LICENSE +license_files = LICENSE [versioneer] VCS = git @@ -10,4 +10,4 @@ tag_prefix = v parentdir_prefix = debugpy- [aliases] -test=pytest +test = pytest diff --git a/src/debugpy/adapter/clients.py b/src/debugpy/adapter/clients.py index bc4bc50ab..82985e608 100644 --- a/src/debugpy/adapter/clients.py +++ b/src/debugpy/adapter/clients.py @@ -470,12 +470,16 @@ def attach_request(self, request): ) if listen != (): + if servers.is_serving(): + raise request.isnt_valid('Multiple concurrent "listen" sessions are not supported') host = listen("host", "127.0.0.1") port = listen("port", int) adapter.access_token = None host, port = servers.serve(host, port) else: - host, port = servers.serve() + if not servers.is_serving(): + servers.serve() + host, port = servers.listener.getsockname() # There are four distinct possibilities here. # diff --git a/src/debugpy/adapter/servers.py b/src/debugpy/adapter/servers.py index 176c4b0e6..b860558c6 100644 --- a/src/debugpy/adapter/servers.py +++ b/src/debugpy/adapter/servers.py @@ -19,6 +19,9 @@ access_token = None """Access token used to authenticate with the servers.""" +listener = None +"""Listener socket that accepts server connections.""" + _lock = threading.RLock() _connections = [] @@ -433,9 +436,16 @@ def serve(host="127.0.0.1", port=0): return listener.getsockname() +def is_serving(): + return listener is not None + + def stop_serving(): + global listener try: - listener.close() + if listener is not None: + listener.close() + listener = None except Exception: log.swallow_exception(level="warning") diff --git a/src/debugpy/common/log.py b/src/debugpy/common/log.py index 80003b53a..2859dc201 100644 --- a/src/debugpy/common/log.py +++ b/src/debugpy/common/log.py @@ -339,6 +339,7 @@ def report_paths(get_paths, label=None): report_paths("os.__file__") report_paths("threading.__file__") + report_paths("debugpy.__file__") result = "".join(result).rstrip("\n") info("{0}", result) @@ -376,3 +377,8 @@ def _vars(*names): # pragma: no cover def _stack(): # pragma: no cover stack = "\n".join(traceback.format_stack()) warning("$STACK:\n\n{0}", stack) + + +def _threads(): # pragma: no cover + output = "\n".join([str(t) for t in threading.enumerate()]) + warning("$THREADS:\n\n{0}", output)