From b8de320eb66eb54a991e3ede296aa0c5cccc9e56 Mon Sep 17 00:00:00 2001 From: fitermay Date: Sat, 10 Mar 2018 16:38:34 -0500 Subject: [PATCH] PY-28911: Prevent pydevd_tracing.SetTrace from being reentered As it causes a deadlock on a non-recursive lock --- .../pydev/_pydevd_bundle/pydevd_tracing.py | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py b/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py index 94d4c8eb819c..2d05f8f28b1b 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py @@ -1,3 +1,5 @@ +from contextlib import contextmanager + from _pydevd_bundle.pydevd_constants import get_frame from _pydev_imps._pydev_saved_modules import thread, threading @@ -67,6 +69,20 @@ def _internal_set_trace(tracing_func): TracingFunctionHolder._original_tracing(tracing_func) +@contextmanager +def _do_not_trace_ctx(): + current_thread = threading.currentThread() + do_not_trace_before = getattr(current_thread, 'pydev_do_not_trace', None) + if do_not_trace_before: + yield + return + current_thread.pydev_do_not_trace = True + try: + yield + finally: + current_thread.pydev_do_not_trace = do_not_trace_before + + def SetTrace(tracing_func, frame_eval_func=None, dummy_tracing_func=None): if tracing_func is not None and frame_eval_func is not None: # There is no need to set tracing function if frame evaluation is available @@ -78,13 +94,14 @@ def SetTrace(tracing_func, frame_eval_func=None, dummy_tracing_func=None): sys.settrace(tracing_func) return - TracingFunctionHolder._lock.acquire() - try: - TracingFunctionHolder._warn = False - _internal_set_trace(tracing_func) - TracingFunctionHolder._warn = True - finally: - TracingFunctionHolder._lock.release() + with _do_not_trace_ctx(): + TracingFunctionHolder._lock.acquire() + try: + TracingFunctionHolder._warn = False + _internal_set_trace(tracing_func) + TracingFunctionHolder._warn = True + finally: + TracingFunctionHolder._lock.release() def replace_sys_set_trace_func():