]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-111924: Use PyMutex for runtime global locks.
authorSam Gross <colesbury@gmail.com>
Thu, 16 Nov 2023 21:41:21 +0000 (16:41 -0500)
committerSam Gross <colesbury@gmail.com>
Thu, 16 Nov 2023 22:39:49 +0000 (17:39 -0500)
This replaces some usages of PyThread_type_lock with PyMutex, which
does not require memory allocation to initialize.

18 files changed:
Include/internal/pycore_atexit.h
Include/internal/pycore_ceval.h
Include/internal/pycore_ceval_state.h
Include/internal/pycore_crossinterp.h
Include/internal/pycore_import.h
Include/internal/pycore_lock.h
Include/internal/pycore_pymem.h
Include/internal/pycore_pystate.h
Include/internal/pycore_runtime.h
Include/internal/pycore_unicodeobject.h
Objects/obmalloc.c
Objects/unicodeobject.c
Python/ceval_gil.c
Python/crossinterp.c
Python/import.c
Python/pylifecycle.c
Python/pystate.c
Python/sysmodule.c

index 3966df70e2616fb4d7349b28975846be871eaacd..4dcda8f517c787315e294f53941f216f9d8fda01 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef Py_INTERNAL_ATEXIT_H
 #define Py_INTERNAL_ATEXIT_H
