diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi
index 55d8468d57c05a..d6680f9064f3b1 100644
--- a/Doc/data/python3.12.abi
+++ b/Doc/data/python3.12.abi
@@ -1702,7 +1702,7 @@
-
+
@@ -7546,30 +7546,30 @@
-
-
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
@@ -8230,8 +8230,8 @@
-
-
+
+
@@ -8868,111 +8868,111 @@
-
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
+
@@ -10883,10 +10883,10 @@
-
+
-
+
@@ -12759,114 +12759,117 @@
-
+
-
+
-
-
+
+
+
+
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -12883,7 +12886,7 @@
-
+
@@ -12891,10 +12894,10 @@
-
+
-
+
@@ -12906,10 +12909,10 @@
-
+
-
+
@@ -13113,10 +13116,10 @@
-
+
-
+
@@ -13322,10 +13325,10 @@
-
+
-
+
@@ -13447,10 +13450,10 @@
-
+
-
+
@@ -13479,7 +13482,7 @@
-
+
@@ -13494,7 +13497,7 @@
-
+
@@ -13515,13 +13518,13 @@
-
+
-
+
-
+
@@ -13557,7 +13560,7 @@
-
+
@@ -13658,7 +13661,7 @@
-
+
@@ -14258,7 +14261,7 @@
-
+
@@ -14318,7 +14321,7 @@
-
+
@@ -14372,7 +14375,7 @@
-
+
@@ -14531,7 +14534,7 @@
-
+
@@ -14615,7 +14618,7 @@
-
+
@@ -15098,7 +15101,7 @@
-
+
@@ -15233,7 +15236,7 @@
-
+
@@ -15317,7 +15320,7 @@
-
+
@@ -15389,7 +15392,7 @@
-
+
@@ -15695,7 +15698,7 @@
-
+
@@ -15832,7 +15835,7 @@
-
+
@@ -15962,7 +15965,7 @@
-
+
@@ -15999,7 +16002,7 @@
-
+
@@ -16053,7 +16056,7 @@
-
+
@@ -16062,7 +16065,7 @@
-
+
@@ -16134,7 +16137,7 @@
-
+
@@ -16515,7 +16518,7 @@
-
+
@@ -16541,7 +16544,7 @@
-
+
@@ -16558,7 +16561,7 @@
-
+
@@ -16602,61 +16605,61 @@
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -16670,7 +16673,7 @@
-
+
@@ -16684,7 +16687,7 @@
-
+
@@ -16698,10 +16701,10 @@
-
+
-
+
@@ -16767,7 +16770,7 @@
-
+
@@ -16884,7 +16887,7 @@
-
+
@@ -16943,7 +16946,7 @@
-
+
@@ -17337,12 +17340,12 @@
-
-
-
+
+
+
-
+
@@ -17356,7 +17359,7 @@
-
+
@@ -17372,8 +17375,8 @@
-
-
+
+
@@ -17412,15 +17415,15 @@
-
+
-
+
-
+
@@ -17736,7 +17739,7 @@
-
+
@@ -17843,49 +17846,55 @@
-
+
-
+
-
+
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
@@ -18792,12 +18801,17 @@
-
+
+
+
+
+
+
-
+
@@ -18807,39 +18821,39 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -18850,31 +18864,31 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -18917,7 +18931,7 @@
-
+
@@ -18929,7 +18943,7 @@
-
+
@@ -19960,13 +19974,13 @@
-
+
-
+
@@ -20345,7 +20359,7 @@
-
+
@@ -20452,49 +20466,55 @@
-
+
-
+
-
+
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
@@ -20667,7 +20687,7 @@
-
+
@@ -20796,42 +20816,42 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -21245,17 +21265,30 @@
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
@@ -21928,7 +21961,7 @@
-
+
@@ -21976,7 +22009,7 @@
-
+
@@ -22015,53 +22048,53 @@
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
+
@@ -22687,35 +22720,35 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -22963,12 +22996,6 @@
-
-
-
-
-
-
@@ -24341,40 +24368,40 @@
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
+
@@ -24664,13 +24691,13 @@
-
+
-
+
-
+
@@ -24732,6 +24759,7 @@
+
@@ -25333,27 +25361,27 @@
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
@@ -25363,7 +25391,7 @@
-
+
@@ -25430,137 +25458,137 @@
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
@@ -26311,7 +26339,7 @@
-
+
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 8b846443ce8f6a..95b39f478f51f6 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -2974,24 +2974,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 39fe5473ed46b3..e3a010adbf5480 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -380,7 +380,16 @@ _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, \
+ &(runtime)->xidregistry.mutex, \
+ &(runtime)->getargs.mutex, \
+ &(runtime)->unicode_state.ids.lock, \
+ &(runtime)->imports.extensions.mutex, \
+ &(runtime)->atexit.mutex, \
+ }
static int
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
@@ -427,13 +436,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 +515,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 +538,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]);