From 3cdbcdc671517cea9bbbfb9e8721a69b4f8f70f2 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 6 Jun 2023 18:12:18 -0600 Subject: [PATCH 1/2] Factor out LOCKS_INIT(). --- Python/pystate.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 5b7a6c86ade4d7..0a316a82fcb916 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -381,6 +381,14 @@ static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP #define NUMLOCKS 5 +#define LOCKS_INIT(runtime) \ + { \ + &(runtime)->interpreters.mutex, \ + &(runtime)->xidregistry.mutex, \ + &(runtime)->getargs.mutex, \ + &(runtime)->unicode_state.ids.lock, \ + &(runtime)->imports.extensions.mutex, \ + } static int alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS]) @@ -427,13 +435,7 @@ init_runtime(_PyRuntimeState *runtime, PyPreConfig_InitPythonConfig(&runtime->preconfig); - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); for (int i = 0; i < NUMLOCKS; i++) { assert(locks[i] != NULL); *lockptrs[i] = locks[i]; @@ -512,13 +514,7 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) LOCK = NULL; \ } - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); for (int i = 0; i < NUMLOCKS; i++) { FREE_LOCK(*lockptrs[i]); } @@ -541,13 +537,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); int reinit_err = 0; for (int i = 0; i < NUMLOCKS; i++) { reinit_err += _PyThread_at_fork_reinit(lockptrs[i]); From f1b6610ff08f22d5f36154a6dcb101ad871b3627 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 6 Jun 2023 18:12:58 -0600 Subject: [PATCH 2/2] Add a granular lock for global atexit state. --- Include/internal/pycore_atexit.h | 1 + Python/pylifecycle.c | 17 ++++++++++++++--- Python/pystate.c | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_atexit.h b/Include/internal/pycore_atexit.h index b4663b396852f3..63a2cd5d507d2c 100644 --- a/Include/internal/pycore_atexit.h +++ b/Include/internal/pycore_atexit.h @@ -15,6 +15,7 @@ extern "C" { typedef void (*atexit_callbackfunc)(void); struct _atexit_runtime_state { + PyThread_type_lock mutex; #define NEXITFUNCS 32 atexit_callbackfunc callbacks[NEXITFUNCS]; int ncallbacks; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4c21160d312465..9ac5630959f8f5 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2973,24 +2973,35 @@ wait_for_thread_shutdown(PyThreadState *tstate) int Py_AtExit(void (*func)(void)) { - if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS) + struct _atexit_runtime_state *state = &_PyRuntime.atexit; + PyThread_acquire_lock(state->mutex, WAIT_LOCK); + if (state->ncallbacks >= NEXITFUNCS) { + PyThread_release_lock(state->mutex); return -1; - _PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func; + } + state->callbacks[state->ncallbacks++] = func; + PyThread_release_lock(state->mutex); return 0; } static void call_ll_exitfuncs(_PyRuntimeState *runtime) { + atexit_callbackfunc exitfunc; struct _atexit_runtime_state *state = &runtime->atexit; + + PyThread_acquire_lock(state->mutex, WAIT_LOCK); while (state->ncallbacks > 0) { /* pop last function from the list */ state->ncallbacks--; - atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks]; + exitfunc = state->callbacks[state->ncallbacks]; state->callbacks[state->ncallbacks] = NULL; + PyThread_release_lock(state->mutex); exitfunc(); + PyThread_acquire_lock(state->mutex, WAIT_LOCK); } + PyThread_release_lock(state->mutex); fflush(stdout); fflush(stderr); diff --git a/Python/pystate.c b/Python/pystate.c index 0a316a82fcb916..a1f14f76e751df 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 5 +#define NUMLOCKS 6 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -388,6 +388,7 @@ _Py_COMP_DIAG_POP &(runtime)->getargs.mutex, \ &(runtime)->unicode_state.ids.lock, \ &(runtime)->imports.extensions.mutex, \ + &(runtime)->atexit.mutex, \ } static int