+
+#include "pycore_lock.h"        // PyMutex
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -15,7 +18,7 @@ extern "C" {
 typedef void (*atexit_callbackfunc)(void);
 
 struct _atexit_runtime_state {
-    PyThread_type_lock mutex;
+    PyMutex mutex;
 #define NEXITFUNCS 32
     atexit_callbackfunc callbacks[NEXITFUNCS];
     int ncallbacks;
index c372b7224fb047b88d899924c2753c2cc7cf837c..eeaf25b25e551fc6ccb6d1f0b98a8be4ec8789ea 100644 (file)
@@ -41,8 +41,7 @@ PyAPI_FUNC(int) _PyEval_MakePendingCalls(PyThreadState *);
 #endif
 
 extern void _Py_FinishPendingCalls(PyThreadState *tstate);
-extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock);
-extern void _PyEval_FiniState(struct _ceval_state *ceval);
+extern void _PyEval_InitState(PyInterpreterState *);
 extern void _PyEval_SignalReceived(PyInterpreterState *interp);
 
 // bitwise flags:
index 072bbcda0c3c828ebef0bc301acc3381a8b9e104..28738980eb49be8f2a4b76d2a3057951f75b21d5 100644 (file)
@@ -8,6 +8,7 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+#include "pycore_lock.h"            // PyMutex
 #include "pycore_gil.h"             // struct _gil_runtime_state
 
 
@@ -15,7 +16,7 @@ typedef int (*_Py_pending_call_func)(void *);
 
 struct _pending_calls {
     int busy;
-    PyThread_type_lock lock;
+    PyMutex mutex;
     /* Request for running pending calls. */
     int32_t calls_to_do;
 #define NPENDINGCALLS 32
index ee9ff0090c2484e32ff588047ca4baca09dd07cd..41e685d4668dddef52e504823617d970a90c5ad3 100644 (file)
@@ -8,6 +8,7 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+#include "pycore_lock.h"            // PyMutex
 #include "pycore_pyerrors.h"
 
 
@@ -128,7 +129,7 @@ struct _xidregitem {
 struct _xidregistry {
     int global;  /* builtin types or heap types */
     int initialized;
-    PyThread_type_lock mutex;
+    PyMutex mutex;
     struct _xidregitem *head;
 };
 
index 117e46bb86285d2191a088132aa0b63b234a2064..c84f87a831bf38466ba1d101371ea6c20e351eb4 100644 (file)
@@ -9,6 +9,7 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+#include "pycore_lock.h"          // PyMutex
 #include "pycore_hashtable.h"     // _Py_hashtable_t
 #include "pycore_time.h"          // _PyTime_t
 
@@ -47,7 +48,7 @@ struct _import_runtime_state {
     Py_ssize_t last_module_index;
     struct {
         /* A lock to guard the cache. */
-        PyThread_type_lock mutex;
+        PyMutex mutex;
         /* The actual cache of (filename, name, PyModuleDef) for modules.
            Only legacy (single-phase init) extension modules are added
            and only if they support multiple initialization (m_size >- 0)
index 25c3cf5377b7780a2c79bc2125ebc0eec1f95253..bd455ea57c521b8c9bef7e3957f77fb81a42faa0 100644 (file)
@@ -108,6 +108,16 @@ typedef enum _PyLockFlags {
 extern PyLockStatus
 _PyMutex_LockTimed(PyMutex *m, _PyTime_t timeout_ns, _PyLockFlags flags);
 
+// Lock a mutex with aditional options. See _PyLockFlags for details.
+static inline void
+PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags)
+{
+    uint8_t expected = _Py_UNLOCKED;
+    if (!_Py_atomic_compare_exchange_uint8(&m->v, &expected, _Py_LOCKED)) {
+        _PyMutex_LockTimed(m, -1, flags);
+    }
+}
+
 // Unlock a mutex, returns 0 if the mutex is not locked (used for improved
 // error messages).
 extern int _PyMutex_TryUnlock(PyMutex *m);
index 6b5113714dbeb28f0cd7d6bc042ea620a06ce3a1..8631ca34a5e61600a52f007b6a92298039c4e1f3 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef Py_INTERNAL_PYMEM_H
 #define Py_INTERNAL_PYMEM_H
+
+#include "pycore_lock.h"            // PyMutex
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -30,7 +33,7 @@ typedef struct {
 } debug_alloc_api_t;
 
 struct _pymem_allocators {
-    PyThread_type_lock mutex;
+    PyMutex mutex;
     struct {
         PyMemAllocatorEx raw;
         PyMemAllocatorEx mem;
index 7fa952e371d7b46bd457381e0b0e65191ffd029d..c031a38cd6bfa30445fa13f847bc22d2cf16b38d 100644 (file)
@@ -220,9 +220,9 @@ PyAPI_FUNC(int) _PyState_AddModule(
 extern int _PyOS_InterruptOccurred(PyThreadState *tstate);
 
 #define HEAD_LOCK(runtime) \
-    PyThread_acquire_lock((runtime)->interpreters.mutex, WAIT_LOCK)
+    PyMutex_LockFlags(&(runtime)->interpreters.mutex, _Py_LOCK_DONT_DETACH)
 #define HEAD_UNLOCK(runtime) \
-    PyThread_release_lock((runtime)->interpreters.mutex)
+    PyMutex_Unlock(&(runtime)->interpreters.mutex)
 
 // Get the configuration of the current interpreter.
 // The caller must hold the GIL.
index e6efe8b646e86f85d10f8db017f16b04ca8bb95b..d7d5b4c4df3824981ad99e14fedcf6f38018e280 100644 (file)
@@ -174,7 +174,7 @@ typedef struct pyruntimestate {
     unsigned long _finalizing_id;
 
     struct pyinterpreters {
-        PyThread_type_lock mutex;
+        PyMutex mutex;
         /* The linked list of interpreters, newest first. */
         PyInterpreterState *head;
         /* The runtime's initial interpreter, which has a special role
@@ -236,7 +236,7 @@ typedef struct pyruntimestate {
     Py_OpenCodeHookFunction open_code_hook;
     void *open_code_userdata;
     struct {
-        PyThread_type_lock mutex;
+        PyMutex mutex;
         _Py_AuditHookEntry *head;
     } audit_hooks;
 
index a0d00af92e0f5d744cd3995b19eecc2ea95b3b4a..7ee540154b23d88d0076f84d7e37882fe2c6d219 100644 (file)
@@ -8,6 +8,7 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+#include "pycore_lock.h"          // PyMutex
 #include "pycore_fileutils.h"     // _Py_error_handler
 #include "pycore_identifier.h"    // _Py_Identifier
 #include "pycore_ucnhash.h"       // _PyUnicode_Name_CAPI
@@ -277,7 +278,7 @@ extern PyTypeObject _PyUnicodeASCIIIter_Type;
 /* --- Other API ---------------------------------------------------------- */
 
 struct _Py_unicode_runtime_ids {
-    PyThread_type_lock lock;
+    PyMutex mutex;
     // next_index value must be preserved when Py_Initialize()/Py_Finalize()
     // is called multiple times: see _PyUnicode_FromId() implementation.
     Py_ssize_t next_index;
index 2761c7742097869a0cfb0056599b53c9336d47bb..b737c03095756417b98f6cb585624e04da4cf6bf 100644 (file)
@@ -329,13 +329,9 @@ int
 _PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
                            PyMemAllocatorEx *old_alloc)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must be initializing. */
-        return set_default_allocator_unlocked(domain, pydebug, old_alloc);
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     int res = set_default_allocator_unlocked(domain, pydebug, old_alloc);
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
     return res;
 }
 
@@ -467,9 +463,9 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
 int
 _PyMem_SetupAllocators(PyMemAllocatorName allocator)
 {
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     int res = set_up_allocators_unlocked(allocator);
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
     return res;
 }
 
@@ -554,9 +550,9 @@ get_current_allocator_name_unlocked(void)
 const char*
 _PyMem_GetCurrentAllocatorName(void)
 {
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     const char *name = get_current_allocator_name_unlocked();
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
     return name;
 }
 
@@ -653,14 +649,9 @@ set_up_debug_hooks_unlocked(void)
 void
 PyMem_SetupDebugHooks(void)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must not be completely initialized yet. */
-        set_up_debug_hooks_unlocked();
-        return;
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     set_up_debug_hooks_unlocked();
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
 }
 
 static void
@@ -696,53 +687,33 @@ set_allocator_unlocked(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
 void
 PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must not be completely initialized yet. */
-        get_allocator_unlocked(domain, allocator);
-        return;
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     get_allocator_unlocked(domain, allocator);
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
 }
 
 void
 PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must not be completely initialized yet. */
-        set_allocator_unlocked(domain, allocator);
-        return;
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     set_allocator_unlocked(domain, allocator);
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
 }
 
 void
 PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must not be completely initialized yet. */
-        *allocator = _PyObject_Arena;
-        return;
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     *allocator = _PyObject_Arena;
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
 }
 
 void
 PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
 {
-    if (ALLOCATORS_MUTEX == NULL) {
-        /* The runtime must not be completely initialized yet. */
-        _PyObject_Arena = *allocator;
-        return;
-    }
-    PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
+    PyMutex_Lock(&ALLOCATORS_MUTEX);
     _PyObject_Arena = *allocator;
-    PyThread_release_lock(ALLOCATORS_MUTEX);
+    PyMutex_Unlock(&ALLOCATORS_MUTEX);
 }
 
 
index cffc06297a9aeea245d69604132e9d74a842f37d..a1b23d209a54bb9fb58fe35226308a29e8ac8797 100644 (file)
@@ -1904,7 +1904,7 @@ _PyUnicode_FromId(_Py_Identifier *id)
     if (index < 0) {
         struct _Py_unicode_runtime_ids *rt_ids = &interp->runtime->unicode_state.ids;
 
-        PyThread_acquire_lock(rt_ids->lock, WAIT_LOCK);
+        PyMutex_Lock(&rt_ids->mutex);
         // Check again to detect concurrent access. Another thread can have
         // initialized the index while this thread waited for the lock.
         index = _Py_atomic_load_ssize(&id->index);
@@ -1914,7 +1914,7 @@ _PyUnicode_FromId(_Py_Identifier *id)
             rt_ids->next_index++;
             _Py_atomic_store_ssize(&id->index, index);
         }
-        PyThread_release_lock(rt_ids->lock);
+        PyMutex_Unlock(&rt_ids->mutex);
     }
     assert(index >= 0);
 
