mirror of
https://github.com/python/cpython.git
synced 2025-11-25 21:11:09 +00:00
gh-119344: Make critical section API public (#119353)
This makes the following macros public as part of the non-limited C-API for locking a single object or two objects at once. * `Py_BEGIN_CRITICAL_SECTION(op)` / `Py_END_CRITICAL_SECTION()` * `Py_BEGIN_CRITICAL_SECTION2(a, b)` / `Py_END_CRITICAL_SECTION2()` The supporting functions and structs used by the macros are also exposed for cases where C macros are not available.
This commit is contained in:
parent
03fa2df927
commit
8f17d69b7b
15 changed files with 459 additions and 225 deletions
|
|
@ -62,24 +62,13 @@ class object "PyObject *" "&PyBaseObject_Type"
|
|||
// be released and reacquired during a subclass update if there's contention
|
||||
// on the subclass lock.
|
||||
#define TYPE_LOCK &PyInterpreterState_Get()->types.mutex
|
||||
#define BEGIN_TYPE_LOCK() \
|
||||
{ \
|
||||
_PyCriticalSection _cs; \
|
||||
_PyCriticalSection_Begin(&_cs, TYPE_LOCK); \
|
||||
#define BEGIN_TYPE_LOCK() Py_BEGIN_CRITICAL_SECTION_MUT(TYPE_LOCK)
|
||||
#define END_TYPE_LOCK() Py_END_CRITICAL_SECTION()
|
||||
|
||||
#define END_TYPE_LOCK() \
|
||||
_PyCriticalSection_End(&_cs); \
|
||||
}
|
||||
#define BEGIN_TYPE_DICT_LOCK(d) \
|
||||
Py_BEGIN_CRITICAL_SECTION2_MUT(TYPE_LOCK, &_PyObject_CAST(d)->ob_mutex)
|
||||
|
||||
#define BEGIN_TYPE_DICT_LOCK(d) \
|
||||
{ \
|
||||
_PyCriticalSection2 _cs; \
|
||||
_PyCriticalSection2_Begin(&_cs, TYPE_LOCK, \
|
||||
&_PyObject_CAST(d)->ob_mutex); \
|
||||
|
||||
#define END_TYPE_DICT_LOCK() \
|
||||
_PyCriticalSection2_End(&_cs); \
|
||||
}
|
||||
#define END_TYPE_DICT_LOCK() Py_END_CRITICAL_SECTION2()
|
||||
|
||||
#define ASSERT_TYPE_LOCK_HELD() \
|
||||
_Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(TYPE_LOCK)
|
||||
|
|
@ -442,7 +431,7 @@ _PyType_GetBases(PyTypeObject *self)
|
|||
BEGIN_TYPE_LOCK();
|
||||
res = lookup_tp_bases(self);
|
||||
Py_INCREF(res);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -513,7 +502,7 @@ _PyType_GetMRO(PyTypeObject *self)
|
|||
BEGIN_TYPE_LOCK();
|
||||
mro = lookup_tp_mro(self);
|
||||
Py_XINCREF(mro);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return mro;
|
||||
#else
|
||||
return Py_XNewRef(lookup_tp_mro(self));
|
||||
|
|
@ -951,10 +940,10 @@ PyType_Watch(int watcher_id, PyObject* obj)
|
|||
return -1;
|
||||
}
|
||||
// ensure we will get a callback on the next modification
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
assign_version_tag(interp, type);
|
||||
type->tp_watched |= (1 << watcher_id);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1080,9 +1069,9 @@ PyType_Modified(PyTypeObject *type)
|
|||
return;
|
||||
}
|
||||
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
type_modified_unlocked(type);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1161,9 +1150,9 @@ void
|
|||
_PyType_SetVersion(PyTypeObject *tp, unsigned int version)
|
||||
{
|
||||
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
set_version_unlocked(tp, version);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
}
|
||||
|
||||
PyTypeObject *
|
||||
|
|
@ -1245,9 +1234,9 @@ int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
|
|||
{
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
int assigned;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
assigned = assign_version_tag(interp, type);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return assigned;
|
||||
}
|
||||
|
||||
|
|
@ -1532,7 +1521,7 @@ type_get_mro(PyTypeObject *type, void *context)
|
|||
{
|
||||
PyObject *mro;
|
||||
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
mro = lookup_tp_mro(type);
|
||||
if (mro == NULL) {
|
||||
mro = Py_None;
|
||||
|
|
@ -1540,7 +1529,7 @@ type_get_mro(PyTypeObject *type, void *context)
|
|||
Py_INCREF(mro);
|
||||
}
|
||||
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return mro;
|
||||
}
|
||||
|
||||
|
|
@ -3121,9 +3110,9 @@ static PyObject *
|
|||
mro_implementation(PyTypeObject *type)
|
||||
{
|
||||
PyObject *mro;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
mro = mro_implementation_unlocked(type);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return mro;
|
||||
}
|
||||
|
||||
|
|
@ -3310,9 +3299,9 @@ static int
|
|||
mro_internal(PyTypeObject *type, PyObject **p_old_mro)
|
||||
{
|
||||
int res;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
res = mro_internal_unlocked(type, 0, p_old_mro);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -5173,7 +5162,7 @@ get_module_by_def(PyTypeObject *type, PyModuleDef *def)
|
|||
}
|
||||
|
||||
PyObject *res = NULL;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
|
||||
PyObject *mro = lookup_tp_mro(type);
|
||||
// The type must be ready
|
||||
|
|
@ -5200,7 +5189,7 @@ get_module_by_def(PyTypeObject *type, PyModuleDef *def)
|
|||
break;
|
||||
}
|
||||
}
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -5458,13 +5447,13 @@ _PyType_LookupRef(PyTypeObject *type, PyObject *name)
|
|||
|
||||
int has_version = 0;
|
||||
int version = 0;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
res = find_name_in_mro(type, name, &error);
|
||||
if (MCACHE_CACHEABLE_NAME(name)) {
|
||||
has_version = assign_version_tag(interp, type);
|
||||
version = type->tp_version_tag;
|
||||
}
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
|
||||
/* Only put NULL results into cache if there was no error. */
|
||||
if (error) {
|
||||
|
|
@ -8454,14 +8443,14 @@ PyType_Ready(PyTypeObject *type)
|
|||
}
|
||||
|
||||
int res;
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
if (!(type->tp_flags & Py_TPFLAGS_READY)) {
|
||||
res = type_ready(type, 1);
|
||||
} else {
|
||||
res = 0;
|
||||
assert(_PyType_CheckConsistency(type));
|
||||
}
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -8495,7 +8484,7 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self,
|
|||
int res;
|
||||
BEGIN_TYPE_LOCK();
|
||||
res = type_ready(self, initial);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
if (res < 0) {
|
||||
_PyStaticType_ClearWeakRefs(interp, self);
|
||||
managed_static_type_state_clear(interp, self, isbuiltin, initial);
|
||||
|
|
@ -8967,7 +8956,7 @@ hackcheck(PyObject *self, setattrofunc func, const char *what)
|
|||
int res;
|
||||
BEGIN_TYPE_LOCK();
|
||||
res = hackcheck_unlocked(self, func, what);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -10896,14 +10885,14 @@ fixup_slot_dispatchers(PyTypeObject *type)
|
|||
// This lock isn't strictly necessary because the type has not been
|
||||
// exposed to anyone else yet, but update_ont_slot calls find_name_in_mro
|
||||
// where we'd like to assert that the type is locked.
|
||||
BEGIN_TYPE_LOCK()
|
||||
BEGIN_TYPE_LOCK();
|
||||
|
||||
assert(!PyErr_Occurred());
|
||||
for (pytype_slotdef *p = slotdefs; p->name; ) {
|
||||
p = update_one_slot(type, p);
|
||||
}
|
||||
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -11192,7 +11181,7 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *
|
|||
another thread can modify it after we end the critical section
|
||||
below */
|
||||
Py_XINCREF(mro);
|
||||
END_TYPE_LOCK()
|
||||
END_TYPE_LOCK();
|
||||
|
||||
if (mro == NULL)
|
||||
return NULL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue