/src/cpython/Python/critical_section.c
Line | Count | Source |
1 | | #include "Python.h" |
2 | | |
3 | | #include "pycore_critical_section.h" |
4 | | #include "pycore_interp.h" |
5 | | #include "pycore_lock.h" |
6 | | |
7 | | #ifdef Py_GIL_DISABLED |
8 | | static_assert(_Alignof(PyCriticalSection) >= 4, |
9 | | "critical section must be aligned to at least 4 bytes"); |
10 | | #endif |
11 | | |
12 | | #ifdef Py_GIL_DISABLED |
13 | | static PyCriticalSection * |
14 | | untag_critical_section(uintptr_t tag) |
15 | | { |
16 | | return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); |
17 | | } |
18 | | #endif |
19 | | |
20 | | void |
21 | | _PyCriticalSection_BeginSlow(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m) |
22 | 0 | { |
23 | | #ifdef Py_GIL_DISABLED |
24 | | // As an optimisation for locking the same object recursively, skip |
25 | | // locking if the mutex is currently locked by the top-most critical |
26 | | // section. |
27 | | // If the top-most critical section is a two-mutex critical section, |
28 | | // then locking is skipped if either mutex is m. |
29 | | if (tstate->critical_section) { |
30 | | PyCriticalSection *prev = untag_critical_section(tstate->critical_section); |
31 | | if (prev->_cs_mutex == m) { |
32 | | c->_cs_mutex = NULL; |
33 | | c->_cs_prev = 0; |
34 | | return; |
35 | | } |
36 | | if (tstate->critical_section & _Py_CRITICAL_SECTION_TWO_MUTEXES) { |
37 | | PyCriticalSection2 *prev2 = (PyCriticalSection2 *) |
38 | | untag_critical_section(tstate->critical_section); |
39 | | if (prev2->_cs_mutex2 == m) { |
40 | | c->_cs_mutex = NULL; |
41 | | c->_cs_prev = 0; |
42 | | return; |
43 | | } |
44 | | } |
45 | | } |
46 | | // If the world is stopped, we don't need to acquire the lock because |
47 | | // there are no other threads that could be accessing the object. |
48 | | // Without this check, acquiring a critical section while the world is |
49 | | // stopped could lead to a deadlock. |
50 | | if (tstate->interp->stoptheworld.world_stopped) { |
51 | | c->_cs_mutex = NULL; |
52 | | c->_cs_prev = 0; |
53 | | return; |
54 | | } |
55 | | c->_cs_mutex = NULL; |
56 | | c->_cs_prev = (uintptr_t)tstate->critical_section; |
57 | | tstate->critical_section = (uintptr_t)c; |
58 | | |
59 | | PyMutex_Lock(m); |
60 | | c->_cs_mutex = m; |
61 | | #endif |
62 | 0 | } |
63 | | |
64 | | void |
65 | | _PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, |
66 | | int is_m1_locked) |
67 | 0 | { |
68 | | #ifdef Py_GIL_DISABLED |
69 | | if (tstate->interp->stoptheworld.world_stopped) { |
70 | | c->_cs_base._cs_mutex = NULL; |
71 | | c->_cs_mutex2 = NULL; |
72 | | c->_cs_base._cs_prev = 0; |
73 | | return; |
74 | | } |
75 | | c->_cs_base._cs_mutex = NULL; |
76 | | c->_cs_mutex2 = NULL; |
77 | | c->_cs_base._cs_prev = tstate->critical_section; |
78 | | tstate->critical_section = (uintptr_t)c | _Py_CRITICAL_SECTION_TWO_MUTEXES; |
79 | | |
80 | | if (!is_m1_locked) { |
81 | | PyMutex_Lock(m1); |
82 | | } |
83 | | PyMutex_Lock(m2); |
84 | | c->_cs_base._cs_mutex = m1; |
85 | | c->_cs_mutex2 = m2; |
86 | | #endif |
87 | 0 | } |
88 | | |
89 | | |
90 | | // Release all locks held by critical sections. This is called by |
91 | | // _PyThreadState_Detach. |
92 | | void |
93 | | _PyCriticalSection_SuspendAll(PyThreadState *tstate) |
94 | 0 | { |
95 | | #ifdef Py_GIL_DISABLED |
96 | | uintptr_t *tagptr = &tstate->critical_section; |
97 | | while (_PyCriticalSection_IsActive(*tagptr)) { |
98 | | PyCriticalSection *c = untag_critical_section(*tagptr); |
99 | | |
100 | | if (c->_cs_mutex) { |
101 | | PyMutex_Unlock(c->_cs_mutex); |
102 | | if ((*tagptr & _Py_CRITICAL_SECTION_TWO_MUTEXES)) { |
103 | | PyCriticalSection2 *c2 = (PyCriticalSection2 *)c; |
104 | | if (c2->_cs_mutex2) { |
105 | | PyMutex_Unlock(c2->_cs_mutex2); |
106 | | } |
107 | | } |
108 | | } |
109 | | |
110 | | *tagptr |= _Py_CRITICAL_SECTION_INACTIVE; |
111 | | tagptr = &c->_cs_prev; |
112 | | } |
113 | | #endif |
114 | 0 | } |
115 | | |
116 | | void |
117 | | _PyCriticalSection_Resume(PyThreadState *tstate) |
118 | 0 | { |
119 | | #ifdef Py_GIL_DISABLED |
120 | | uintptr_t p = tstate->critical_section; |
121 | | PyCriticalSection *c = untag_critical_section(p); |
122 | | assert(!_PyCriticalSection_IsActive(p)); |
123 | | |
124 | | PyMutex *m1 = c->_cs_mutex; |
125 | | c->_cs_mutex = NULL; |
126 | | |
127 | | PyMutex *m2 = NULL; |
128 | | PyCriticalSection2 *c2 = NULL; |
129 | | if ((p & _Py_CRITICAL_SECTION_TWO_MUTEXES)) { |
130 | | c2 = (PyCriticalSection2 *)c; |
131 | | m2 = c2->_cs_mutex2; |
132 | | c2->_cs_mutex2 = NULL; |
133 | | } |
134 | | |
135 | | if (m1) { |
136 | | PyMutex_Lock(m1); |
137 | | } |
138 | | if (m2) { |
139 | | PyMutex_Lock(m2); |
140 | | } |
141 | | |
142 | | c->_cs_mutex = m1; |
143 | | if (m2) { |
144 | | c2->_cs_mutex2 = m2; |
145 | | } |
146 | | |
147 | | tstate->critical_section &= ~_Py_CRITICAL_SECTION_INACTIVE; |
148 | | #endif |
149 | 0 | } |
150 | | |
151 | | #undef PyCriticalSection_Begin |
152 | | void |
153 | | PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op) |
154 | 0 | { |
155 | | #ifdef Py_GIL_DISABLED |
156 | | _PyCriticalSection_Begin(_PyThreadState_GET(), c, op); |
157 | | #endif |
158 | 0 | } |
159 | | |
160 | | #undef PyCriticalSection_BeginMutex |
161 | | void |
162 | | PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m) |
163 | 0 | { |
164 | | #ifdef Py_GIL_DISABLED |
165 | | _PyCriticalSection_BeginMutex(_PyThreadState_GET(), c, m); |
166 | | #endif |
167 | 0 | } |
168 | | |
169 | | #undef PyCriticalSection_End |
170 | | void |
171 | | PyCriticalSection_End(PyCriticalSection *c) |
172 | 0 | { |
173 | | #ifdef Py_GIL_DISABLED |
174 | | _PyCriticalSection_End(_PyThreadState_GET(), c); |
175 | | #endif |
176 | 0 | } |
177 | | |
178 | | #undef PyCriticalSection2_Begin |
179 | | void |
180 | | PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b) |
181 | 0 | { |
182 | | #ifdef Py_GIL_DISABLED |
183 | | _PyCriticalSection2_Begin(_PyThreadState_GET(), c, a, b); |
184 | | #endif |
185 | 0 | } |
186 | | |
187 | | #undef PyCriticalSection2_BeginMutex |
188 | | void |
189 | | PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) |
190 | 0 | { |
191 | | #ifdef Py_GIL_DISABLED |
192 | | _PyCriticalSection2_BeginMutex(_PyThreadState_GET(), c, m1, m2); |
193 | | #endif |
194 | 0 | } |
195 | | |
196 | | #undef PyCriticalSection2_End |
197 | | void |
198 | | PyCriticalSection2_End(PyCriticalSection2 *c) |
199 | 0 | { |
200 | | #ifdef Py_GIL_DISABLED |
201 | | _PyCriticalSection2_End(_PyThreadState_GET(), c); |
202 | | #endif |
203 | 0 | } |