gh-144513: Skip critical section locking during stop-the-world (gh-144524)

When the interpreter is in a stop-the-world pause, critical sections
don't need to acquire locks since no other threads can be running.
This avoids a potential deadlock where lock fairness hands off ownership
to a thread that has already suspended for stop-the-world.
This commit is contained in:
Sam Gross 2026-02-06 10:14:08 -05:00 committed by GitHub
parent 5bb3bbb9c6
commit 0fdf6a9a71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 103 additions and 1 deletions

View file

@ -1,7 +1,8 @@
#include "Python.h"
#include "pycore_lock.h"
#include "pycore_critical_section.h"
#include "pycore_interp.h"
#include "pycore_lock.h"
#ifdef Py_GIL_DISABLED
static_assert(_Alignof(PyCriticalSection) >= 4,
@ -42,6 +43,15 @@ _PyCriticalSection_BeginSlow(PyThreadState *tstate, PyCriticalSection *c, PyMute
}
}
}
// If the world is stopped, we don't need to acquire the lock because
// there are no other threads that could be accessing the object.
// Without this check, acquiring a critical section while the world is
// stopped could lead to a deadlock.
if (tstate->interp->stoptheworld.world_stopped) {
c->_cs_mutex = NULL;
c->_cs_prev = 0;
return;
}
c->_cs_mutex = NULL;
c->_cs_prev = (uintptr_t)tstate->critical_section;
tstate->critical_section = (uintptr_t)c;
@ -56,6 +66,12 @@ _PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMu
int is_m1_locked)
{
#ifdef Py_GIL_DISABLED
if (tstate->interp->stoptheworld.world_stopped) {
c->_cs_base._cs_mutex = NULL;
c->_cs_mutex2 = NULL;
c->_cs_base._cs_prev = 0;
return;
}
c->_cs_base._cs_mutex = NULL;
c->_cs_mutex2 = NULL;
c->_cs_base._cs_prev = tstate->critical_section;