@@ -230,7 +230,9 @@ using instance_map = std::unordered_multimap<const void *, instance *>;
230230#ifdef Py_GIL_DISABLED
231231// Wrapper around PyMutex to provide BasicLockable semantics
232232class pymutex {
233+ # if PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
233234 friend class pycritical_section ;
235+ # endif
234236 PyMutex mutex;
235237
236238public:
@@ -239,36 +241,27 @@ class pymutex {
239241 void unlock () { PyMutex_Unlock (&mutex); }
240242};
241243
244+ // PyCriticalSection_BeginMutex was added in Python 3.15.0a1 and backported to 3.14.0rc1
245+ # if PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
242246class pycritical_section {
243247 pymutex &mutex;
244- # if PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
245248 PyCriticalSection cs;
246- # endif
247249
248250public:
249251 explicit pycritical_section (pymutex &m) : mutex(m) {
250- // PyCriticalSection_BeginMutex was added in Python 3.15.0a1 and backported to 3.14.0rc1
251- # if PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
252252 PyCriticalSection_BeginMutex (&cs, &mutex.mutex );
253- # else
254- // Fall back to direct mutex locking for older free-threaded Python versions
255- mutex.lock ();
256- # endif
257- }
258- ~pycritical_section () {
259- # if PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
260- PyCriticalSection_End (&cs);
261- # else
262- mutex.unlock ();
263- # endif
264253 }
254+ ~pycritical_section () { PyCriticalSection_End (&cs); }
265255
266256 // Non-copyable and non-movable to prevent double-unlock
267257 pycritical_section (const pycritical_section &) = delete ;
268258 pycritical_section &operator =(const pycritical_section &) = delete ;
269259 pycritical_section (pycritical_section &&) = delete ;
270260 pycritical_section &operator =(pycritical_section &&) = delete ;
271261};
262+ # else
263+ using pycritical_section = std::unique_lock<pymutex>;
264+ # endif
272265
273266// Instance map shards are used to reduce mutex contention in free-threaded Python.
274267struct instance_map_shard {
0 commit comments