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