From c74ca9b3661eab4626d9387b61a76b52a9ed92c3 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 1 Jul 2025 13:26:13 -0400 Subject: [PATCH] [3.14] gh-134009: Expose `PyMutex_IsLocked` in the public C API (gh-134365) The `PyMutex_IsLocked()` function is useful in assertions for verifying that code maintains certain locking invariants. (cherry picked from commit f41e9c750e6971c165e055374a1014d6afd2d50e) Co-authored-by: Sam Gross --- Doc/c-api/init.rst | 12 ++++++++++++ Doc/whatsnew/3.14.rst | 1 + 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 ++++++++ 6 files changed, 33 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 dc96ed7f719fcf..13524e6ae7c9ec 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -2441,6 +2441,18 @@ The C-API provides a basic mutual exclusion lock. .. versionadded:: 3.13 +.. c:function:: int PyMutex_IsLocked(PyMutex *m) + + Returns non-zero 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/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 630d011ffbbd1f..2906828e05d229 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -3027,6 +3027,7 @@ Porting to Python 3.14 * ``_PyLong_IsPositive()``: :c:func:`PyLong_IsPositive` * ``_PyLong_IsZero()``: :c:func:`PyLong_IsZero` * ``_PyLong_Sign()``: :c:func:`PyLong_GetSign` + * ``_PyMutex_IsLocked()`` : :c:func:`PyMutex_IsLocked` * ``_PyUnicodeWriter_Dealloc()``: :c:func:`PyUnicodeWriter_Discard` * ``_PyUnicodeWriter_Finish()``: :c:func:`PyUnicodeWriter_Finish` * ``_PyUnicodeWriter_Init()``: use :c:func:`PyUnicodeWriter_Create` diff --git a/Include/cpython/lock.h b/Include/cpython/lock.h index 8ee03e82f74dfd..63886fca28eae2 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 checking if the mutex is locked +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 3c0804c468e08d..ca269bd2cb4b51 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); +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy