(tracing_func, thread_idents=None, create_dummy_thread=True)
| 294 | |
| 295 | |
| 296 | def set_trace_to_threads(tracing_func, thread_idents=None, create_dummy_thread=True): |
| 297 | if PYDEVD_USE_SYS_MONITORING: |
| 298 | raise RuntimeError("Should not be called when using sys.monitoring.") |
| 299 | assert tracing_func is not None |
| 300 | |
| 301 | ret = 0 |
| 302 | |
| 303 | # Note: use sys._current_frames() keys to get the thread ids because it'll return |
| 304 | # thread ids created in C/C++ where there's user code running, unlike the APIs |
| 305 | # from the threading module which see only threads created through it (unless |
| 306 | # a call for threading.current_thread() was previously done in that thread, |
| 307 | # in which case a dummy thread would've been created for it). |
| 308 | if thread_idents is None: |
| 309 | thread_idents = set(sys._current_frames().keys()) |
| 310 | |
| 311 | for t in threading.enumerate(): |
| 312 | # PY-44778: ignore pydevd threads and also add any thread that wasn't found on |
| 313 | # sys._current_frames() as some existing threads may not appear in |
| 314 | # sys._current_frames() but may be available through the `threading` module. |
| 315 | if getattr(t, "pydev_do_not_trace", False): |
| 316 | thread_idents.discard(t.ident) |
| 317 | else: |
| 318 | thread_idents.add(t.ident) |
| 319 | |
| 320 | curr_ident = thread.get_ident() |
| 321 | curr_thread = threading._active.get(curr_ident) |
| 322 | |
| 323 | if curr_ident in thread_idents and len(thread_idents) != 1: |
| 324 | # The current thread must be updated first (because we need to set |
| 325 | # the reference to `curr_thread`). |
| 326 | thread_idents = list(thread_idents) |
| 327 | thread_idents.remove(curr_ident) |
| 328 | thread_idents.insert(0, curr_ident) |
| 329 | |
| 330 | for thread_ident in thread_idents: |
| 331 | # If that thread is not available in the threading module we also need to create a |
| 332 | # dummy thread for it (otherwise it'll be invisible to the debugger). |
| 333 | if create_dummy_thread: |
| 334 | if thread_ident not in threading._active: |
| 335 | |
| 336 | class _DummyThread(threading._DummyThread): |
| 337 | def _set_ident(self): |
| 338 | # Note: Hack to set the thread ident that we want. |
| 339 | self._ident = thread_ident |
| 340 | |
| 341 | t = _DummyThread() |
| 342 | # Reset to the base class (don't expose our own version of the class). |
| 343 | t.__class__ = threading._DummyThread |
| 344 | |
| 345 | if thread_ident == curr_ident: |
| 346 | curr_thread = t |
| 347 | |
| 348 | with threading._active_limbo_lock: |
| 349 | # On Py2 it'll put in active getting the current indent, not using the |
| 350 | # ident that was set, so, we have to update it (should be harmless on Py3 |
| 351 | # so, do it always). |
| 352 | threading._active[thread_ident] = t |
| 353 | threading._active[curr_ident] = curr_thread |
no test coverage detected