def __init__(self, thread_id, method=None, *args, **kwargs): assert thread_id == '*' InternalThreadCommand.__init__(self, thread_id, method, *args, **kwargs) self.executed = False self.lock = thread.allocate_lock()
class TracingFunctionHolder: '''This class exists just to keep some variables (so that we don't keep them in the global namespace). ''' _original_tracing = None _warn = True _lock = thread.allocate_lock() _traceback_limit = 1 _warnings_shown = {}
def _init(self): if self._rlock: self._lock = threading.RLock() else: self._lock = thread.allocate_lock() self.acquire = self._lock.acquire self.release = self._lock.release _fork_safe_locks.append(weakref.ref(self))
def custom_frames_container_init(): #Note: no staticmethod on jython 2.1 (so, use free-function) CustomFramesContainer.custom_frames_lock = thread.allocate_lock() # custom_frames can only be accessed if properly locked with custom_frames_lock! # Key is a string identifying the frame (as well as the thread it belongs to). # Value is a CustomFrame. # CustomFramesContainer.custom_frames = {} # Only to be used in this module CustomFramesContainer._next_frame_id = 0 # This is the event we must set to release an internal process events. It's later set by the actual debugger # when we do create the debugger. CustomFramesContainer._py_db_command_thread_event = Null()
def __init__(self): PyDBAdditionalThreadInfoOriginal.__init__(self) #That's where the last frame entered is kept. That's needed so that we're able to #trace contexts that were previously untraced and are currently active. So, the bad thing #is that the frame may be kept alive longer than it would if we go up on the frame stack, #and is only disposed when some other frame is removed. #A better way would be if we could get the topmost frame for each thread, but that's #not possible (until python 2.5 -- which is the PyDBAdditionalThreadInfo version) #Or if the user compiled threadframe (from http://www.majid.info/mylos/stories/2004/06/10/threadframe.html) #NOT RLock!! (could deadlock if it was) self.lock = thread.allocate_lock() self._acquire_lock = self.lock.acquire self._release_lock = self.lock.release #collection with the refs d = {} self.pydev_existing_frames = d try: self._iter_frames = d.iterkeys except AttributeError: self._iter_frames = d.keys
class AdditionalFramesContainer: lock = thread.allocate_lock() additional_frames = {} # dict of dicts
def set_trace_to_threads(tracing_func): lib = load_python_helper_lib() if lib is None: # This is the case if it's not CPython. pydev_log.info( 'Unable to load helper lib to set tracing to all threads (unsupported python vm).' ) return -1 pydev_log.info( 'Successfully Loaded helper lib to set tracing to all threads.') ret = 0 set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace # Note: use sys._current_frames() keys to get the thread ids because it'll return # thread ids created in C/C++ where there's user code running, unlike the APIs # from the threading module which see only threads created through it (unless # a call for threading.current_thread() was previously done in that thread, # in which case a dummy thread would've been created for it). thread_idents = set(sys._current_frames().keys()) thread_idents = thread_idents.difference( # Ignore pydevd threads. set(t.ident for t in threading.enumerate() if getattr(t, 'pydev_do_not_trace', False))) curr_ident = thread.get_ident() curr_thread = threading._active.get(curr_ident) for thread_ident in thread_idents: # If that thread is not available in the threading module we also need to create a # dummy thread for it (otherwise it'll be invisible to the debugger). if thread_ident not in threading._active: class _DummyThread(threading._DummyThread): def _set_ident(self): # Note: Hack to set the thread ident that we want. if IS_PY2: self._Thread__ident = thread_ident else: self._ident = thread_ident t = _DummyThread() # Reset to the base class (don't expose our own version of the class). t.__class__ = threading._DummyThread with threading._active_limbo_lock: # On Py2 it'll put in active getting the current indent, not using the # ident that was set, so, we have to update it (should be harmless on Py3 # so, do it always). threading._active[thread_ident] = t threading._active[curr_ident] = curr_thread if t.ident != thread_ident: # Check if it actually worked. pydev_log.critical( 'pydevd: creation of _DummyThread with fixed thread ident did not succeed.' ) # Some (ptvsd) tests failed because of this, so, leave it always disabled for now. # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0 show_debug_info = 0 # Hack to increase _Py_TracingPossible. # See comments on py_custom_pyeval_settrace.hpp proceed = thread.allocate_lock() proceed.acquire() def dummy_trace(frame, event, arg): return dummy_trace def increase_tracing_count(): SetTrace(dummy_trace) proceed.release() start_new_thread = pydev_monkey.get_original_start_new_thread(thread) start_new_thread(increase_tracing_count, ()) proceed.acquire() # Only proceed after the release() is done. proceed = None result = lib.AttachDebuggerTracing( ctypes.c_int(show_debug_info), ctypes.py_object(set_trace_func), ctypes.py_object(tracing_func), ctypes.c_uint(thread_ident), ctypes.py_object(None), ) if result != 0: pydev_log.info( 'Unable to set tracing for existing thread. Result: %s', result) ret = result return ret
for name in patched_modules: del sys.modules[name] # import for side effects import _pydev_imps._pydev_saved_modules for name in patched_modules: sys.modules[name] = patched_modules[name] if USE_LIB_COPY: protect_libraries_from_patching() from _pydev_imps._pydev_saved_modules import thread _nextThreadIdLock = thread.allocate_lock() if IS_PY3K: def dict_keys(d): return list(d.keys()) def dict_values(d): return list(d.values()) dict_iter_values = dict.values def dict_iter_items(d): return d.items() def dict_items(d): return list(d.items())
for name in patched_modules: del sys.modules[name] # import for side effects import _pydev_imps._pydev_saved_modules for name in patched_modules: sys.modules[name] = patched_modules[name] if USE_LIB_COPY: protect_libraries_from_patching() from _pydev_imps._pydev_saved_modules import thread _thread_id_lock = thread.allocate_lock() thread_get_ident = thread.get_ident if IS_PY3K: def dict_keys(d): return list(d.keys()) def dict_values(d): return list(d.values()) dict_iter_values = dict.values def dict_iter_items(d): return d.items()
def set_trace_to_threads(tracing_func): lib = load_python_helper_lib() if lib is None: # This is the case if it's not CPython. return -1 if hasattr(sys, 'getswitchinterval'): get_interval, set_interval = sys.getswitchinterval, sys.setswitchinterval else: get_interval, set_interval = sys.getcheckinterval, sys.setcheckinterval prev_value = get_interval() ret = 0 try: if not IS_PY37_OR_GREATER: # Prevent going to any other thread... if we switch the thread during this operation we # could potentially corrupt the interpreter. # Note: on CPython 3.7 onwards this is not needed (we have a different implementation # for setting the tracing for other threads in this case). set_interval(2 ** 15) set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace # Note: use sys._current_frames() keys to get the thread ids because it'll return # thread ids created in C/C++ where there's user code running, unlike the APIs # from the threading module which see only threads created through it (unless # a call for threading.current_thread() was previously done in that thread, # in which case a dummy thread would've been created for it). thread_idents = set(sys._current_frames().keys()) thread_idents = thread_idents.difference( # Ignore pydevd threads. set(t.ident for t in threading.enumerate() if getattr(t, 'pydev_do_not_trace', False)) ) curr_ident = thread.get_ident() curr_thread = threading._active.get(curr_ident) for thread_ident in thread_idents: # If that thread is not available in the threading module we also need to create a # dummy thread for it (otherwise it'll be invisible to the debugger). if thread_ident not in threading._active: class _DummyThread(threading._DummyThread): def _set_ident(self): # Note: Hack to set the thread ident that we want. if IS_PY2: self._Thread__ident = thread_ident else: self._ident = thread_ident t = _DummyThread() # Reset to the base class (don't expose our own version of the class). t.__class__ = threading._DummyThread with threading._active_limbo_lock: # On Py2 it'll put in active getting the current indent, not using the # ident that was set, so, we have to update it (should be harmless on Py3 # so, do it always). threading._active[thread_ident] = t threading._active[curr_ident] = curr_thread if t.ident != thread_ident: # Check if it actually worked. pydev_log.error('pydevd: creation of _DummyThread with fixed thread ident did not succeed.') # Some (ptvsd) tests failed because of this, so, leave it always disabled for now. # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0 show_debug_info = 0 if IS_PY37_OR_GREATER: # Hack to increase _Py_TracingPossible. # See comments on py_settrace_37.hpp proceed = thread.allocate_lock() proceed.acquire() def dummy_trace_on_py37(frame, event, arg): return dummy_trace_on_py37 def increase_tracing_count_on_py37(): SetTrace(dummy_trace_on_py37) proceed.release() start_new_thread = pydev_monkey.get_original_start_new_thread(thread) start_new_thread(increase_tracing_count_on_py37, ()) proceed.acquire() # Only proceed after the release() is done. proceed = None result = lib.AttachDebuggerTracing( ctypes.c_int(show_debug_info), ctypes.py_object(set_trace_func), ctypes.py_object(tracing_func), ctypes.c_uint(thread_ident), ctypes.py_object(None), ) if result != 0: pydev_log.info('Unable to set tracing for existing threads. Result: %s' % result) ret = result finally: if not IS_PY37_OR_GREATER: set_interval(prev_value) return ret
for name in patched_modules: del sys.modules[name] # import for side effects import _pydev_imps._pydev_saved_modules for name in patched_modules: sys.modules[name] = patched_modules[name] if USE_LIB_COPY: protect_libraries_from_patching() from _pydev_imps._pydev_saved_modules import thread _nextThreadIdLock = thread.allocate_lock() #======================================================================================================================= # Jython? #======================================================================================================================= try: dict_contains = dict.has_key except: try: #Py3k does not have has_key anymore, and older versions don't have __contains__ dict_contains = dict.__contains__ except: try: dict_contains = dict.has_key except NameError: def dict_contains(d, key):
def set_trace_to_threads(tracing_func, thread_idents=None, create_dummy_thread=True): assert tracing_func is not None ret = 0 # Note: use sys._current_frames() keys to get the thread ids because it'll return # thread ids created in C/C++ where there's user code running, unlike the APIs # from the threading module which see only threads created through it (unless # a call for threading.current_thread() was previously done in that thread, # in which case a dummy thread would've been created for it). if thread_idents is None: thread_idents = set(sys._current_frames().keys()) for t in threading.enumerate(): # PY-44778: ignore pydevd threads and also add any thread that wasn't found on # sys._current_frames() as some existing threads may not appear in # sys._current_frames() but may be available through the `threading` module. if getattr(t, 'pydev_do_not_trace', False): thread_idents.discard(t.ident) else: thread_idents.add(t.ident) curr_ident = thread.get_ident() curr_thread = threading._active.get(curr_ident) if curr_ident in thread_idents and len(thread_idents) != 1: # The current thread must be updated first (because we need to set # the reference to `curr_thread`). thread_idents = list(thread_idents) thread_idents.remove(curr_ident) thread_idents.insert(0, curr_ident) for thread_ident in thread_idents: # If that thread is not available in the threading module we also need to create a # dummy thread for it (otherwise it'll be invisible to the debugger). if create_dummy_thread: if thread_ident not in threading._active: class _DummyThread(threading._DummyThread): def _set_ident(self): # Note: Hack to set the thread ident that we want. if IS_PY2: self._Thread__ident = thread_ident else: self._ident = thread_ident t = _DummyThread() # Reset to the base class (don't expose our own version of the class). t.__class__ = threading._DummyThread if thread_ident == curr_ident: curr_thread = t with threading._active_limbo_lock: # On Py2 it'll put in active getting the current indent, not using the # ident that was set, so, we have to update it (should be harmless on Py3 # so, do it always). threading._active[thread_ident] = t threading._active[curr_ident] = curr_thread if t.ident != thread_ident: # Check if it actually worked. pydev_log.critical( 'pydevd: creation of _DummyThread with fixed thread ident did not succeed.' ) # Some (ptvsd) tests failed because of this, so, leave it always disabled for now. # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0 show_debug_info = 0 # Hack to increase _Py_TracingPossible. # See comments on py_custom_pyeval_settrace.hpp proceed = thread.allocate_lock() proceed.acquire() def dummy_trace(frame, event, arg): return dummy_trace def increase_tracing_count(): set_trace = TracingFunctionHolder._original_tracing or sys.settrace set_trace(dummy_trace) proceed.release() start_new_thread = pydev_monkey.get_original_start_new_thread(thread) start_new_thread(increase_tracing_count, ()) proceed.acquire() # Only proceed after the release() is done. proceed = None # Note: The set_trace_func is not really used anymore in the C side. set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace lib = _load_python_helper_lib() if lib is None: # This is the case if it's not CPython. pydev_log.info( 'Unable to load helper lib to set tracing to all threads (unsupported python vm).' ) ret = -1 else: try: result = lib.AttachDebuggerTracing( ctypes.c_int(show_debug_info), ctypes.py_object(set_trace_func), ctypes.py_object(tracing_func), ctypes.c_uint(thread_ident), ctypes.py_object(None), ) except: if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1: # There is no need to show this unless debug tracing is enabled. pydev_log.exception('Error attaching debugger tracing') ret = -1 else: if result != 0: pydev_log.info( 'Unable to set tracing for existing thread. Result: %s', result) ret = result return ret