Skip to content

Commit f1460af

Browse files
committed
Serialize pending calls via the ceval mutex.
Py_AddPendingCall() can be called without an attached thread state, so we can't rely on stop-the-world or the GIL for it. Instead, acquire its dedicated mutex to prevent threads from creating new pending calls.
1 parent 2dda7a4 commit f1460af

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

Python/pylifecycle.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,8 +2056,15 @@ make_pre_finalization_calls(PyThreadState *tstate)
20562056

20572057
_PyAtExit_Call(tstate->interp);
20582058

2059+
/* Stop the world to prevent other threads from creating threads or
2060+
* atexit callbacks. On the default build, this is simply locked by
2061+
* the GIL. For pending calls, we acquire the dedicated mutex, because
2062+
* Py_AddPendingCall() can be called without an attached thread state.
2063+
*/
2064+
20592065
// XXX Why does _PyThreadState_DeleteList() rely on all interpreters
20602066
// being stopped?
2067+
PyMutex_Lock(&interp->ceval.pending.mutex);
20612068
_PyEval_StopTheWorldAll(interp->runtime);
20622069
int should_continue = (interp_has_threads(interp)
20632070
|| interp_has_atexit_callbacks(interp)
@@ -2066,6 +2073,7 @@ make_pre_finalization_calls(PyThreadState *tstate)
20662073
break;
20672074
}
20682075
_PyEval_StartTheWorldAll(interp->runtime);
2076+
PyMutex_Unlock(&interp->ceval.pending.mutex);
20692077
}
20702078
assert(interp->runtime->stoptheworld.world_stopped);
20712079
}
@@ -2125,6 +2133,7 @@ _Py_Finalize(_PyRuntimeState *runtime)
21252133
_PyThreadState_SetShuttingDown(p);
21262134
}
21272135
_PyEval_StartTheWorldAll(runtime);
2136+
PyMutex_Unlock(&tstate->interp->ceval.pending.mutex);
21282137

21292138
/* Clear frames of other threads to call objects destructors. Destructors
21302139
will be called in the current Python thread. Since
@@ -2496,6 +2505,7 @@ Py_EndInterpreter(PyThreadState *tstate)
24962505
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
24972506
_PyInterpreterState_SetFinalizing(interp, tstate);
24982507
_PyEval_StartTheWorldAll(interp->runtime);
2508+
PyMutex_Unlock(&interp->ceval.pending.mutex);
24992509

25002510
// XXX Call something like _PyImport_Disable() here?
25012511

0 commit comments

Comments
 (0)