/src/cpython/Python/critical_section.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "Python.h" |
2 | | |
3 | | #include "pycore_lock.h" |
4 | | #include "pycore_critical_section.h" |
5 | | |
6 | | #ifdef Py_GIL_DISABLED |
7 | | static_assert(_Alignof(PyCriticalSection) >= 4, |
8 | | "critical section must be aligned to at least 4 bytes"); |
9 | | #endif |
10 | | |
11 | | #ifdef Py_GIL_DISABLED |
12 | | static PyCriticalSection * |
13 | | untag_critical_section(uintptr_t tag) |
14 | | { |
15 | | return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); |
16 | | } |
17 | | #endif |
18 | | |
19 | | void |
20 | | _PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m) |
21 | 0 | { |
22 | | #ifdef Py_GIL_DISABLED |
23 | | PyThreadState *tstate = _PyThreadState_GET(); |
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 (tstate->critical_section && |
28 | | untag_critical_section(tstate->critical_section)->_cs_mutex == m) { |
29 | | c->_cs_mutex = NULL; |
30 | | c->_cs_prev = 0; |
31 | | return; |
32 | | } |
33 | | c->_cs_mutex = NULL; |
34 | | c->_cs_prev = (uintptr_t)tstate->critical_section; |
35 | | tstate->critical_section = (uintptr_t)c; |
36 | | |
37 | | PyMutex_Lock(m); |
38 | | c->_cs_mutex = m; |
39 | | #endif |
40 | 0 | } |
41 | | |
42 | | void |
43 | | _PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, |
44 | | int is_m1_locked) |
45 | 0 | { |
46 | | #ifdef Py_GIL_DISABLED |
47 | | PyThreadState *tstate = _PyThreadState_GET(); |
48 | | c->_cs_base._cs_mutex = NULL; |
49 | | c->_cs_mutex2 = NULL; |
50 | | c->_cs_base._cs_prev = tstate->critical_section; |
51 | | tstate->critical_section = (uintptr_t)c | _Py_CRITICAL_SECTION_TWO_MUTEXES; |
52 | | |
53 | | if (!is_m1_locked) { |
54 | | PyMutex_Lock(m1); |
55 | | } |
56 | | PyMutex_Lock(m2); |
57 | | c->_cs_base._cs_mutex = m1; |
58 | | c->_cs_mutex2 = m2; |
59 | | #endif |
60 | 0 | } |
61 | | |
62 | | |
63 | | // Release all locks held by critical sections. This is called by |
64 | | // _PyThreadState_Detach. |
65 | | void |
66 | | _PyCriticalSection_SuspendAll(PyThreadState *tstate) |
67 | 0 | { |
68 | | #ifdef Py_GIL_DISABLED |
69 | | uintptr_t *tagptr = &tstate->critical_section; |
70 | | while (_PyCriticalSection_IsActive(*tagptr)) { |
71 | | PyCriticalSection *c = untag_critical_section(*tagptr); |
72 | | |
73 | | if (c->_cs_mutex) { |
74 | | PyMutex_Unlock(c->_cs_mutex); |
75 | | if ((*tagptr & _Py_CRITICAL_SECTION_TWO_MUTEXES)) { |
76 | | PyCriticalSection2 *c2 = (PyCriticalSection2 *)c; |
77 | | if (c2->_cs_mutex2) { |
78 | | PyMutex_Unlock(c2->_cs_mutex2); |
79 | | } |
80 | | } |
81 | | } |
82 | | |
83 | | *tagptr |= _Py_CRITICAL_SECTION_INACTIVE; |
84 | | tagptr = &c->_cs_prev; |
85 | | } |
86 | | #endif |
87 | 0 | } |
88 | | |
89 | | void |
90 | | _PyCriticalSection_Resume(PyThreadState *tstate) |
91 | 0 | { |
92 | | #ifdef Py_GIL_DISABLED |
93 | | uintptr_t p = tstate->critical_section; |
94 | | PyCriticalSection *c = untag_critical_section(p); |
95 | | assert(!_PyCriticalSection_IsActive(p)); |
96 | | |
97 | | PyMutex *m1 = c->_cs_mutex; |
98 | | c->_cs_mutex = NULL; |
99 | | |
100 | | PyMutex *m2 = NULL; |
101 | | PyCriticalSection2 *c2 = NULL; |
102 | | if ((p & _Py_CRITICAL_SECTION_TWO_MUTEXES)) { |
103 | | c2 = (PyCriticalSection2 *)c; |
104 | | m2 = c2->_cs_mutex2; |
105 | | c2->_cs_mutex2 = NULL; |
106 | | } |
107 | | |
108 | | if (m1) { |
109 | | PyMutex_Lock(m1); |
110 | | } |
111 | | if (m2) { |
112 | | PyMutex_Lock(m2); |
113 | | } |
114 | | |
115 | | c->_cs_mutex = m1; |
116 | | if (m2) { |
117 | | c2->_cs_mutex2 = m2; |
118 | | } |
119 | | |
120 | | tstate->critical_section &= ~_Py_CRITICAL_SECTION_INACTIVE; |
121 | | #endif |
122 | 0 | } |
123 | | |
124 | | #undef PyCriticalSection_Begin |
125 | | void |
126 | | PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op) |
127 | 0 | { |
128 | | #ifdef Py_GIL_DISABLED |
129 | | _PyCriticalSection_Begin(c, op); |
130 | | #endif |
131 | 0 | } |
132 | | |
133 | | #undef PyCriticalSection_End |
134 | | void |
135 | | PyCriticalSection_End(PyCriticalSection *c) |
136 | 0 | { |
137 | | #ifdef Py_GIL_DISABLED |
138 | | _PyCriticalSection_End(c); |
139 | | #endif |
140 | 0 | } |
141 | | |
142 | | #undef PyCriticalSection2_Begin |
143 | | void |
144 | | PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b) |
145 | 0 | { |
146 | | #ifdef Py_GIL_DISABLED |
147 | | _PyCriticalSection2_Begin(c, a, b); |
148 | | #endif |
149 | 0 | } |
150 | | |
151 | | #undef PyCriticalSection2_End |
152 | | void |
153 | | PyCriticalSection2_End(PyCriticalSection2 *c) |
154 | 0 | { |
155 | | #ifdef Py_GIL_DISABLED |
156 | | _PyCriticalSection2_End(c); |
157 | | #endif |
158 | 0 | } |