gh-114423: Remove DummyThread from threading._active when thread dies (GH-114424)

This commit is contained in:
Fabio Zadrozny 2024-01-23 09:12:50 -03:00 committed by GitHub
parent 7d21cae964
commit 5a1ecc8cc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 28 deletions

View file

@ -54,6 +54,13 @@ except AttributeError:
TIMEOUT_MAX = _thread.TIMEOUT_MAX
del _thread
# get thread-local implementation, either from the thread
# module, or from the python fallback
try:
from _thread import _local as local
except ImportError:
from _threading_local import local
# Support for profile and trace hooks
@ -1476,10 +1483,36 @@ class _MainThread(Thread):
_active[self._ident] = self
# Helper thread-local instance to detect when a _DummyThread
# is collected. Not a part of the public API.
_thread_local_info = local()
class _DeleteDummyThreadOnDel:
'''
Helper class to remove a dummy thread from threading._active on __del__.
'''
def __init__(self, dummy_thread):
self._dummy_thread = dummy_thread
self._tident = dummy_thread.ident
# Put the thread on a thread local variable so that when
# the related thread finishes this instance is collected.
#
# Note: no other references to this instance may be created.
# If any client code creates a reference to this instance,
# the related _DummyThread will be kept forever!
_thread_local_info._track_dummy_thread_ref = self
def __del__(self):
with _active_limbo_lock:
if _active.get(self._tident) is self._dummy_thread:
_active.pop(self._tident, None)
# Dummy thread class to represent threads not started here.
# These aren't garbage collected when they die, nor can they be waited for.
# If they invoke anything in threading.py that calls current_thread(), they
# leave an entry in the _active dict forever after.
# These should be added to `_active` and removed automatically
# when they die, although they can't be waited for.
# Their purpose is to return *something* from current_thread().
# They are marked as daemon threads so we won't wait for them
# when we exit (conform previous semantics).
@ -1495,6 +1528,7 @@ class _DummyThread(Thread):
self._set_native_id()
with _active_limbo_lock:
_active[self._ident] = self
_DeleteDummyThreadOnDel(self)
def _stop(self):
pass
@ -1676,14 +1710,6 @@ def main_thread():
# XXX Figure this out for subinterpreters. (See gh-75698.)
return _main_thread
# get thread-local implementation, either from the thread
# module, or from the python fallback
try:
from _thread import _local as local
except ImportError:
from _threading_local import local
def _after_fork():
"""