index 92c4b2fee9f863ef3633b7ebacb430902281ce2d..255e838fd25655770e86c04f517bedc892bc1fda 100644 (file)
@@ -589,9 +589,7 @@ _PyEval_ReInitThreads(PyThreadState *tstate)
     take_gil(tstate);
 
     struct _pending_calls *pending = &tstate->interp->ceval.pending;
-    if (_PyThread_at_fork_reinit(&pending->lock) < 0) {
-        return _PyStatus_ERR("Can't reinitialize pending calls lock");
-    }
+    pending->mutex = (PyMutex){0};
 
     /* Destroy all threads except the current one */
     _PyThreadState_DeleteExcept(tstate);
@@ -720,13 +718,10 @@ _PyEval_AddPendingCall(PyInterpreterState *interp,
         assert(_Py_IsMainInterpreter(interp));
         pending = &_PyRuntime.ceval.pending_mainthread;
     }
-    /* Ensure that _PyEval_InitState() was called
-       and that _PyEval_FiniState() is not called yet. */
-    assert(pending->lock != NULL);
 
-    PyThread_acquire_lock(pending->lock, WAIT_LOCK);
+    PyMutex_Lock(&pending->mutex);
     int result = _push_pending_call(pending, func, arg, flags);
-    PyThread_release_lock(pending->lock);
+    PyMutex_Unlock(&pending->mutex);
 
     /* signal main loop */
     SIGNAL_PENDING_CALLS(interp);
