Fix #1510: [sys.monitoring] Deadlocks when breakpoints are hit

This commit is contained in:
Pavel Minaev 2024-02-01 11:40:05 -08:00
parent 8ce0f35d75
commit 256967225e
2 changed files with 22 additions and 20 deletions

View file

@ -38,6 +38,12 @@ class Thread:
DAP "thread" event with "reason":"started".
"""
is_traced: bool
"""
Whether this thread is traced. Threads are normally traced, but API clients
can exclude a specific thread from tracing.
"""
_last_id = 0
_all: ClassVar[Dict[int, "Thread"]] = {}
@ -48,6 +54,7 @@ class Thread:
"""
self.python_thread = python_thread
self.is_known_to_adapter = False
self.is_traced = True
with _cvar:
# Thread IDs are serialized as JSON numbers in DAP, which are handled as 64-bit
@ -71,14 +78,6 @@ class Thread:
"name": self.name,
}
@property
def is_debugpy_thread(self):
return getattr(self.python_thread, "is_debugpy_thread", False)
@property
def is_traced(self):
return not self.is_debugpy_thread
@property
def name(self):
return self.python_thread.name
@ -88,10 +87,13 @@ class Thread:
"""
Returns the DAP Thread object corresponding to the given Python thread, or for
the current Python thread if None, creating it and reporting it to adapter if
necessary.
necessary. If the current thread is internal debugpy thread, returns None.
"""
if python_thread is None:
python_thread = threading.current_thread()
if getattr(python_thread, "is_debugpy_thread", False):
return None
with _cvar:
for thread in self._all.values():
if thread.python_thread is python_thread:
@ -118,7 +120,7 @@ class Thread:
thread
for python_thread in threading.enumerate()
for thread in [Thread.from_python_thread(python_thread)]
if thread.is_traced
if thread is not None and thread.is_traced
]
def make_known_to_adapter(self):

View file

@ -238,7 +238,7 @@ class Tracer:
def _trace_line(self, code: CodeType, line_number: int):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return self.monitoring.DISABLE
self.log.debug(f"sys.monitoring event: LINE({line_number}, {code})")
@ -347,19 +347,19 @@ class Tracer:
def _trace_py_start(self, code: CodeType, ip: int):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return self.monitoring.DISABLE
self.log.debug(f"sys.monitoring event: PY_START({code}, {ip})")
def _trace_py_resume(self, code: CodeType, ip: int):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return self.monitoring.DISABLE
self.log.debug(f"sys.monitoring event: PY_RESUME({code}, {ip})")
def _trace_py_return(self, code: CodeType, ip: int, retval: object):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return self.monitoring.DISABLE
self.log.debug(f"sys.monitoring event: PY_RETURN({code}, {ip})")
# TODO: capture returned value to report it when client requests locals.
@ -367,7 +367,7 @@ class Tracer:
def _trace_py_yield(self, code: CodeType, ip: int, retval: object):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return self.monitoring.DISABLE
self.log.debug(f"sys.monitoring event: PY_YIELD({code}, {ip})")
# TODO: capture yielded value to report it when client requests locals.
@ -375,7 +375,7 @@ class Tracer:
def _trace_py_throw(self, code: CodeType, ip: int, exc: BaseException):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return
self.log.debug(
f"sys.monitoring event: PY_THROW({code}, {ip}, {type(exc).__qualname__})"
@ -383,7 +383,7 @@ class Tracer:
def _trace_py_unwind(self, code: CodeType, ip: int, exc: BaseException):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return
self.log.debug(
f"sys.monitoring event: PY_UNWIND({code}, {ip}, {type(exc).__qualname__})"
@ -391,7 +391,7 @@ class Tracer:
def _trace_raise(self, code: CodeType, ip: int, exc: BaseException):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return
self.log.debug(
f"sys.monitoring event: RAISE({code}, {ip}, {type(exc).__qualname__})"
@ -399,7 +399,7 @@ class Tracer:
def _trace_reraise(self, code: CodeType, ip: int, exc: BaseException):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return
self.log.debug(
f"sys.monitoring event: RERAISE({code}, {ip}, {type(exc).__qualname__})"
@ -407,7 +407,7 @@ class Tracer:
def _trace_exception_handled(self, code: CodeType, ip: int, exc: BaseException):
thread = self.Thread.from_python_thread()
if not thread.is_traced:
if thread is None or not thread.is_traced:
return
self.log.debug(
f"sys.monitoring event: EXCEPTION_HANDLED({code}, {ip}, {type(exc).__qualname__})"