]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-150902: Optimize PyCriticalSection2 to skip locking the same locks held...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 19 Jun 2026 13:51:55 +0000 (15:51 +0200)
committerGitHub <noreply@github.com>
Fri, 19 Jun 2026 13:51:55 +0000 (09:51 -0400)
This mimics an optimization already present for the single-mutex critical section.
(cherry picked from commit c2ca7724af94df6e078a4b2e86d1be8c410d9940)

Co-authored-by: Daniele Parmeggiani <8658291+dpdani@users.noreply.github.com>
Include/internal/pycore_critical_section.h
Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst [new file with mode: 0644]
Python/critical_section.c

index 2b49b9f00df3ea5bde0822aca0014a56d391f952..942bcff7e01df77dff71275fe9f9219c53c0fb97 100644 (file)
@@ -195,10 +195,9 @@ _PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b)
 static inline void
 _PyCriticalSection2_End(PyCriticalSection2 *c)
 {
-    // if mutex1 is NULL, we used the fast path in
-    // _PyCriticalSection_BeginSlow for mutexes that are already held,
-    // which should only happen when mutex1 and mutex2 were the same mutex,
-    // and mutex2 should also be NULL.
+    // if mutex1 is NULL, we used the fast path in either
+    // _PyCriticalSection_BeginSlow or _PyCriticalSection2_BeginSlow for mutexes
+    // that are already held, and mutex2 should also be NULL.
     if (c->_cs_base._cs_mutex == NULL) {
         assert(c->_cs_mutex2 == NULL);
         return;
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-08-13-14-42.gh-issue-150902.-CWZ66.rst
new file mode 100644 (file)
index 0000000..e3b7cd3
--- /dev/null
@@ -0,0 +1 @@
+Apply an existing optimization of PyCriticalSection (single mutex) to PyCriticalSection2: avoid acquiring the same locks that the current CS has already acquired.
index 11a3f027547f39068f39157fcd10667ff35330f0..d3df5caddae6d07f446b1de0c196fa5c6d85c254 100644 (file)
@@ -74,6 +74,22 @@ _PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2,
         c->_cs_base._cs_prev = 0;
         return;
     }
+    // Same optimization as in _PyCriticalSection_BeginSlow: skip locking when
+    // recursively acquiring the same locks.
+    if (tstate->critical_section &&
+        tstate->critical_section & _Py_CRITICAL_SECTION_TWO_MUTEXES) {
+        PyCriticalSection2 *prev2 = (PyCriticalSection2 *)
+            untag_critical_section(tstate->critical_section);
+        assert((uintptr_t)m1 < (uintptr_t)m2);
+        assert((uintptr_t)prev2->_cs_base._cs_mutex <
+            (uintptr_t)prev2->_cs_mutex2);
+        if (prev2->_cs_base._cs_mutex == m1 && prev2->_cs_mutex2 == m2) {
+            c->_cs_base._cs_mutex = NULL;
+            c->_cs_mutex2 = NULL;
+            c->_cs_base._cs_prev = 0;
+            return;
+        }
+    }
     c->_cs_base._cs_mutex = NULL;
     c->_cs_mutex2 = NULL;
     c->_cs_base._cs_prev = tstate->critical_section;