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:
Victor Stinner 2020-06-02 15:51:37 +02:00 committed by GitHub
parent 297257f7bc
commit 26881c8fae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 84 additions and 50 deletions

View 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

View 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

View 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 (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