@@ -768,9 +763,9 @@ _make_pending_calls(struct _pending_calls *pending)
         int flags = 0;
 
         /* pop one item off the queue while holding the lock */
-        PyThread_acquire_lock(pending->lock, WAIT_LOCK);
+        PyMutex_Lock(&pending->mutex);
         _pop_pending_call(pending, &func, &arg, &flags);
-        PyThread_release_lock(pending->lock);
+        PyMutex_Unlock(&pending->mutex);
 
         /* having released the lock, perform the callback */
         if (func == NULL) {
@@ -795,7 +790,7 @@ make_pending_calls(PyInterpreterState *interp)
 
     /* Only one thread (per interpreter) may run the pending calls
        at once.  In the same way, we don't do recursive pending calls. */
-    PyThread_acquire_lock(pending->lock, WAIT_LOCK);
+    PyMutex_Lock(&pending->mutex);
     if (pending->busy) {
         /* A pending call was added after another thread was already
            handling the pending calls (and had already "unsignaled").
@@ -807,11 +802,11 @@ make_pending_calls(PyInterpreterState *interp)
            care of any remaining pending calls.  Until then, though,
            all the interpreter's threads will be tripping the eval
            breaker every time it's checked. */
-        PyThread_release_lock(pending->lock);
+        PyMutex_Unlock(&pending->mutex);
         return 0;
     }
     pending->busy = 1;
-    PyThread_release_lock(pending->lock);
+    PyMutex_Unlock(&pending->mutex);
 
     /* unsignal before starting to call callbacks, so that any callback
        added in-between re-signals */
@@ -892,23 +887,9 @@ Py_MakePendingCalls(void)
 }
 
 void
-_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock)
+_PyEval_InitState(PyInterpreterState *interp)
 {
     _gil_initialize(&interp->_gil);
-
-    struct _pending_calls *pending = &interp->ceval.pending;
-    assert(pending->lock == NULL);
-    pending->lock = pending_lock;
-}
-
-void
-_PyEval_FiniState(struct _ceval_state *ceval)
-{
-    struct _pending_calls *pending = &ceval->pending;
-    if (pending->lock != NULL) {
-        PyThread_free_lock(pending->lock);
-        pending->lock = NULL;
-    }
 }
 
 
index a908f9ae340ee93a187df36299746381df926966..6beb319782eeca3fdfe57bd84a81a3e75f1bde56 100644 (file)
@@ -454,16 +454,16 @@ _xidregistry_clear(struct _xidregistry *xidregistry)
 static void
 _xidregistry_lock(struct _xidregistry *registry)
 {
-    if (registry->mutex != NULL) {
-        PyThread_acquire_lock(registry->mutex, WAIT_LOCK);
+    if (registry->global) {
+        PyMutex_Lock(&registry->mutex);
     }
 }
 
 static void
 _xidregistry_unlock(struct _xidregistry *registry)
 {
-    if (registry->mutex != NULL) {
-        PyThread_release_lock(registry->mutex);
+    if (registry->global) {
+        PyMutex_Unlock(&registry->mutex);
     }
 }
 
@@ -856,19 +856,10 @@ _xidregistry_init(struct _xidregistry *registry)
     registry->initialized = 1;
 
     if (registry->global) {
-        // We manage the mutex lifecycle in pystate.c.
-        assert(registry->mutex != NULL);
-
         // Registering the builtins is cheap so we don't bother doing it lazily.
         assert(registry->head == NULL);
         _register_builtins_for_crossinterpreter_data(registry);
     }
-    else {
-        // Within an interpreter we rely on the GIL instead of a separate lock.
-        assert(registry->mutex == NULL);
-
-        // There's nothing else to initialize.
-    }
 }
 
 static void
@@ -880,17 +871,6 @@ _xidregistry_fini(struct _xidregistry *registry)
     registry->initialized = 0;
 
     _xidregistry_clear(registry);
-
-    if (registry->global) {
-        // We manage the mutex lifecycle in pystate.c.
-        assert(registry->mutex != NULL);
-    }
-    else {
-        // There's nothing else to finalize.
-
-        // Within an interpreter we rely on the GIL instead of a separate lock.
-        assert(registry->mutex == NULL);
-    }
 }
 
 
