From b930a2d2b1247bdba560db341ba90a9cbb538eb3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 24 Apr 2019 17:14:33 +0200 Subject: bpo-36710: PyOS_AfterFork_Child() pass runtime parameter (GH-12936) The PyOS_AfterFork_Child() function now pass a 'runtime' parameter to subfunctions. * Fix _PyRuntimeState_ReInitThreads(): use the correct memory allocator * Add runtime parameter to _PyRuntimeState_ReInitThreads(), _PyGILState_Reinit() and _PyInterpreterState_DeleteExceptMain() * Move _PyGILState_Reinit() to the internal C API. --- Include/cpython/pystate.h | 1 - Include/internal/pycore_pystate.h | 12 +++++--- Modules/posixmodule.c | 7 +++-- Python/pystate.c | 65 +++++++++++++++++++-------------------- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 2341dda..94331f3 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -155,7 +155,6 @@ PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_Get(void); PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*); PyAPI_FUNC(void) _PyState_ClearModules(void); PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); -PyAPI_FUNC(void) _PyGILState_Reinit(void); /* Similar to PyThreadState_Get(), but don't issue a fatal error * if it is NULL. */ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 509ca36..2c24f67 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -185,9 +185,9 @@ typedef struct pyruntimestate { /* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ PyAPI_DATA(_PyRuntimeState) _PyRuntime; -PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *); -PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *); -PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(void); +PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *runtime); +PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime); +PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); /* Initialize _PyRuntimeState. Return NULL on success, or return an error message on failure. */ @@ -236,8 +236,10 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); -PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *); -PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(void); +PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *runtime); +PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime); + +PyAPI_FUNC(void) _PyGILState_Reinit(_PyRuntimeState *runtime); #ifdef __cplusplus } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e8dbdcc..56ec3ee 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -421,12 +421,13 @@ PyOS_AfterFork_Parent(void) void PyOS_AfterFork_Child(void) { - _PyGILState_Reinit(); - _PyInterpreterState_DeleteExceptMain(); + _PyRuntimeState *runtime = &_PyRuntime; + _PyGILState_Reinit(runtime); + _PyInterpreterState_DeleteExceptMain(runtime); PyEval_ReInitThreads(); _PyImport_ReInitLock(); _PySignal_AfterFork(); - _PyRuntimeState_ReInitThreads(); + _PyRuntimeState_ReInitThreads(runtime); run_at_forkers(_PyInterpreterState_Get()->after_forkers_child, 0); } diff --git a/Python/pystate.c b/Python/pystate.c index ef9d792..6aaf993 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -108,23 +108,31 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) */ void -_PyRuntimeState_ReInitThreads(void) +_PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) { // This was initially set in _PyRuntimeState_Init(). - _PyRuntime.main_thread = PyThread_get_thread_ident(); + runtime->main_thread = PyThread_get_thread_ident(); + + /* Force default allocator, since _PyRuntimeState_Fini() must + use the same allocator than this function. */ + PyMemAllocatorEx old_alloc; + _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + + runtime->interpreters.mutex = PyThread_allocate_lock(); + runtime->interpreters.main->id_mutex = PyThread_allocate_lock(); + runtime->xidregistry.mutex = PyThread_allocate_lock(); + + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - _PyRuntime.interpreters.mutex = PyThread_allocate_lock(); - if (_PyRuntime.interpreters.mutex == NULL) { + if (runtime->interpreters.mutex == NULL) { Py_FatalError("Can't initialize lock for runtime interpreters"); } - _PyRuntime.interpreters.main->id_mutex = PyThread_allocate_lock(); - if (_PyRuntime.interpreters.main->id_mutex == NULL) { + if (runtime->interpreters.main->id_mutex == NULL) { Py_FatalError("Can't initialize ID lock for main interpreter"); } - _PyRuntime.xidregistry.mutex = PyThread_allocate_lock(); - if (_PyRuntime.xidregistry.mutex == NULL) { + if (runtime->xidregistry.mutex == NULL) { Py_FatalError("Can't initialize lock for cross-interpreter data registry"); } } @@ -290,20 +298,22 @@ PyInterpreterState_Delete(PyInterpreterState *interp) * is a current interpreter state, it *must* be the main interpreter. */ void -_PyInterpreterState_DeleteExceptMain() +_PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) { + struct pyinterpreters *interpreters = &runtime->interpreters; + PyThreadState *tstate = PyThreadState_Swap(NULL); - if (tstate != NULL && tstate->interp != _PyRuntime.interpreters.main) { + if (tstate != NULL && tstate->interp != interpreters->main) { Py_FatalError("PyInterpreterState_DeleteExceptMain: not main interpreter"); } HEAD_LOCK(); - PyInterpreterState *interp = _PyRuntime.interpreters.head; - _PyRuntime.interpreters.head = NULL; + PyInterpreterState *interp = interpreters->head; + interpreters->head = NULL; while (interp != NULL) { - if (interp == _PyRuntime.interpreters.main) { - _PyRuntime.interpreters.main->next = NULL; - _PyRuntime.interpreters.head = interp; + if (interp == interpreters->main) { + interpreters->main->next = NULL; + interpreters->head = interp; interp = interp->next; continue; } @@ -319,7 +329,7 @@ _PyInterpreterState_DeleteExceptMain() } HEAD_UNLOCK(); - if (_PyRuntime.interpreters.head == NULL) { + if (interpreters->head == NULL) { Py_FatalError("PyInterpreterState_DeleteExceptMain: missing main"); } PyThreadState_Swap(tstate); @@ -1079,31 +1089,20 @@ _PyGILState_Fini(void) * don't reset TSS upon fork(), see issue #10517. */ void -_PyGILState_Reinit(void) +_PyGILState_Reinit(_PyRuntimeState *runtime) { - /* Force default allocator, since _PyRuntimeState_Fini() must - use the same allocator than this function. */ - PyMemAllocatorEx old_alloc; - _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - - _PyRuntime.interpreters.mutex = PyThread_allocate_lock(); - - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - - if (_PyRuntime.interpreters.mutex == NULL) { - Py_FatalError("Can't initialize threads for interpreter"); - } - + struct _gilstate_runtime_state *gilstate = &runtime->gilstate; PyThreadState *tstate = PyGILState_GetThisThreadState(); - PyThread_tss_delete(&_PyRuntime.gilstate.autoTSSkey); - if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) { + + PyThread_tss_delete(&gilstate->autoTSSkey); + if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) { Py_FatalError("Could not allocate TSS entry"); } /* If the thread had an associated auto thread state, reassociate it with * the new key. */ if (tstate && - PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate) != 0) + PyThread_tss_set(&gilstate->autoTSSkey, (void *)tstate) != 0) { Py_FatalError("Couldn't create autoTSSkey mapping"); } -- cgit v0.12