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.
This commit is contained in:
Victor Stinner 2019-04-24 17:14:33 +02:00 committed by GitHub
parent 8bb3230149
commit b930a2d2b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 42 deletions

View File

@ -155,7 +155,6 @@ PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_Get(void);
PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*); PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*);
PyAPI_FUNC(void) _PyState_ClearModules(void); PyAPI_FUNC(void) _PyState_ClearModules(void);
PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *);
PyAPI_FUNC(void) _PyGILState_Reinit(void);
/* Similar to PyThreadState_Get(), but don't issue a fatal error /* Similar to PyThreadState_Get(), but don't issue a fatal error
* if it is NULL. */ * if it is NULL. */

View File

@ -185,9 +185,9 @@ typedef struct pyruntimestate {
/* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ /* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */
PyAPI_DATA(_PyRuntimeState) _PyRuntime; PyAPI_DATA(_PyRuntimeState) _PyRuntime;
PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *); PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *); PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(void); PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime);
/* Initialize _PyRuntimeState. /* Initialize _PyRuntimeState.
Return NULL on success, or return an error message on failure. */ Return NULL on success, or return an error message on failure. */
@ -236,8 +236,10 @@ PyAPI_FUNC(void) _PyThreadState_Init(
PyThreadState *tstate); PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate);
PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *); PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(void); PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyGILState_Reinit(_PyRuntimeState *runtime);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -421,12 +421,13 @@ PyOS_AfterFork_Parent(void)
void void
PyOS_AfterFork_Child(void) PyOS_AfterFork_Child(void)
{ {
_PyGILState_Reinit(); _PyRuntimeState *runtime = &_PyRuntime;
_PyInterpreterState_DeleteExceptMain(); _PyGILState_Reinit(runtime);
_PyInterpreterState_DeleteExceptMain(runtime);
PyEval_ReInitThreads(); PyEval_ReInitThreads();
_PyImport_ReInitLock(); _PyImport_ReInitLock();
_PySignal_AfterFork(); _PySignal_AfterFork();
_PyRuntimeState_ReInitThreads(); _PyRuntimeState_ReInitThreads(runtime);
run_at_forkers(_PyInterpreterState_Get()->after_forkers_child, 0); run_at_forkers(_PyInterpreterState_Get()->after_forkers_child, 0);
} }

View File

@ -108,23 +108,31 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
*/ */
void void
_PyRuntimeState_ReInitThreads(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
{ {
// This was initially set in _PyRuntimeState_Init(). // This was initially set in _PyRuntimeState_Init().
_PyRuntime.main_thread = PyThread_get_thread_ident(); runtime->main_thread = PyThread_get_thread_ident();
_PyRuntime.interpreters.mutex = PyThread_allocate_lock(); /* Force default allocator, since _PyRuntimeState_Fini() must
if (_PyRuntime.interpreters.mutex == NULL) { 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);
if (runtime->interpreters.mutex == NULL) {
Py_FatalError("Can't initialize lock for runtime interpreters"); Py_FatalError("Can't initialize lock for runtime interpreters");
} }
_PyRuntime.interpreters.main->id_mutex = PyThread_allocate_lock(); if (runtime->interpreters.main->id_mutex == NULL) {
if (_PyRuntime.interpreters.main->id_mutex == NULL) {
Py_FatalError("Can't initialize ID lock for main interpreter"); Py_FatalError("Can't initialize ID lock for main interpreter");
} }
_PyRuntime.xidregistry.mutex = PyThread_allocate_lock(); if (runtime->xidregistry.mutex == NULL) {
if (_PyRuntime.xidregistry.mutex == NULL) {
Py_FatalError("Can't initialize lock for cross-interpreter data registry"); 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. * is a current interpreter state, it *must* be the main interpreter.
*/ */
void void
_PyInterpreterState_DeleteExceptMain() _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
{ {
struct pyinterpreters *interpreters = &runtime->interpreters;
PyThreadState *tstate = PyThreadState_Swap(NULL); 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"); Py_FatalError("PyInterpreterState_DeleteExceptMain: not main interpreter");
} }
HEAD_LOCK(); HEAD_LOCK();
PyInterpreterState *interp = _PyRuntime.interpreters.head; PyInterpreterState *interp = interpreters->head;
_PyRuntime.interpreters.head = NULL; interpreters->head = NULL;
while (interp != NULL) { while (interp != NULL) {
if (interp == _PyRuntime.interpreters.main) { if (interp == interpreters->main) {
_PyRuntime.interpreters.main->next = NULL; interpreters->main->next = NULL;
_PyRuntime.interpreters.head = interp; interpreters->head = interp;
interp = interp->next; interp = interp->next;
continue; continue;
} }
@ -319,7 +329,7 @@ _PyInterpreterState_DeleteExceptMain()
} }
HEAD_UNLOCK(); HEAD_UNLOCK();
if (_PyRuntime.interpreters.head == NULL) { if (interpreters->head == NULL) {
Py_FatalError("PyInterpreterState_DeleteExceptMain: missing main"); Py_FatalError("PyInterpreterState_DeleteExceptMain: missing main");
} }
PyThreadState_Swap(tstate); PyThreadState_Swap(tstate);
@ -1079,31 +1089,20 @@ _PyGILState_Fini(void)
* don't reset TSS upon fork(), see issue #10517. * don't reset TSS upon fork(), see issue #10517.
*/ */
void void
_PyGILState_Reinit(void) _PyGILState_Reinit(_PyRuntimeState *runtime)
{ {
/* Force default allocator, since _PyRuntimeState_Fini() must struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
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");
}
PyThreadState *tstate = PyGILState_GetThisThreadState(); 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"); Py_FatalError("Could not allocate TSS entry");
} }
/* If the thread had an associated auto thread state, reassociate it with /* If the thread had an associated auto thread state, reassociate it with
* the new key. */ * the new key. */
if (tstate && 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"); Py_FatalError("Couldn't create autoTSSkey mapping");
} }