index f37393bbdc4269527884e7ea13ea1aadb3f050c7..1d6e0cf6e13fc303671687debf055df5315ee48c 100644 (file)
@@ -415,11 +415,7 @@ remove_module(PyThreadState *tstate, PyObject *name)
 Py_ssize_t
 _PyImport_GetNextModuleIndex(void)
 {
-    PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
-    LAST_MODULE_INDEX++;
-    Py_ssize_t index = LAST_MODULE_INDEX;
-    PyThread_release_lock(EXTENSIONS.mutex);
-    return index;
+    return _Py_atomic_add_ssize(&LAST_MODULE_INDEX, 1) + 1;
 }
 
 static const char *
@@ -879,13 +875,13 @@ gets even messier.
 static inline void
 extensions_lock_acquire(void)
 {
-    PyThread_acquire_lock(_PyRuntime.imports.extensions.mutex, WAIT_LOCK);
+    PyMutex_Lock(&_PyRuntime.imports.extensions.mutex);
 }
 
 static inline void
 extensions_lock_release(void)
 {
-    PyThread_release_lock(_PyRuntime.imports.extensions.mutex);
+    PyMutex_Unlock(&_PyRuntime.imports.extensions.mutex);
 }
 
 /* Magic for extension modules (built-in as well as dynamically
index ac8d5208322882aa268ded84f93d13045e225b1e..d763f444412920d1a46b4dd96774f4bfd0d40c7d 100644 (file)
@@ -3055,13 +3055,13 @@ wait_for_thread_shutdown(PyThreadState *tstate)
 int Py_AtExit(void (*func)(void))
 {
     struct _atexit_runtime_state *state = &_PyRuntime.atexit;
-    PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+    PyMutex_Lock(&state->mutex);
     if (state->ncallbacks >= NEXITFUNCS) {
-        PyThread_release_lock(state->mutex);
+        PyMutex_Unlock(&state->mutex);
         return -1;
     }
     state->callbacks[state->ncallbacks++] = func;
-    PyThread_release_lock(state->mutex);
+    PyMutex_Unlock(&state->mutex);
     return 0;
 }
 
@@ -3071,18 +3071,18 @@ call_ll_exitfuncs(_PyRuntimeState *runtime)
     atexit_callbackfunc exitfunc;
     struct _atexit_runtime_state *state = &runtime->atexit;
 
-    PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+    PyMutex_Lock(&state->mutex);
     while (state->ncallbacks > 0) {
         /* pop last function from the list */
         state->ncallbacks--;
         exitfunc = state->callbacks[state->ncallbacks];
         state->callbacks[state->ncallbacks] = NULL;
 
-        PyThread_release_lock(state->mutex);
+        PyMutex_Unlock(&state->mutex);
         exitfunc();
-        PyThread_acquire_lock(state->mutex, WAIT_LOCK);
+        PyMutex_Lock(&state->mutex);
     }
-    PyThread_release_lock(state->mutex);
+    PyMutex_Unlock(&state->mutex);
 
     fflush(stdout);
     fflush(stderr);
index 89e9bddc6de060d576541313a01ea7f61d3a4886..730e66f586dcae3371dcfbb75eb6a63b647b8d27 100644 (file)
@@ -379,49 +379,11 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
 static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
 _Py_COMP_DIAG_POP
 
