Skip to content

Commit 2e0695f

Browse files
committed
pythongh-117511: Make PyMutex public in the non-limited API
1 parent 6258844 commit 2e0695f

4 files changed

Lines changed: 28 additions & 67 deletions

File tree

‎Doc/c-api/init.rst‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1942,3 +1942,29 @@ be used in new code.
19421942
.. c:function:: void PyThread_delete_key_value(int key)
19431943
.. c:function:: void PyThread_ReInitTLS()
19441944
1945+
Synchronization Primitives
1946+
==========================
1947+
1948+
The C-API provides a basic mutual exclusion lock.
1949+
1950+
.. c:type:: PyMutex
1951+
1952+
A mutual exclusion lock. The ``PyMutex`` should be initialized to zero to
1953+
represent the unlocked state.
1954+
1955+
.. versionadded:: 3.13
1956+
1957+
.. c:function:: void PyMutex_Lock(PyMutex *m)
1958+
1959+
Lock the mutex. If another thread has already locked it, the calling
1960+
thread will block until the mutex is unlocked. While blocked, the thread
1961+
will temporarily release the :term:`GIL` if it is held.
1962+
1963+
.. versionadded:: 3.13
1964+
1965+
.. c:function:: void PyMutex_Unlock(PyMutex *m)
1966+
1967+
Unlock the mutex. The mutex must be locked --- otherwise, the function will
1968+
issue a fatal error.
1969+
1970+
.. versionadded:: 3.13

‎Include/Python.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "pybuffer.h"
5656
#include "pystats.h"
5757
#include "pyatomic.h"
58+
#include "lock.h"
5859
#include "object.h"
5960
#include "objimpl.h"
6061
#include "typeslots.h"

‎Include/internal/pycore_lock.h‎

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,79 +13,17 @@ extern "C" {
1313
# error "this header requires Py_BUILD_CORE define"
1414
#endif
1515

16-
17-
// A mutex that occupies one byte. The lock can be zero initialized.
18-
//
19-
// Only the two least significant bits are used. The remaining bits should be
20-
// zero:
21-
// 0b00: unlocked
22-
// 0b01: locked
23-
// 0b10: unlocked and has parked threads
24-
// 0b11: locked and has parked threads
25-
//
26-
// Typical initialization:
27-
// PyMutex m = (PyMutex){0};
28-
//
29-
// Or initialize as global variables:
30-
// static PyMutex m;
31-
//
32-
// Typical usage:
33-
// PyMutex_Lock(&m);
34-
// ...
35-
// PyMutex_Unlock(&m);
36-
37-
// NOTE: In Py_GIL_DISABLED builds, `struct _PyMutex` is defined in Include/object.h.
38-
// The Py_GIL_DISABLED builds need the definition in Include/object.h for the
39-
// `ob_mutex` field in PyObject. For the default (non-free-threaded) build,
40-
// we define the struct here to avoid exposing it in the public API.
41-
#ifndef Py_GIL_DISABLED
42-
struct _PyMutex { uint8_t v; };
43-
#endif
44-
45-
typedef struct _PyMutex PyMutex;
46-
47-
#define _Py_UNLOCKED 0
48-
#define _Py_LOCKED 1
16+
// NOTE: _Py_UNLOCKED and _Py_LOCKED are defined as 0 and 1
4917
#define _Py_HAS_PARKED 2
5018
#define _Py_ONCE_INITIALIZED 4
5119

52-
// (private) slow path for locking the mutex
53-
PyAPI_FUNC(void) _PyMutex_LockSlow(PyMutex *m);
54-
55-
// (private) slow path for unlocking the mutex
56-
PyAPI_FUNC(void) _PyMutex_UnlockSlow(PyMutex *m);
57-
5820
static inline int
5921
PyMutex_LockFast(uint8_t *lock_bits)
6022
{
6123
uint8_t expected = _Py_UNLOCKED;
6224
return _Py_atomic_compare_exchange_uint8(lock_bits, &expected, _Py_LOCKED);
6325
}
6426

65-
// Locks the mutex.
66-
//
67-
// If the mutex is currently locked, the calling thread will be parked until
68-
// the mutex is unlocked. If the current thread holds the GIL, then the GIL
69-
// will be released while the thread is parked.
70-
static inline void
71-
PyMutex_Lock(PyMutex *m)
72-
{
73-
uint8_t expected = _Py_UNLOCKED;
74-
if (!_Py_atomic_compare_exchange_uint8(&m->v, &expected, _Py_LOCKED)) {
75-
_PyMutex_LockSlow(m);
76-
}
77-
}
78-
79-
// Unlocks the mutex.
80-
static inline void
81-
PyMutex_Unlock(PyMutex *m)
82-
{
83-
uint8_t expected = _Py_LOCKED;
84-
if (!_Py_atomic_compare_exchange_uint8(&m->v, &expected, _Py_UNLOCKED)) {
85-
_PyMutex_UnlockSlow(m);
86-
}
87-
}
88-
8927
// Checks if the mutex is currently locked.
9028
static inline int
9129
PyMutex_IsLocked(PyMutex *m)

‎Include/object.h‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,6 @@ struct _object {
207207
// Create a shared field from a refcnt and desired flags
208208
#define _Py_REF_SHARED(refcnt, flags) (((refcnt) << _Py_REF_SHARED_SHIFT) + (flags))
209209

210-
// NOTE: In non-free-threaded builds, `struct _PyMutex` is defined in
211-
// pycore_lock.h. See pycore_lock.h for more details.
212-
struct _PyMutex { uint8_t v; };
213-
214210
struct _object {
215211
// ob_tid stores the thread id (or zero). It is also used by the GC and the
216212
// trashcan mechanism as a linked list pointer and by the GC to store the

0 commit comments

Comments
 (0)