PyOS_AfterFork_Child() uses PyStatus (GH-20596)
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().
This commit is contained in:
parent
297257f7bc
commit
26881c8fae
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue