summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/critical_section.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/critical_section.c')
-rw-r--r--contrib/tools/python3/Python/critical_section.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/contrib/tools/python3/Python/critical_section.c b/contrib/tools/python3/Python/critical_section.c
new file mode 100644
index 00000000000..62ed25523fd
--- /dev/null
+++ b/contrib/tools/python3/Python/critical_section.c
@@ -0,0 +1,148 @@
+#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
+
+void
+_PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m)
+{
+#ifdef Py_GIL_DISABLED
+ PyThreadState *tstate = _PyThreadState_GET();
+ 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
+}
+
+#ifdef Py_GIL_DISABLED
+static PyCriticalSection *
+untag_critical_section(uintptr_t tag)
+{
+ return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK);
+}
+#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_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_End
+void
+PyCriticalSection2_End(PyCriticalSection2 *c)
+{
+#ifdef Py_GIL_DISABLED
+ _PyCriticalSection2_End(c);
+#endif
+}