Skip to content

gh-104341: Clean Up threading Module #104552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

26 changes: 0 additions & 26 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,32 +188,6 @@ struct _ts {

struct _py_trashcan trash;

/* Called when a thread state is deleted normally, but not when it
* is destroyed after fork().
* Pain: to prevent rare but fatal shutdown errors (issue 18808),
* Thread.join() must wait for the join'ed thread's tstate to be unlinked
* from the tstate chain. That happens at the end of a thread's life,
* in pystate.c.
* The obvious way doesn't quite work: create a lock which the tstate
* unlinking code releases, and have Thread.join() wait to acquire that
* lock. The problem is that we _are_ at the end of the thread's life:
* if the thread holds the last reference to the lock, decref'ing the
* lock will delete the lock, and that may trigger arbitrary Python code
* if there's a weakref, with a callback, to the lock. But by this time
* _PyRuntime.gilstate.tstate_current is already NULL, so only the simplest
* of C code can be allowed to run (in particular it must not be possible to
* release the GIL).
* So instead of holding the lock directly, the tstate holds a weakref to
* the lock: that's the value of on_delete_data below. Decref'ing a
* weakref is harmless.
* on_delete points to _threadmodule.c's static release_sentinel() function.
* After the tstate is unlinked, release_sentinel is called with the
* weakref-to-lock (on_delete_data) argument, and release_sentinel releases
* the indirectly held lock.
*/
void (*on_delete)(void *);
void *on_delete_data;

int coroutine_origin_tracking_depth;

PyObject *async_gen_firstiter;
Expand Down
2 changes: 0 additions & 2 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ struct _is {
uint64_t next_unique_id;
/* The linked list of threads, newest first. */
PyThreadState *head;
/* Used in Modules/_threadmodule.c. */
long count;
/* Support for runtime thread stack size tuning.
A value of 0 means using the platform's default stack size
or the size specified by the THREAD_STACK_SIZE macro. */
Expand Down
9 changes: 6 additions & 3 deletions Lib/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
except AttributeError:
_CRLock = None
TIMEOUT_MAX = _thread.TIMEOUT_MAX
_internal_after_fork = _thread._after_fork
del _thread


Expand Down Expand Up @@ -1143,9 +1144,7 @@ def _wait_for_tstate_lock(self, block=True, timeout=-1):
return

try:
if lock.acquire(block, timeout):
lock.release()
self._stop()
locked = lock.acquire(block, timeout)
except:
if lock.locked():
# bpo-45274: lock.acquire() acquired the lock, but the function
Expand All @@ -1155,6 +1154,9 @@ def _wait_for_tstate_lock(self, block=True, timeout=-1):
lock.release()
self._stop()
raise
if locked:
lock.release()
self._stop()

@property
def name(self):
Expand Down Expand Up @@ -1677,4 +1679,5 @@ def _after_fork():


if hasattr(_os, "register_at_fork"):
_os.register_at_fork(after_in_child=_internal_after_fork)
_os.register_at_fork(after_in_child=_after_fork)
Loading