Skip to content

Commit c1befd7

Browse files
committed
Stop the world before fork() and Python shutdown
1 parent 2864b6b commit c1befd7

File tree

2 files changed

+21
-5
lines changed

2 files changed

+21
-5
lines changed

Modules/posixmodule.c

+15-5
Original file line numberDiff line numberDiff line change
@@ -572,11 +572,18 @@ PyOS_BeforeFork(void)
572572
run_at_forkers(_PyInterpreterState_GET()->before_forkers, 1);
573573

574574
_PyImport_AcquireLock();
575+
576+
// Stop all other threads still attached to the Python VM.
577+
_PyRuntimeState_StopTheWorld(&_PyRuntime);
578+
HEAD_LOCK(&_PyRuntime);
575579
}
576580

577581
void
578582
PyOS_AfterFork_Parent(void)
579583
{
584+
HEAD_UNLOCK(&_PyRuntime);
585+
_PyRuntimeState_StartTheWorld(&_PyRuntime);
586+
580587
if (_PyImport_ReleaseLock() <= 0)
581588
Py_FatalError("failed releasing import lock after fork");
582589

@@ -606,6 +613,12 @@ PyOS_AfterFork_Child(void)
606613
tstate->native_thread_id = PyThread_get_thread_native_id();
607614
#endif
608615

616+
// re-creates runtime->interpreters.mutex (HEAD_UNLOCK)
617+
status = _PyRuntimeState_ReInitThreads(runtime);
618+
if (_PyStatus_EXCEPTION(status)) {
619+
goto fatal_error;
620+
}
621+
609622
status = _PyEval_ReInitThreads(tstate);
610623
if (_PyStatus_EXCEPTION(status)) {
611624
goto fatal_error;
@@ -619,13 +632,10 @@ PyOS_AfterFork_Child(void)
619632
_PySignal_AfterFork();
620633
_Py_queue_after_fork();
621634

622-
status = _PyRuntimeState_ReInitThreads(runtime);
623-
if (_PyStatus_EXCEPTION(status)) {
624-
goto fatal_error;
625-
}
626-
627635
PyThreadState *garbage = _PyThreadState_UnlinkExcept(runtime, tstate, 1);
628636

637+
_PyRuntimeState_StartTheWorld(runtime);
638+
629639
status = _PyInterpreterState_DeleteExceptMain(runtime);
630640
if (_PyStatus_EXCEPTION(status)) {
631641
goto fatal_error;

Python/pylifecycle.c

+6
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,12 @@ Py_FinalizeEx(void)
18671867
runtime->initialized = 0;
18681868
runtime->core_initialized = 0;
18691869

1870+
/* Wait until all daemon threads exit. Release the stoptheworld_mutex
1871+
afterwards because we're going to attempt further stop-the-worlds
1872+
via GC calls. */
1873+
_PyRuntimeState_StopTheWorld(runtime);
1874+
_PyMutex_unlock(&runtime->stoptheworld_mutex);
1875+
18701876
/* Destroy the state of all threads of the interpreter, except of the
18711877
current thread. In practice, only daemon threads should still be alive,
18721878
except if wait_for_thread_shutdown() has been cancelled by CTRL+C.

0 commit comments

Comments
 (0)