Skip to content

Commit 707942f

Browse files
dpdanimiss-islington
authored andcommitted
gh-150902: Optimize PyCriticalSection2 to skip locking the same locks held by the current CS2
This mimics an optimization already present for the single-mutex critical section. (cherry picked from commit c2ca772) Co-authored-by: Daniele Parmeggiani <8658291+dpdani@users.noreply.github.com>
1 parent 60132db commit 707942f

3 files changed

Lines changed: 20 additions & 4 deletions

File tree

Include/internal/pycore_critical_section.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,9 @@ _PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b)
195195
static inline void
196196
_PyCriticalSection2_End(PyCriticalSection2 *c)
197197
{
198-
// if mutex1 is NULL, we used the fast path in
199-
// _PyCriticalSection_BeginSlow for mutexes that are already held,
200-
// which should only happen when mutex1 and mutex2 were the same mutex,
201-
// and mutex2 should also be NULL.
198+
// if mutex1 is NULL, we used the fast path in either
199+
// _PyCriticalSection_BeginSlow or _PyCriticalSection2_BeginSlow for mutexes
200+
// that are already held, and mutex2 should also be NULL.
202201
if (c->_cs_base._cs_mutex == NULL) {
203202
assert(c->_cs_mutex2 == NULL);
204203
return;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Apply an existing optimization of PyCriticalSection (single mutex) to PyCriticalSection2: avoid acquiring the same locks that the current CS has already acquired.

Python/critical_section.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,22 @@ _PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2,
7474
c->_cs_base._cs_prev = 0;
7575
return;
7676
}
77+
// Same optimization as in _PyCriticalSection_BeginSlow: skip locking when
78+
// recursively acquiring the same locks.
79+
if (tstate->critical_section &&
80+
tstate->critical_section & _Py_CRITICAL_SECTION_TWO_MUTEXES) {
81+
PyCriticalSection2 *prev2 = (PyCriticalSection2 *)
82+
untag_critical_section(tstate->critical_section);
83+
assert((uintptr_t)m1 < (uintptr_t)m2);
84+
assert((uintptr_t)prev2->_cs_base._cs_mutex <
85+
(uintptr_t)prev2->_cs_mutex2);
86+
if (prev2->_cs_base._cs_mutex == m1 && prev2->_cs_mutex2 == m2) {
87+
c->_cs_base._cs_mutex = NULL;
88+
c->_cs_mutex2 = NULL;
89+
c->_cs_base._cs_prev = 0;
90+
return;
91+
}
92+
}
7793
c->_cs_base._cs_mutex = NULL;
7894
c->_cs_mutex2 = NULL;
7995
c->_cs_base._cs_prev = tstate->critical_section;

0 commit comments

Comments
 (0)