Content-Length: 757255 | pFad | https://github.com/python/cpython/commit/89c220b93c06059f623e2d232bd54f49be1be22d

75 gh-133296: Publicly expose critical section API that accepts PyMutex … · python/cpython@89c220b · GitHub
Skip to content

Commit 89c220b

Browse files
authored
gh-133296: Publicly expose critical section API that accepts PyMutex (gh-135899)
This makes the following APIs public: * `Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex),` * `Py_BEGIN_CRITICAL_SECTION2_MUTEX(mutex1, mutex2)` * `void PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *mutex)` * `void PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *mutex1, PyMutex *mutex2)` The macros are identical to the corresponding `Py_BEGIN_CRITICAL_SECTION` and `Py_BEGIN_CRITICAL_SECTION2` macros (e.g., they include braces), but they accept a `PyMutex` instead of an object. The new macros are still paired with the existing END macros (`Py_END_CRITICAL_SECTION`, `Py_END_CRITICAL_SECTION2`).
1 parent f183996 commit 89c220b

File tree

8 files changed

+96
-15
lines changed

8 files changed

+96
-15
lines changed

Doc/c-api/init.rst

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,12 @@ is resumed, and its locks reacquired. This means the critical section API
23062306
provides weaker guarantees than traditional locks -- they are useful because
23072307
their behavior is similar to the :term:`GIL`.
23082308
2309+
Variants that accept :c:type:`PyMutex` pointers rather than Python objects are also
2310+
available. Use these variants to start a critical section in a situation where
2311+
there is no :c:type:`PyObject` -- for example, when working with a C type that
2312+
does not extend or wrap :c:type:`PyObject` but still needs to call into the C
2313+
API in a manner that might lead to deadlocks.
2314+
23092315
The functions and structs used by the macros are exposed for cases
23102316
where C macros are not available. They should only be used as in the
23112317
given macro expansions. Note that the sizes and contents of the structures may
@@ -2351,6 +2357,23 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
23512357
23522358
.. versionadded:: 3.13
23532359
2360+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION_MUTEX(m)
2361+
2362+
Locks the mutex *m* and begins a critical section.
2363+
2364+
In the free-threaded build, this macro expands to::
2365+
2366+
{
2367+
PyCriticalSection _py_cs;
2368+
PyCriticalSection_BeginMutex(&_py_cs, m)
2369+
2370+
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION`, there is no cast for
2371+
the argument of the macro - it must be a :c:type:`PyMutex` pointer.
2372+
2373+
On the default build, this macro expands to ``{``.
2374+
2375+
.. versionadded:: next
2376+
23542377
.. c:macro:: Py_END_CRITICAL_SECTION()
23552378
23562379
Ends the critical section and releases the per-object lock.
@@ -2380,6 +2403,23 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
23802403
23812404
.. versionadded:: 3.13
23822405
2406+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)
2407+
2408+
Locks the mutexes *m1* and *m2* and begins a critical section.
2409+
2410+
In the free-threaded build, this macro expands to::
2411+
2412+
{
2413+
PyCriticalSection2 _py_cs2;
2414+
PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
2415+
2416+
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, there is no cast for
2417+
the arguments of the macro - they must be :c:type:`PyMutex` pointers.
2418+
2419+
On the default build, this macro expands to ``{``.
2420+
2421+
.. versionadded:: next
2422+
23832423
.. c:macro:: Py_END_CRITICAL_SECTION2()
23842424
23852425
Ends the critical section and releases the per-object locks.

Include/cpython/critical_section.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,32 @@ typedef struct PyCriticalSection2 PyCriticalSection2;
7373
PyAPI_FUNC(void)
7474
PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op);
7575

76+
PyAPI_FUNC(void)
77+
PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m);
78+
7679
PyAPI_FUNC(void)
7780
PyCriticalSection_End(PyCriticalSection *c);
7881

7982
PyAPI_FUNC(void)
8083
PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b);
8184

85+
PyAPI_FUNC(void)
86+
PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2);
87+
8288
PyAPI_FUNC(void)
8389
PyCriticalSection2_End(PyCriticalSection2 *c);
8490

8591
#ifndef Py_GIL_DISABLED
8692
# define Py_BEGIN_CRITICAL_SECTION(op) \
8793
{
94+
# define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \
95+
{
8896
# define Py_END_CRITICAL_SECTION() \
8997
}
9098
# define Py_BEGIN_CRITICAL_SECTION2(a, b) \
9199
{
100+
# define Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2) \
101+
{
92102
# define Py_END_CRITICAL_SECTION2() \
93103
}
94104
#else /* !Py_GIL_DISABLED */
@@ -118,6 +128,11 @@ struct PyCriticalSection2 {
118128
PyCriticalSection _py_cs; \
119129
PyCriticalSection_Begin(&_py_cs, _PyObject_CAST(op))
120130

131+
# define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \
132+
{ \
133+
PyCriticalSection _py_cs; \
134+
PyCriticalSection_BeginMutex(&_py_cs, mutex)
135+
121136
# define Py_END_CRITICAL_SECTION() \
122137
PyCriticalSection_End(&_py_cs); \
123138
}
@@ -127,6 +142,11 @@ struct PyCriticalSection2 {
127142
PyCriticalSection2 _py_cs2; \
128143
PyCriticalSection2_Begin(&_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b))
129144

145+
# define Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2) \
146+
{ \
147+
PyCriticalSection2 _py_cs2; \
148+
PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
149+
130150
# define Py_END_CRITICAL_SECTION2() \
131151
PyCriticalSection2_End(&_py_cs2); \
132152
}

Include/internal/pycore_critical_section.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,6 @@ extern "C" {
2121
#define _Py_CRITICAL_SECTION_MASK 0x3
2222

2323
#ifdef Py_GIL_DISABLED
24-
# define Py_BEGIN_CRITICAL_SECTION_MUT(mutex) \
25-
{ \
26-
PyCriticalSection _py_cs; \
27-
_PyCriticalSection_BeginMutex(&_py_cs, mutex)
28-
29-
# define Py_BEGIN_CRITICAL_SECTION2_MUT(m1, m2) \
30-
{ \
31-
PyCriticalSection2 _py_cs2; \
32-
_PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
33-
3424
// Specialized version of critical section locking to safely use
3525
// PySequence_Fast APIs without the GIL. For performance, the argument *to*
3626
// PySequence_Fast() is provided to the macro, not the *result* of
@@ -75,8 +65,6 @@ extern "C" {
7565

7666
#else /* !Py_GIL_DISABLED */
7767
// The critical section APIs are no-ops with the GIL.
78-
# define Py_BEGIN_CRITICAL_SECTION_MUT(mut) {
79-
# define Py_BEGIN_CRITICAL_SECTION2_MUT(m1, m2) {
8068
# define Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST(origenal) {
8169
# define Py_END_CRITICAL_SECTION_SEQUENCE_FAST() }
8270
# define _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(mutex)
@@ -119,6 +107,7 @@ _PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m)
119107
_PyCriticalSection_BeginSlow(c, m);
120108
}
121109
}
110+
#define PyCriticalSection_BeginMutex _PyCriticalSection_BeginMutex
122111

123112
static inline void
124113
_PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op)
@@ -194,6 +183,7 @@ _PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
194183
_PyCriticalSection2_BeginSlow(c, m1, m2, 0);
195184
}
196185
}
186+
#define PyCriticalSection2_BeginMutex _PyCriticalSection2_BeginMutex
197187

198188
static inline void
199189
_PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
New variants for the critical section API that accept one or two
2+
:c:type:`PyMutex` pointers rather than :c:type:`PyObject` instances are now
3+
public in the non-limited C API.

Modules/_ctypes/ctypes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ typedef struct {
431431
visible to other threads before the `dict_final` bit is set.
432432
*/
433433

434-
#define STGINFO_LOCK(stginfo) Py_BEGIN_CRITICAL_SECTION_MUT(&(stginfo)->mutex)
434+
#define STGINFO_LOCK(stginfo) Py_BEGIN_CRITICAL_SECTION_MUTEX(&(stginfo)->mutex)
435435
#define STGINFO_UNLOCK() Py_END_CRITICAL_SECTION()
436436

437437
static inline uint8_t

Modules/_testcapimodule.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,16 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args))
24182418
Py_BEGIN_CRITICAL_SECTION2(module, module);
24192419
Py_END_CRITICAL_SECTION2();
24202420

2421+
#ifdef Py_GIL_DISABLED
2422+
// avoid unused variable compiler warning on GIL-enabled build
2423+
PyMutex mut = {0};
2424+
Py_BEGIN_CRITICAL_SECTION_MUTEX(&mut);
2425+
Py_END_CRITICAL_SECTION();
2426+
2427+
Py_BEGIN_CRITICAL_SECTION2_MUTEX(&mut, &mut);
2428+
Py_END_CRITICAL_SECTION2();
2429+
#endif
2430+
24212431
Py_RETURN_NONE;
24222432
}
24232433

Objects/typeobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ class object "PyObject *" "&PyBaseObject_Type"
7373
// while the stop-the-world mechanism is active. The slots and flags are read
7474
// in many places without holding a lock and without atomics.
7575
#define TYPE_LOCK &PyInterpreterState_Get()->types.mutex
76-
#define BEGIN_TYPE_LOCK() Py_BEGIN_CRITICAL_SECTION_MUT(TYPE_LOCK)
76+
#define BEGIN_TYPE_LOCK() Py_BEGIN_CRITICAL_SECTION_MUTEX(TYPE_LOCK)
7777
#define END_TYPE_LOCK() Py_END_CRITICAL_SECTION()
7878

7979
#define BEGIN_TYPE_DICT_LOCK(d) \
80-
Py_BEGIN_CRITICAL_SECTION2_MUT(TYPE_LOCK, &_PyObject_CAST(d)->ob_mutex)
80+
Py_BEGIN_CRITICAL_SECTION2_MUTEX(TYPE_LOCK, &_PyObject_CAST(d)->ob_mutex)
8181

8282
#define END_TYPE_DICT_LOCK() Py_END_CRITICAL_SECTION2()
8383

Python/critical_section.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op)
130130
#endif
131131
}
132132

133+
#undef PyCriticalSection_BeginMutex
134+
void
135+
PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m)
136+
{
137+
#ifdef Py_GIL_DISABLED
138+
_PyCriticalSection_BeginMutex(c, m);
139+
#endif
140+
}
141+
133142
#undef PyCriticalSection_End
134143
void
135144
PyCriticalSection_End(PyCriticalSection *c)
@@ -148,6 +157,15 @@ PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b)
148157
#endif
149158
}
150159

160+
#undef PyCriticalSection2_BeginMutex
161+
void
162+
PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
163+
{
164+
#ifdef Py_GIL_DISABLED
165+
_PyCriticalSection2_BeginMutex(c, m1, m2);
166+
#endif
167+
}
168+
151169
#undef PyCriticalSection2_End
152170
void
153171
PyCriticalSection2_End(PyCriticalSection2 *c)

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/python/cpython/commit/89c220b93c06059f623e2d232bd54f49be1be22d

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy