diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 36899009908..2da0154525b 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -25,7 +25,7 @@ PyAPI_FUNC(int) _PyEval_AddPendingCall( void *arg); PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate); #ifdef HAVE_FORK -extern void _PyEval_ReInitThreads(struct pyruntimestate *runtime); +extern PyStatus _PyEval_ReInitThreads(struct pyruntimestate *runtime); #endif PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth( PyThreadState *tstate, diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index b011ea44251..35a67abebac 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -11,7 +11,7 @@ PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin( ); #ifdef HAVE_FORK -extern void _PyImport_ReInitLock(void); +extern PyStatus _PyImport_ReInitLock(void); #endif extern void _PyImport_Cleanup(PyThreadState *tstate); diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 7ac4ad5869b..423c8113d7a 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -131,9 +131,12 @@ PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap( PyThreadState *newts); PyAPI_FUNC(PyStatus) _PyInterpreterState_Enable(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyGILState_Reinit(_PyRuntimeState *runtime); +#ifdef HAVE_FORK +extern PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime); +extern PyStatus _PyGILState_Reinit(_PyRuntimeState *runtime); +extern void _PySignal_AfterFork(void); +#endif PyAPI_FUNC(int) _PyState_AddModule( diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index ebdc12b23a9..3a01d64e63d 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -120,7 +120,7 @@ PyAPI_FUNC(PyStatus) _PyRuntimeState_Init(_PyRuntimeState *runtime); PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime); #ifdef HAVE_FORK -PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); +extern PyStatus _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); #endif /* Initialize _PyRuntimeState. diff --git a/Include/intrcheck.h b/Include/intrcheck.h index e5bf5a834e4..88f2a7076ce 100644 --- a/Include/intrcheck.h +++ b/Include/intrcheck.h @@ -1,4 +1,3 @@ - #ifndef Py_INTRCHECK_H #define Py_INTRCHECK_H #ifdef __cplusplus @@ -19,7 +18,6 @@ Py_DEPRECATED(3.7) PyAPI_FUNC(void) PyOS_AfterFork(void); #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyOS_IsMainThread(void); -PyAPI_FUNC(void) _PySignal_AfterFork(void); #ifdef MS_WINDOWS /* windows.h is not included by Python.h so use void* instead of HANDLE */ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 747184415e8..afb6d183077 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -34,6 +34,7 @@ #include "pycore_ceval.h" // _PyEval_ReInitThreads() #include "pycore_import.h" // _PyImport_ReInitLock() +#include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "structmember.h" // PyMemberDef #ifndef MS_WINDOWS @@ -461,15 +462,41 @@ PyOS_AfterFork_Parent(void) void PyOS_AfterFork_Child(void) { + PyStatus status; _PyRuntimeState *runtime = &_PyRuntime; - _PyGILState_Reinit(runtime); - _PyEval_ReInitThreads(runtime); - _PyImport_ReInitLock(); + + status = _PyGILState_Reinit(runtime); + if (_PyStatus_EXCEPTION(status)) { + goto fatal_error; + } + + status = _PyEval_ReInitThreads(runtime); + if (_PyStatus_EXCEPTION(status)) { + goto fatal_error; + } + + status = _PyImport_ReInitLock(); + if (_PyStatus_EXCEPTION(status)) { + goto fatal_error; + } + _PySignal_AfterFork(); - _PyRuntimeState_ReInitThreads(runtime); - _PyInterpreterState_DeleteExceptMain(runtime); + + status = _PyRuntimeState_ReInitThreads(runtime); + if (_PyStatus_EXCEPTION(status)) { + goto fatal_error; + } + + status = _PyInterpreterState_DeleteExceptMain(runtime); + if (_PyStatus_EXCEPTION(status)) { + goto fatal_error; + } run_at_forkers(_PyInterpreterState_GET()->after_forkers_child, 0); + return; + +fatal_error: + Py_ExitStatusException(status); } static int diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 6d340a68634..24dbd4255a6 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1796,14 +1796,17 @@ PyOS_InterruptOccurred(void) return 1; } + +#ifdef HAVE_FORK static void _clear_pending_signals(void) { - int i; - if (!_Py_atomic_load(&is_tripped)) + if (!_Py_atomic_load(&is_tripped)) { return; + } + _Py_atomic_store(&is_tripped, 0); - for (i = 1; i < NSIG; ++i) { + for (int i = 1; i < NSIG; ++i) { _Py_atomic_store_relaxed(&Handlers[i].tripped, 0); } } @@ -1816,6 +1819,8 @@ _PySignal_AfterFork(void) * the interpreter had an opportunity to call the handlers. issue9535. */ _clear_pending_signals(); } +#endif /* HAVE_FORK */ + int _PyOS_IsMainThread(void) diff --git a/Python/ceval.c b/Python/ceval.c index 01dd361e503..5edcfe35405 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -433,11 +433,9 @@ PyEval_ReleaseThread(PyThreadState *tstate) #ifdef HAVE_FORK /* This function is called from PyOS_AfterFork_Child to destroy all threads - * which are not running in the child process, and clear internal locks - * which might be held by those threads. - */ - -void + which are not running in the child process, and clear internal locks + which might be held by those threads. */ +PyStatus _PyEval_ReInitThreads(_PyRuntimeState *runtime) { PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); @@ -449,7 +447,7 @@ _PyEval_ReInitThreads(_PyRuntimeState *runtime) struct _gil_runtime_state *gil = &runtime->ceval.gil; #endif if (!gil_created(gil)) { - return; + return _PyStatus_OK(); } recreate_gil(gil); @@ -457,11 +455,12 @@ _PyEval_ReInitThreads(_PyRuntimeState *runtime) struct _pending_calls *pending = &tstate->interp->ceval.pending; if (_PyThread_at_fork_reinit(&pending->lock) < 0) { - Py_FatalError("Can't initialize threads for pending calls"); + return _PyStatus_ERR("Can't reinitialize pending calls lock"); } /* Destroy all threads except the current one */ _PyThreadState_DeleteExcept(runtime, tstate); + return _PyStatus_OK(); } #endif diff --git a/Python/import.c b/Python/import.c index 0e2e7c37086..35724fef37a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -148,7 +148,7 @@ _PyImportZip_Init(PyThreadState *tstate) in different threads to return with a partially loaded module. These calls are serialized by the global interpreter lock. */ -static PyThread_type_lock import_lock = 0; +static PyThread_type_lock import_lock = NULL; static unsigned long import_lock_thread = PYTHREAD_INVALID_THREAD_ID; static int import_lock_level = 0; @@ -171,7 +171,7 @@ _PyImport_AcquireLock(void) !PyThread_acquire_lock(import_lock, 0)) { PyThreadState *tstate = PyEval_SaveThread(); - PyThread_acquire_lock(import_lock, 1); + PyThread_acquire_lock(import_lock, WAIT_LOCK); PyEval_RestoreThread(tstate); } assert(import_lock_level == 0); @@ -197,19 +197,19 @@ _PyImport_ReleaseLock(void) } #ifdef HAVE_FORK -/* This function is called from PyOS_AfterFork_Child to ensure that newly +/* This function is called from PyOS_AfterFork_Child() to ensure that newly created child processes do not share locks with the parent. We now acquire the import lock around fork() calls but on some platforms (Solaris 9 and earlier? see isue7242) that still left us with problems. */ - -void +PyStatus _PyImport_ReInitLock(void) { if (import_lock != NULL) { if (_PyThread_at_fork_reinit(&import_lock) < 0) { - _Py_FatalErrorFunc(__func__, "failed to create a new lock"); + return _PyStatus_ERR("failed to create a new lock"); } } + if (import_lock_level > 1) { /* Forked as a side effect of import */ unsigned long me = PyThread_get_thread_ident(); @@ -224,6 +224,7 @@ _PyImport_ReInitLock(void) import_lock_thread = PYTHREAD_INVALID_THREAD_ID; import_lock_level = 0; } + return _PyStatus_OK(); } #endif diff --git a/Python/pystate.c b/Python/pystate.c index f92c55e7471..72d8b363425 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -124,10 +124,8 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) #ifdef HAVE_FORK /* This function is called from PyOS_AfterFork_Child to ensure that - * newly created child processes do not share locks with the parent. - */ - -void + newly created child processes do not share locks with the parent. */ +PyStatus _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) { // This was initially set in _PyRuntimeState_Init(). @@ -138,23 +136,20 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - int interp_mutex = _PyThread_at_fork_reinit(&runtime->interpreters.mutex); - int main_interp_id_mutex = _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex); - int xidregistry_mutex = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex); + int reinit_interp = _PyThread_at_fork_reinit(&runtime->interpreters.mutex); + int reinit_main_id = _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex); + int reinit_xidregistry = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - if (interp_mutex < 0) { - Py_FatalError("Can't initialize lock for runtime interpreters"); - } + if (reinit_interp < 0 + || reinit_main_id < 0 + || reinit_xidregistry < 0) + { + return _PyStatus_ERR("Failed to reinitialize runtime locks"); - if (main_interp_id_mutex < 0) { - Py_FatalError("Can't initialize ID lock for main interpreter"); - } - - if (xidregistry_mutex < 0) { - Py_FatalError("Can't initialize lock for cross-interpreter data registry"); } + return _PyStatus_OK(); } #endif @@ -373,11 +368,12 @@ PyInterpreterState_Delete(PyInterpreterState *interp) } +#ifdef HAVE_FORK /* * Delete all interpreter states except the main interpreter. If there * is a current interpreter state, it *must* be the main interpreter. */ -void +PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) { struct _gilstate_runtime_state *gilstate = &runtime->gilstate; @@ -385,7 +381,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) PyThreadState *tstate = _PyThreadState_Swap(gilstate, NULL); if (tstate != NULL && tstate->interp != interpreters->main) { - Py_FatalError("not main interpreter"); + return _PyStatus_ERR("not main interpreter"); } HEAD_LOCK(runtime); @@ -411,10 +407,12 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) HEAD_UNLOCK(runtime); if (interpreters->head == NULL) { - Py_FatalError("missing main interpreter"); + return _PyStatus_ERR("missing main interpreter"); } _PyThreadState_Swap(gilstate, tstate); + return _PyStatus_OK(); } +#endif PyInterpreterState * @@ -1259,11 +1257,12 @@ _PyGILState_Fini(PyThreadState *tstate) gilstate->autoInterpreterState = NULL; } +#ifdef HAVE_FORK /* Reset the TSS key - called by PyOS_AfterFork_Child(). * This should not be necessary, but some - buggy - pthread implementations * don't reset TSS upon fork(), see issue #10517. */ -void +PyStatus _PyGILState_Reinit(_PyRuntimeState *runtime) { struct _gilstate_runtime_state *gilstate = &runtime->gilstate; @@ -1271,7 +1270,7 @@ _PyGILState_Reinit(_PyRuntimeState *runtime) PyThread_tss_delete(&gilstate->autoTSSkey); if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) { - Py_FatalError("Could not allocate TSS entry"); + return _PyStatus_NO_MEMORY(); } /* If the thread had an associated auto thread state, reassociate it with @@ -1279,9 +1278,11 @@ _PyGILState_Reinit(_PyRuntimeState *runtime) if (tstate && PyThread_tss_set(&gilstate->autoTSSkey, (void *)tstate) != 0) { - Py_FatalError("Couldn't create autoTSSkey mapping"); + return _PyStatus_ERR("failed to set autoTSSkey"); } + return _PyStatus_OK(); } +#endif /* When a thread state is created for a thread by some mechanism other than PyGILState_Ensure, it's important that the GILState machinery knows about