gh-118332: Fix deadlock involving stop the world (#118412)

Avoid detaching thread state when stopping the world. When re-attaching
the thread state, the thread would attempt to resume the top-most
critical section, which might now be held by a thread paused for our
stop-the-world request.
This commit is contained in:
Sam Gross 2024-04-30 15:01:28 -04:00 committed by GitHub
parent 4a1cf66c5c
commit b2c3b70c71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 96 additions and 7 deletions

View file

@ -277,12 +277,12 @@ _PyEvent_Notify(PyEvent *evt)
void
PyEvent_Wait(PyEvent *evt)
{
while (!PyEvent_WaitTimed(evt, -1))
while (!PyEvent_WaitTimed(evt, -1, /*detach=*/1))
;
}
int
PyEvent_WaitTimed(PyEvent *evt, PyTime_t timeout_ns)
PyEvent_WaitTimed(PyEvent *evt, PyTime_t timeout_ns, int detach)
{
for (;;) {
uint8_t v = _Py_atomic_load_uint8(&evt->v);
@ -298,7 +298,7 @@ PyEvent_WaitTimed(PyEvent *evt, PyTime_t timeout_ns)
uint8_t expected = _Py_HAS_PARKED;
(void) _PyParkingLot_Park(&evt->v, &expected, sizeof(evt->v),
timeout_ns, NULL, 1);
timeout_ns, NULL, detach);
return _Py_atomic_load_uint8(&evt->v) == _Py_LOCKED;
}

View file

@ -2238,7 +2238,8 @@ stop_the_world(struct _stoptheworld_state *stw)
}
PyTime_t wait_ns = 1000*1000; // 1ms (arbitrary, may need tuning)
if (PyEvent_WaitTimed(&stw->stop_event, wait_ns)) {
int detach = 0;
if (PyEvent_WaitTimed(&stw->stop_event, wait_ns, detach)) {
assert(stw->thread_countdown == 0);
break;
}