@@ -613,11 +613,16 @@ PyOS_BeforeFork(void)
613
613
run_at_forkers (interp -> before_forkers , 1 );
614
614
615
615
_PyImport_AcquireLock (interp );
616
+ _PyEval_StopTheWorldAll (& _PyRuntime );
617
+ HEAD_LOCK (& _PyRuntime );
616
618
}
617
619
618
620
void
619
621
PyOS_AfterFork_Parent (void )
620
622
{
623
+ HEAD_UNLOCK (& _PyRuntime );
624
+ _PyEval_StartTheWorldAll (& _PyRuntime );
625
+
621
626
PyInterpreterState * interp = _PyInterpreterState_GET ();
622
627
if (_PyImport_ReleaseLock (interp ) <= 0 ) {
623
628
Py_FatalError ("failed releasing import lock after fork" );
@@ -632,6 +637,7 @@ PyOS_AfterFork_Child(void)
632
637
PyStatus status ;
633
638
_PyRuntimeState * runtime = & _PyRuntime ;
634
639
640
+ // re-creates runtime->interpreters.mutex (HEAD_UNLOCK)
635
641
status = _PyRuntimeState_ReInitThreads (runtime );
636
642
if (_PyStatus_EXCEPTION (status )) {
637
643
goto fatal_error ;
@@ -7731,10 +7737,15 @@ os_register_at_fork_impl(PyObject *module, PyObject *before,
7731
7737
// running in the process. Best effort, silent if unable to count threads.
7732
7738
// Constraint: Quick. Never overcounts. Never leaves an error set.
7733
7739
//
7734
- // This code might do an import, thus acquiring the import lock, which
7735
- // PyOS_BeforeFork() also does. As this should only be called from
7736
- // the parent process, it is in the same thread so that works.
7737
- static void warn_about_fork_with_threads (const char * name ) {
7740
+ // This should only be called from the parent process after
7741
+ // PyOS_AfterFork_Parent().
7742
+ static void
7743
+ warn_about_fork_with_threads (const char * name )
7744
+ {
7745
+ // It's not safe to issue the warning while the world is stopped, because
7746
+ // other threads might be holding locks that we need, which would deadlock.
7747
+ assert (!_PyRuntime .stoptheworld .world_stopped );
7748
+
7738
7749
// TODO: Consider making an `os` module API to return the current number
7739
7750
// of threads in the process. That'd presumably use this platform code but
7740
7751
// raise an error rather than using the inaccurate fallback.
@@ -7858,9 +7869,10 @@ os_fork1_impl(PyObject *module)
7858
7869
/* child: this clobbers and resets the import lock. */
7859
7870
PyOS_AfterFork_Child ();
7860
7871
} else {
7861
- warn_about_fork_with_threads ("fork1" );
7862
7872
/* parent: release the import lock. */
7863
7873
PyOS_AfterFork_Parent ();
7874
+ // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
7875
+ warn_about_fork_with_threads ("fork1" );
7864
7876
}
7865
7877
if (pid == -1 ) {
7866
7878
errno = saved_errno ;
@@ -7906,9 +7918,10 @@ os_fork_impl(PyObject *module)
7906
7918
/* child: this clobbers and resets the import lock. */
7907
7919
PyOS_AfterFork_Child ();
7908
7920
} else {
7909
- warn_about_fork_with_threads ("fork" );
7910
7921
/* parent: release the import lock. */
7911
7922
PyOS_AfterFork_Parent ();
7923
+ // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
7924
+ warn_about_fork_with_threads ("fork" );
7912
7925
}
7913
7926
if (pid == -1 ) {
7914
7927
errno = saved_errno ;
@@ -8737,9 +8750,10 @@ os_forkpty_impl(PyObject *module)
8737
8750
/* child: this clobbers and resets the import lock. */
8738
8751
PyOS_AfterFork_Child ();
8739
8752
} else {
8740
- warn_about_fork_with_threads ("forkpty" );
8741
8753
/* parent: release the import lock. */
8742
8754
PyOS_AfterFork_Parent ();
8755
+ // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
8756
+ warn_about_fork_with_threads ("forkpty" );
8743
8757
}
8744
8758
if (pid == -1 ) {
8745
8759
return posix_error ();
0 commit comments