22# error "this header file must not be included directly"
33#endif
44
5- // Python critical sections
6- //
7- // Conceptually, critical sections are a deadlock avoidance layer on top of
8- // per-object locks. These helpers, in combination with those locks, replace
9- // our usage of the global interpreter lock to provide thread-safety for
10- // otherwise thread-unsafe objects, such as dict.
11- //
12- // NOTE: These APIs are no-ops in non-free-threaded builds.
13- //
145// Straightforward per-object locking could introduce deadlocks that were not
156// present when running with the GIL. Threads may hold locks for multiple
167// objects simultaneously because Python operations can nest. If threads were
4334// `_PyThreadState_Attach()`, it resumes the top-most (i.e., most recent)
4435// critical section by reacquiring the associated lock or locks. See
4536// `_PyCriticalSection_Resume()`.
46- //
47- // NOTE: Only the top-most critical section is guaranteed to be active.
48- // Operations that need to lock two objects at once must use
49- // `Py_BEGIN_CRITICAL_SECTION2()`. You *CANNOT* use nested critical sections
50- // to lock more than one object at once, because the inner critical section
51- // may suspend the outer critical sections. This API does not provide a way
52- // to lock more than two objects at once (though it could be added later
53- // if actually needed).
54- //
55- // NOTE: Critical sections implicitly behave like reentrant locks because
56- // attempting to acquire the same lock will suspend any outer (earlier)
57- // critical sections. However, they are less efficient for this use case than
58- // purposefully designed reentrant locks.
59- //
60- // Example usage:
61- // Py_BEGIN_CRITICAL_SECTION(op);
62- // ...
63- // Py_END_CRITICAL_SECTION();
64- //
65- // To lock two objects at once:
66- // Py_BEGIN_CRITICAL_SECTION2(op1, op2);
67- // ...
68- // Py_END_CRITICAL_SECTION2();
69-
70- typedef struct PyCriticalSection PyCriticalSection ;
71- typedef struct PyCriticalSection2 PyCriticalSection2 ;
72-
73- PyAPI_FUNC (void )
74- PyCriticalSection_Begin (PyCriticalSection * c , PyObject * op );
7537
7638PyAPI_FUNC (void )
7739PyCriticalSection_BeginMutex (PyCriticalSection * c , PyMutex * m );
7840
79- PyAPI_FUNC (void )
80- PyCriticalSection_End (PyCriticalSection * c );
81-
82- PyAPI_FUNC (void )
83- PyCriticalSection2_Begin (PyCriticalSection2 * c , PyObject * a , PyObject * b );
84-
8541PyAPI_FUNC (void )
8642PyCriticalSection2_BeginMutex (PyCriticalSection2 * c , PyMutex * m1 , PyMutex * m2 );
8743
88- PyAPI_FUNC (void )
89- PyCriticalSection2_End (PyCriticalSection2 * c );
90-
9144#ifndef Py_GIL_DISABLED
45+ #undef Py_BEGIN_CRITICAL_SECTION
46+ #undef Py_END_CRITICAL_SECTION
47+ #undef Py_BEGIN_CRITICAL_SECTION2
48+ #undef Py_END_CRITICAL_SECTION2
49+
9250# define Py_BEGIN_CRITICAL_SECTION (op ) \
9351 {
9452# define Py_BEGIN_CRITICAL_SECTION_MUTEX (mutex ) \
@@ -101,54 +59,17 @@ PyCriticalSection2_End(PyCriticalSection2 *c);
10159 {
10260# define Py_END_CRITICAL_SECTION2 () \
10361 }
104- #else /* !Py_GIL_DISABLED */
105-
106- // NOTE: the contents of this struct are private and may change betweeen
107- // Python releases without a deprecation period.
108- struct PyCriticalSection {
109- // Tagged pointer to an outer active critical section (or 0).
110- uintptr_t _cs_prev ;
111-
112- // Mutex used to protect critical section
113- PyMutex * _cs_mutex ;
114- };
115-
116- // A critical section protected by two mutexes. Use
117- // Py_BEGIN_CRITICAL_SECTION2 and Py_END_CRITICAL_SECTION2.
118- // NOTE: the contents of this struct are private and may change betweeen
119- // Python releases without a deprecation period.
120- struct PyCriticalSection2 {
121- PyCriticalSection _cs_base ;
12262
123- PyMutex * _cs_mutex2 ;
124- };
125-
126- # define Py_BEGIN_CRITICAL_SECTION (op ) \
127- { \
128- PyCriticalSection _py_cs; \
129- PyCriticalSection_Begin(&_py_cs, _PyObject_CAST(op))
63+ #else /* !Py_GIL_DISABLED */
13064
13165# define Py_BEGIN_CRITICAL_SECTION_MUTEX (mutex ) \
13266 { \
13367 PyCriticalSection _py_cs; \
13468 PyCriticalSection_BeginMutex(&_py_cs, mutex)
13569
136- # define Py_END_CRITICAL_SECTION () \
137- PyCriticalSection_End(&_py_cs); \
138- }
139-
140- # define Py_BEGIN_CRITICAL_SECTION2 (a , b ) \
141- { \
142- PyCriticalSection2 _py_cs2; \
143- PyCriticalSection2_Begin(&_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b))
144-
14570# define Py_BEGIN_CRITICAL_SECTION2_MUTEX (m1 , m2 ) \
14671 { \
14772 PyCriticalSection2 _py_cs2; \
14873 PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
14974
150- # define Py_END_CRITICAL_SECTION2 () \
151- PyCriticalSection2_End(&_py_cs2); \
152- }
153-
154- #endif
75+ #endif /* !Py_GIL_DISABLED */
0 commit comments