Skip to content

Commit 4d96b46

Browse files
authored
bpo-39511: PyThreadState_Clear() calls on_delete (GH-18296)
PyThreadState.on_delete is a callback used to notify Python when a thread completes. _thread._set_sentinel() function creates a lock which is released when the thread completes. It sets on_delete callback to the internal release_sentinel() function. This lock is known as Threading._tstate_lock in the threading module. The release_sentinel() function uses the Python C API. The problem is that on_delete is called late in the Python finalization, when the C API is no longer fully working. The PyThreadState_Clear() function now calls the PyThreadState.on_delete callback. Previously, that happened in PyThreadState_Delete(). The release_sentinel() function is now called when the C API is still fully working.
1 parent 7dc1401 commit 4d96b46

File tree

3 files changed

+12
-3
lines changed

3 files changed

+12
-3
lines changed

Doc/c-api/init.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
10481048
Reset all information in a thread state object. The global interpreter lock
10491049
must be held.
10501050
1051+
.. versionchanged:: 3.9
1052+
This function now calls the :c:member:`PyThreadState.on_delete` callback.
1053+
Previously, that happened in :c:func:`PyThreadState_Delete`.
1054+
10511055
10521056
.. c:function:: void PyThreadState_Delete(PyThreadState *tstate)
10531057
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The :c:func:`PyThreadState_Clear` function now calls the
2+
:c:member:`PyThreadState.on_delete` callback. Previously, that happened in
3+
:c:func:`PyThreadState_Delete`.

Python/pystate.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,10 @@ PyThreadState_Clear(PyThreadState *tstate)
806806
Py_CLEAR(tstate->async_gen_finalizer);
807807

808808
Py_CLEAR(tstate->context);
809+
810+
if (tstate->on_delete != NULL) {
811+
tstate->on_delete(tstate->on_delete_data);
812+
}
809813
}
810814

811815

@@ -830,9 +834,7 @@ tstate_delete_common(PyThreadState *tstate,
830834
if (tstate->next)
831835
tstate->next->prev = tstate->prev;
832836
HEAD_UNLOCK(runtime);
833-
if (tstate->on_delete != NULL) {
834-
tstate->on_delete(tstate->on_delete_data);
835-
}
837+
836838
PyMem_RawFree(tstate);
837839

838840
if (gilstate->autoInterpreterState &&

0 commit comments

Comments
 (0)