]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
PyOS_AfterFork_Child() uses PyStatus (GH-20596)
authorVictor Stinner <vstinner@python.org>
Tue, 2 Jun 2020 13:51:37 +0000 (15:51 +0200)
committerGitHub <noreply@github.com>
Tue, 2 Jun 2020 13:51:37 +0000 (15:51 +0200)
PyOS_AfterFork_Child() helper functions now return a PyStatus:
PyOS_AfterFork_Child() is now responsible to handle errors.

* Move _PySignal_AfterFork() to the internal C API
* Add #ifdef HAVE_FORK on _PyGILState_Reinit(), _PySignal_AfterFork()
  and _PyInterpreterState_DeleteExceptMain().

Include/internal/pycore_ceval.h
Include/internal/pycore_import.h
Include/internal/pycore_pystate.h
Include/internal/pycore_runtime.h
Include/intrcheck.h
Modules/posixmodule.c
Modules/signalmodule.c
Python/ceval.c
Python/import.c
Python/pystate.c

index 368990099089fe2476201be003fd288b19583252..2da0154525b1ce9132d294665e6d10c90fb3a138 100644 (file)
@@ -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,
index b011ea4425112b13fc214de954f348df3f09f92b..35a67abebac6f7bc2b14b058ea82775aaed62cb3 100644 (file)
@@ -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);
 
index 7ac4ad5869b4c1c1b23d0f87880ffc54e1ffaefa..423c8113d7ac030e7d414c37c3591f2debb2768d 100644 (file)
@@ -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(
index ebdc12b23a9ca6144cdd20ad32b4bac8b355b8d6..3a01d64e63d81169eee262b2ce3b94c07d57f305 100644 (file)
@@ -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.
index e5bf5a834e44c8edda0158255214abed8503a2a9..88f2a7076ce3795053cf560ac9e9136948d225ca 100644 (file)
@@ -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 */
index 747184415e8bc79c97e893162b1ce97fe8e0b9a8..afb6d183077a1f4fd17acbfa45b709d2ec9cfe0c 100644 (file)
@@ -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
index 6d340a68634afc84778363cb76e14600f4bd8884..24dbd4255a6e4609daa28de7b330a69c5a42a638 100644 (file)
@@ -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)
index 01dd361e5035f4b7710ab1494c73c06eb393e799..5edcfe354054a62240cd64c064d0d39e3351125c 100644 (file)
@@ -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
 
index 0e2e7c370868fa13bb3cff2d18b3eae4bb31c818..35724fef37a6bfe62f1bb265dddd953344e7dac3 100644 (file)
@@ -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
 
index f92c55e7471697ce8b59fa3b7e0d768e84a36d6c..72d8b36342517299b7a15ee00a65780c31b0d1ff 100644 (file)
@@ -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 (main_interp_id_mutex < 0) {
-        Py_FatalError("Can't initialize ID lock for main interpreter");
-    }
+    if (reinit_interp < 0
+        || reinit_main_id < 0
+        || reinit_xidregistry < 0)
+    {
+        return _PyStatus_ERR("Failed to reinitialize runtime locks");
 
-    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