From 1a3320504dc12a9e98e66fe04713b01baffed8d9 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 20 May 2025 17:18:38 +0000 Subject: [PATCH 1/5] gh-134009: Expose `PyMutex_IsLocked` in the public C API The `PyMutex_IsLocked()` function is useful in assertions for verifying that code maintains certain locking invariants. --- Doc/c-api/init.rst | 12 ++++++++++++ Include/cpython/lock.h | 11 +++++++++++ Include/internal/pycore_lock.h | 7 ------- .../2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst | 1 + Python/lock.c | 8 ++++++++ 5 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 9c866438b487d0..335fef546434fb 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -2291,6 +2291,18 @@ The C-API provides a basic mutual exclusion lock. .. versionadded:: 3.13 +.. c:function:: int PyMutex_IsLocked(PyMutex *m) + + Returns one if the mutex *m* is currently locked, zero otherwise. + + .. note:: + + This function is intended for use in assertions and debugging only and + should not be used to make concurrency control decisions, as the lock + state may change immediately after the check. + + .. versionadded:: 3.14 + .. _python-critical-section-api: Python Critical Section API diff --git a/Include/cpython/lock.h b/Include/cpython/lock.h index 8ee03e82f74dfd..bd34a668e8263e 100644 --- a/Include/cpython/lock.h +++ b/Include/cpython/lock.h @@ -36,6 +36,9 @@ PyAPI_FUNC(void) PyMutex_Lock(PyMutex *m); // exported function for unlocking the mutex PyAPI_FUNC(void) PyMutex_Unlock(PyMutex *m); +// exported function for unlocking the mutex +PyAPI_FUNC(int) PyMutex_IsLocked(PyMutex *m); + // Locks the mutex. // // If the mutex is currently locked, the calling thread will be parked until @@ -61,3 +64,11 @@ _PyMutex_Unlock(PyMutex *m) } } #define PyMutex_Unlock _PyMutex_Unlock + +// Checks if the mutex is currently locked. +static inline int +_PyMutex_IsLocked(PyMutex *m) +{ + return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0; +} +#define PyMutex_IsLocked _PyMutex_IsLocked diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h index 7484b05d7f2446..9b071573ad3c74 100644 --- a/Include/internal/pycore_lock.h +++ b/Include/internal/pycore_lock.h @@ -25,13 +25,6 @@ PyMutex_LockFast(PyMutex *m) return _Py_atomic_compare_exchange_uint8(lock_bits, &expected, _Py_LOCKED); } -// Checks if the mutex is currently locked. -static inline int -PyMutex_IsLocked(PyMutex *m) -{ - return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0; -} - // Re-initializes the mutex after a fork to the unlocked state. static inline void _PyMutex_at_fork_reinit(PyMutex *m) diff --git a/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst b/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst new file mode 100644 index 00000000000000..f060f09de19bb8 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst @@ -0,0 +1 @@ +Expose :c:func:`PyMutex_IsLocked` as part of the public C API. diff --git a/Python/lock.c b/Python/lock.c index 28a12ad18352d1..60e517d52f8a64 100644 --- a/Python/lock.c +++ b/Python/lock.c @@ -619,3 +619,11 @@ PyMutex_Unlock(PyMutex *m) Py_FatalError("unlocking mutex that is not locked"); } } + + +#undef PyMutex_IsLocked +int +PyMutex_IsLocked(PyMutex *m) +{ + return _PyMutex_IsLocked(m); +} From 42b8d5f79ffc680a14d5a792b8b920de5af9ef7c Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 22 May 2025 15:22:20 -0400 Subject: [PATCH 2/5] Update Doc/c-api/init.rst Co-authored-by: Victor Stinner --- Doc/c-api/init.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 335fef546434fb..636b035039ca24 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -2293,7 +2293,7 @@ The C-API provides a basic mutual exclusion lock. .. c:function:: int PyMutex_IsLocked(PyMutex *m) - Returns one if the mutex *m* is currently locked, zero otherwise. + Returns non-zero if the mutex *m* is currently locked, zero otherwise. .. note:: From 1f6e87a5278a306b1e795dcc8fa7e468faf8b1a2 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 22 May 2025 19:27:01 +0000 Subject: [PATCH 3/5] Changes from review --- Doc/c-api/init.rst | 2 +- Doc/whatsnew/3.15.rst | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 636b035039ca24..767d33099a0950 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -2301,7 +2301,7 @@ The C-API provides a basic mutual exclusion lock. should not be used to make concurrency control decisions, as the lock state may change immediately after the check. - .. versionadded:: 3.14 + .. versionadded:: next .. _python-critical-section-api: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index bf186c191b04d1..d665cc6cb7d41b 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -212,6 +212,13 @@ Porting to Python 3.15 (Contributed by Serhiy Storchaka in :gh:`133595`.) +* Private functions promoted to public C APIs: + + * ``PyMutex_IsLocked()`` : :c:func:`PyMutex_IsLocked` + + The `pythoncapi-compat project`_ can be used to get most of these new + functions on Python 3.14 and older. + Deprecated C APIs ----------------- From 64333f31962a1d6996cce0d2479853d58100bfb4 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 27 May 2025 16:08:07 +0000 Subject: [PATCH 4/5] Fix link --- Doc/whatsnew/3.15.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index d665cc6cb7d41b..f6a65d3947524e 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -216,7 +216,7 @@ Porting to Python 3.15 * ``PyMutex_IsLocked()`` : :c:func:`PyMutex_IsLocked` - The `pythoncapi-compat project`_ can be used to get most of these new + The |pythoncapi_compat_project| can be used to get most of these new functions on Python 3.14 and older. Deprecated C APIs From e1cee96eebfa8ddd1b8c6c08bddcf5a31d54cad4 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 27 May 2025 12:56:08 -0400 Subject: [PATCH 5/5] Update Include/cpython/lock.h Co-authored-by: Kumar Aditya --- Include/cpython/lock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/cpython/lock.h b/Include/cpython/lock.h index bd34a668e8263e..63886fca28eae2 100644 --- a/Include/cpython/lock.h +++ b/Include/cpython/lock.h @@ -36,7 +36,7 @@ PyAPI_FUNC(void) PyMutex_Lock(PyMutex *m); // exported function for unlocking the mutex PyAPI_FUNC(void) PyMutex_Unlock(PyMutex *m); -// exported function for unlocking the mutex +// exported function for checking if the mutex is locked PyAPI_FUNC(int) PyMutex_IsLocked(PyMutex *m); // Locks the mutex.