[3.13] gh-122201: Lock mutex when setting handling_thread to NULL (GH-122204) (#122319)

In the free-threaded build, we need to lock pending->mutex when clearing
the handling_thread in order not to race with a concurrent
make_pending_calls in the same interpreter.
(cherry picked from commit c557ae97d6)

Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
Miss Islington (bot) 2024-07-26 19:30:08 +02:00 committed by GitHub
parent 816a1572e5
commit 9d5dde5006
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 15 additions and 4 deletions

View File

@ -901,6 +901,18 @@ unsignal_pending_calls(PyThreadState *tstate, PyInterpreterState *interp)
#endif #endif
} }
static void
clear_pending_handling_thread(struct _pending_calls *pending)
{
#ifdef Py_GIL_DISABLED
PyMutex_Lock(&pending->mutex);
pending->handling_thread = NULL;
PyMutex_Unlock(&pending->mutex);
#else
pending->handling_thread = NULL;
#endif
}
static int static int
make_pending_calls(PyThreadState *tstate) make_pending_calls(PyThreadState *tstate)
{ {
@ -933,7 +945,7 @@ make_pending_calls(PyThreadState *tstate)
int32_t npending; int32_t npending;
if (_make_pending_calls(pending, &npending) != 0) { if (_make_pending_calls(pending, &npending) != 0) {
pending->handling_thread = NULL; clear_pending_handling_thread(pending);
/* There might not be more calls to make, but we play it safe. */ /* There might not be more calls to make, but we play it safe. */
signal_pending_calls(tstate, interp); signal_pending_calls(tstate, interp);
return -1; return -1;
@ -945,7 +957,7 @@ make_pending_calls(PyThreadState *tstate)
if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) {
if (_make_pending_calls(pending_main, &npending) != 0) { if (_make_pending_calls(pending_main, &npending) != 0) {
pending->handling_thread = NULL; clear_pending_handling_thread(pending);
/* There might not be more calls to make, but we play it safe. */ /* There might not be more calls to make, but we play it safe. */
signal_pending_calls(tstate, interp); signal_pending_calls(tstate, interp);
return -1; return -1;
@ -956,7 +968,7 @@ make_pending_calls(PyThreadState *tstate)
} }
} }
pending->handling_thread = NULL; clear_pending_handling_thread(pending);
return 0; return 0;
} }

View File

@ -28,7 +28,6 @@ race_top:assign_version_tag
race_top:new_reference race_top:new_reference
race_top:_multiprocessing_SemLock_acquire_impl race_top:_multiprocessing_SemLock_acquire_impl
race_top:list_get_item_ref race_top:list_get_item_ref
race_top:make_pending_calls
race_top:_Py_slot_tp_getattr_hook race_top:_Py_slot_tp_getattr_hook
race_top:add_threadstate race_top:add_threadstate
race_top:dump_traceback race_top:dump_traceback