diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index b6c2897ac..74d96d27a 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -230,6 +230,7 @@ using instance_map = std::unordered_multimap; #ifdef Py_GIL_DISABLED // Wrapper around PyMutex to provide BasicLockable semantics class pymutex { + friend class pycritical_section; PyMutex mutex; public: @@ -238,29 +239,16 @@ public: void unlock() { PyMutex_Unlock(&mutex); } }; -// A recursive mutex implementation using PyMutex -class pyrecursive_mutex { - PyMutex mutex; - std::atomic owner; - size_t lock_count; +class pycritical_section { + pymutex& mutex; + PyCriticalSection cs; public: - pyrecursive_mutex() : mutex({}), owner(0), lock_count(0) {} - void lock() { - if (owner.load(std::memory_order_relaxed) == _Py_ThreadId()) { - ++lock_count; - return; - } - PyMutex_Lock(&mutex); - owner.store(_Py_ThreadId(), std::memory_order_relaxed); + explicit pycritical_section(pymutex& m) : mutex(m) { + PyCriticalSection_BeginMutex(&cs, &mutex.mutex); } - void unlock() { - if (lock_count > 0) { - --lock_count; - return; - } - owner.store(0, std::memory_order_relaxed); - PyMutex_Unlock(&mutex); + ~pycritical_section() { + PyCriticalSection_End(&cs); } }; @@ -297,7 +285,7 @@ class loader_life_support; /// `PYBIND11_INTERNALS_VERSION` must be incremented. struct internals { #ifdef Py_GIL_DISABLED - pyrecursive_mutex mutex; + pymutex mutex; pymutex exception_translator_mutex; #endif #if PYBIND11_INTERNALS_VERSION >= 12 @@ -882,8 +870,7 @@ inline local_internals &get_local_internals() { } #ifdef Py_GIL_DISABLED -# define PYBIND11_LOCK_INTERNALS(internals) \ - std::unique_lock lock((internals).mutex) +# define PYBIND11_LOCK_INTERNALS(internals) pycritical_section lock((internals).mutex) #else # define PYBIND11_LOCK_INTERNALS(internals) #endif @@ -912,7 +899,7 @@ inline auto with_exception_translators(const F &cb) get_local_internals().registered_exception_translators)) { auto &internals = get_internals(); #ifdef Py_GIL_DISABLED - std::unique_lock lock((internals).exception_translator_mutex); + pycritical_section lock((internals).exception_translator_mutex); #endif auto &local_internals = get_local_internals(); return cb(internals.registered_exception_translators,