1 #ifndef Py_CPYTHON_LOCK_H 2 # error "this header file must not be included directly" 3 #endif 4 5 #define _Py_UNLOCKED 0 6 #define _Py_LOCKED 1 7 8 // A mutex that occupies one byte. The lock can be zero initialized to 9 // represent the unlocked state. 10 // 11 // Typical initialization: 12 // PyMutex m = (PyMutex){0}; 13 // 14 // Or initialize as global variables: 15 // static PyMutex m; 16 // 17 // Typical usage: 18 // PyMutex_Lock(&m); 19 // ... 20 // PyMutex_Unlock(&m); 21 // 22 // The contents of the PyMutex are not part of the public API, but are 23 // described to aid in understanding the implementation and debugging. Only 24 // the two least significant bits are used. The remaining bits are always zero: 25 // 0b00: unlocked 26 // 0b01: locked 27 // 0b10: unlocked and has parked threads 28 // 0b11: locked and has parked threads 29 typedef struct PyMutex { 30 uint8_t _bits; // (private) 31 } PyMutex; 32 33 // exported function for locking the mutex 34 PyAPI_FUNC(void) PyMutex_Lock(PyMutex *m); 35 36 // exported function for unlocking the mutex 37 PyAPI_FUNC(void) PyMutex_Unlock(PyMutex *m); 38 39 // Locks the mutex. 40 // 41 // If the mutex is currently locked, the calling thread will be parked until 42 // the mutex is unlocked. If the current thread holds the GIL, then the GIL 43 // will be released while the thread is parked. 44 static inline void _PyMutex_Lock(PyMutex * m)45_PyMutex_Lock(PyMutex *m) 46 { 47 uint8_t expected = _Py_UNLOCKED; 48 if (!_Py_atomic_compare_exchange_uint8(&m->_bits, &expected, _Py_LOCKED)) { 49 PyMutex_Lock(m); 50 } 51 } 52 #define PyMutex_Lock _PyMutex_Lock 53 54 // Unlocks the mutex. 55 static inline void _PyMutex_Unlock(PyMutex * m)56_PyMutex_Unlock(PyMutex *m) 57 { 58 uint8_t expected = _Py_LOCKED; 59 if (!_Py_atomic_compare_exchange_uint8(&m->_bits, &expected, _Py_UNLOCKED)) { 60 PyMutex_Unlock(m); 61 } 62 } 63 #define PyMutex_Unlock _PyMutex_Unlock 64