-#define NUMLOCKS 8
-#define LOCKS_INIT(runtime) \
-    { \
-        &(runtime)->interpreters.mutex, \
-        &(runtime)->xi.registry.mutex, \
-        &(runtime)->unicode_state.ids.lock, \
-        &(runtime)->imports.extensions.mutex, \
-        &(runtime)->ceval.pending_mainthread.lock, \
-        &(runtime)->atexit.mutex, \
-        &(runtime)->audit_hooks.mutex, \
-        &(runtime)->allocators.mutex, \
-    }
-
-static int
-alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
-{
-    /* Force default allocator, since _PyRuntimeState_Fini() must
-       use the same allocator than this function. */
-    PyMemAllocatorEx old_alloc;
-    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
-    for (int i = 0; i < NUMLOCKS; i++) {
-        PyThread_type_lock lock = PyThread_allocate_lock();
-        if (lock == NULL) {
-            for (int j = 0; j < i; j++) {
-                PyThread_free_lock(locks[j]);
-                locks[j] = NULL;
-            }
-            break;
-        }
-        locks[i] = lock;
-    }
-
-    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-    return 0;
-}
-
 static void
 init_runtime(_PyRuntimeState *runtime,
              void *open_code_hook, void *open_code_userdata,
              _Py_AuditHookEntry *audit_hook_head,
-             Py_ssize_t unicode_next_index,
-             PyThread_type_lock locks[NUMLOCKS])
+             Py_ssize_t unicode_next_index)
 {
     assert(!runtime->preinitializing);
     assert(!runtime->preinitialized);
@@ -435,12 +397,6 @@ init_runtime(_PyRuntimeState *runtime,
 
     PyPreConfig_InitPythonConfig(&runtime->preconfig);
 
-    PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
-    for (int i = 0; i < NUMLOCKS; i++) {
-        assert(locks[i] != NULL);
-        *lockptrs[i] = locks[i];
-    }
-
     // Set it to the ID of the main thread of the main interpreter.
     runtime->main_thread = PyThread_get_thread_ident();
 
@@ -466,11 +422,6 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
     // is called multiple times.
     Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
 
-    PyThread_type_lock locks[NUMLOCKS];
-    if (alloc_for_runtime(locks) != 0) {
-        return _PyStatus_NO_MEMORY();
-    }
-
     if (runtime->_initialized) {
         // Py_Initialize() must be running again.
         // Reset to _PyRuntimeState_INIT.
@@ -489,7 +440,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
     }
 
     init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
-                 unicode_next_index, locks);
+                 unicode_next_index);
 
     return _PyStatus_OK();
 }
@@ -509,23 +460,6 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
     if (PyThread_tss_is_created(&runtime->trashTSSkey)) {
         PyThread_tss_delete(&runtime->trashTSSkey);
     }
-
-    /* Force the allocator used by _PyRuntimeState_Init(). */
-    PyMemAllocatorEx old_alloc;
-    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-#define FREE_LOCK(LOCK) \
-    if (LOCK != NULL) { \
-        PyThread_free_lock(LOCK); \
-        LOCK = NULL; \
-    }
-
-    PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
-    for (int i = 0; i < NUMLOCKS; i++) {
-        FREE_LOCK(*lockptrs[i]);
-    }
-
-#undef FREE_LOCK
-    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
 }
 
 #ifdef HAVE_FORK
@@ -537,28 +471,23 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
     // This was initially set in _PyRuntimeState_Init().
     runtime->main_thread = PyThread_get_thread_ident();
 
-    /* Force default allocator, since _PyRuntimeState_Fini() must
-       use the same allocator than this function. */
-    PyMemAllocatorEx old_alloc;
-    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
-    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]);
-    }
-
-    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
     // Clears the parking lot. Any waiting threads are dead. This must be
     // called before releasing any locks that use the parking lot.
     _PyParkingLot_AfterFork();
 
+    // Re-initialize global locks
+    runtime->interpreters.mutex = (PyMutex){0};
+    runtime->xi.registry.mutex = (PyMutex){0};
+    runtime->unicode_state.ids.mutex = (PyMutex){0};
+    runtime->imports.extensions.mutex = (PyMutex){0};
+    runtime->ceval.pending_mainthread.mutex = (PyMutex){0};
+    runtime->atexit.mutex = (PyMutex){0};
+    runtime->audit_hooks.mutex = (PyMutex){0};
+    runtime->allocators.mutex = (PyMutex){0};
+
     /* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
      * not force the default allocator. */
