https://github.com/python/cpython/commit/bf4017b16149ba17d723abacfe93aec79b2235fe
commit: bf4017b16149ba17d723abacfe93aec79b2235fe
branch: main
author: Farhan Saif <[email protected]>
committer: vstinner <[email protected]>
date: 2026-03-10T17:23:39+01:00
summary:

gh-125053: Document that ob_mutex must only be used via critical section API 
(#144599)

Add a warning in the free-threading extensions howto explaining that
PyObject.ob_mutex is reserved for the critical section API and must not
be locked directly with PyMutex_Lock, as this can cause deadlocks.
Extension authors who need their own lock should add a separate PyMutex
field to their object struct.

Also add an ob_mutex member entry under PyObject in the C API reference
(Doc/c-api/structures.rst) with a cross-reference to the howto.

Co-authored-by: Victor Stinner <[email protected]>

files:
M Doc/c-api/structures.rst
M Doc/howto/free-threading-extensions.rst

diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index 70c4de543b7d00..c0d2663adefc6b 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -48,6 +48,19 @@ under :ref:`reference counting <countingrefs>`.
       Do not use this field directly; use :c:macro:`Py_TYPE` and
       :c:func:`Py_SET_TYPE` instead.
 
+   .. c:member:: PyMutex ob_mutex
+
+      A :ref:`per-object lock <per-object-locks>`, present only in the 
:term:`free-threaded <free threading>`
+      build (when :c:macro:`Py_GIL_DISABLED` is defined).
+
+      This field is **reserved for use by the critical section API**
+      (:c:macro:`Py_BEGIN_CRITICAL_SECTION` / 
:c:macro:`Py_END_CRITICAL_SECTION`).
+      Do **not** lock it directly with ``PyMutex_Lock``; doing so can cause
+      deadlocks.  If you need your own lock, add a separate :c:type:`PyMutex`
+      field to your object struct.
+
+      .. versionadded:: 3.13
+
 
 .. c:type:: PyVarObject
 
diff --git a/Doc/howto/free-threading-extensions.rst 
b/Doc/howto/free-threading-extensions.rst
index 83eba8cfea3969..2f089a3d89680a 100644
--- a/Doc/howto/free-threading-extensions.rst
+++ b/Doc/howto/free-threading-extensions.rst
@@ -384,6 +384,30 @@ Important Considerations
   internal extension state, standard mutexes or other synchronization
   primitives might be more appropriate.
 
+.. _per-object-locks:
+
+Per-Object Locks (``ob_mutex``)
+...............................
+
+In the free-threaded build, each Python object contains a 
:c:member:`~PyObject.ob_mutex`
+field of type :c:type:`PyMutex`.  This mutex is **reserved for use by the
+critical section API** (:c:macro:`Py_BEGIN_CRITICAL_SECTION` /
+:c:macro:`Py_END_CRITICAL_SECTION`).
+
+.. warning::
+
+   Do **not** lock ``ob_mutex`` directly with ``PyMutex_Lock(&obj->ob_mutex)``.
+   Mixing direct ``PyMutex_Lock`` calls with the critical section API on the
+   same mutex can cause deadlocks.
+
+Even if your own code never uses critical sections on a particular object type,
+**CPython internals may use the critical section API on any Python object**.
+
+If your extension type needs its own lock, add a separate :c:type:`PyMutex`
+field (or another synchronization primitive) to your object struct.
+:c:type:`PyMutex` is very lightweight, so there is negligible cost to having
+an additional one.
+
 
 Building Extensions for the Free-Threaded Build
 ===============================================

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to