-    reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
-
-    if (reinit_err < 0) {
+    if (_PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex) < 0) {
         return _PyStatus_ERR("Failed to reinitialize runtime locks");
     }
 
@@ -594,24 +523,6 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
 {
     struct pyinterpreters *interpreters = &runtime->interpreters;
     interpreters->next_id = 0;
-
-    /* Py_Finalize() calls _PyRuntimeState_Fini() which clears the mutex.
-       Create a new mutex if needed. */
-    if (interpreters->mutex == NULL) {
-        /* Force default allocator, since _PyRuntimeState_Fini() must
-           use the same allocator than this function. */
-        PyMemAllocatorEx old_alloc;
-        _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
-        interpreters->mutex = PyThread_allocate_lock();
-
-        PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
-        if (interpreters->mutex == NULL) {
-            return _PyStatus_ERR("Can't initialize threads for interpreter");
-        }
-    }
-
     return _PyStatus_OK();
 }
 
@@ -654,8 +565,7 @@ free_interpreter(PyInterpreterState *interp)
 static PyStatus
 init_interpreter(PyInterpreterState *interp,
                  _PyRuntimeState *runtime, int64_t id,
-                 PyInterpreterState *next,
-                 PyThread_type_lock pending_lock)
+                 PyInterpreterState *next)
 {
     if (interp->_initialized) {
         return _PyStatus_ERR("interpreter already initialized");
@@ -684,7 +594,7 @@ init_interpreter(PyInterpreterState *interp,
         return status;
     }
 
-    _PyEval_InitState(interp, pending_lock);
+    _PyEval_InitState(interp);
     _PyGC_InitState(&interp->gc);
     PyConfig_InitPythonConfig(&interp->config);
     _PyType_InitCache(interp);
@@ -730,11 +640,6 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
         }
     }
 
-    PyThread_type_lock pending_lock = PyThread_allocate_lock();
-    if (pending_lock == NULL) {
-        return _PyStatus_NO_MEMORY();
-    }
-
     /* We completely serialize creation of multiple interpreters, since
        it simplifies things here and blocking concurrent calls isn't a problem.
        Regardless, we must fully block subinterpreter creation until
@@ -781,11 +686,10 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
     interpreters->head = interp;
 
     status = init_interpreter(interp, runtime,
-                              id, old_head, pending_lock);
+                              id, old_head);
     if (_PyStatus_EXCEPTION(status)) {
         goto error;
     }
-    pending_lock = NULL;
 
     HEAD_UNLOCK(runtime);
 
@@ -796,9 +700,6 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
 error:
     HEAD_UNLOCK(runtime);
 
-    if (pending_lock != NULL) {
-        PyThread_free_lock(pending_lock);
-    }
     if (interp != NULL) {
         free_interpreter(interp);
     }
@@ -1003,8 +904,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
 
     zapthreads(interp);
 
-    _PyEval_FiniState(&interp->ceval);
-
     // XXX These two calls should be done at the end of clear_interpreter(),
     // but currently some objects get decref'ed after that.
 #ifdef Py_REF_DEBUG
index c17de44731b7030db47e8959ff15da9cf7a600c3..b6b08b6ac16a1e756e23211264ba18dd025014c6 100644 (file)
@@ -451,15 +451,9 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
     e->hookCFunction = (Py_AuditHookFunction)hook;
     e->userData = userData;
 
-    if (runtime->audit_hooks.mutex == NULL) {
-        /* The runtime must not be initialized yet. */
-        add_audit_hook_entry_unlocked(runtime, e);
-    }
-    else {
-        PyThread_acquire_lock(runtime->audit_hooks.mutex, WAIT_LOCK);
-        add_audit_hook_entry_unlocked(runtime, e);
-        PyThread_release_lock(runtime->audit_hooks.mutex);
-    }
+    PyMutex_Lock(&runtime->audit_hooks.mutex);
+    add_audit_hook_entry_unlocked(runtime, e);
+    PyMutex_Unlock(&runtime->audit_hooks.mutex);
 
     return 0;
 }