mirror of https://github.com/python/cpython
gh-116868: Avoid locking in PyType_IsSubtype (#116829)
Make PyType_IsSubType not acquire lock
This commit is contained in:
parent
ebf29b3a02
commit
280de3661b
|
@ -373,12 +373,23 @@ lookup_tp_mro(PyTypeObject *self)
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyType_GetMRO(PyTypeObject *self)
|
_PyType_GetMRO(PyTypeObject *self)
|
||||||
{
|
{
|
||||||
PyObject *mro;
|
#ifdef Py_GIL_DISABLED
|
||||||
|
PyObject *mro = _Py_atomic_load_ptr_relaxed(&self->tp_mro);
|
||||||
|
if (mro == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (_Py_TryIncref(&self->tp_mro, mro)) {
|
||||||
|
return mro;
|
||||||
|
}
|
||||||
|
|
||||||
BEGIN_TYPE_LOCK();
|
BEGIN_TYPE_LOCK();
|
||||||
mro = lookup_tp_mro(self);
|
mro = lookup_tp_mro(self);
|
||||||
Py_INCREF(mro);
|
Py_XINCREF(mro);
|
||||||
END_TYPE_LOCK()
|
END_TYPE_LOCK()
|
||||||
return mro;
|
return mro;
|
||||||
|
#else
|
||||||
|
return Py_XNewRef(lookup_tp_mro(self));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -911,7 +922,7 @@ PyType_Modified(PyTypeObject *type)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_subtype_unlocked(PyTypeObject *a, PyTypeObject *b);
|
is_subtype_with_mro(PyObject *a_mro, PyTypeObject *a, PyTypeObject *b);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
|
@ -957,7 +968,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
||||||
PyTypeObject *cls = _PyType_CAST(b);
|
PyTypeObject *cls = _PyType_CAST(b);
|
||||||
|
|
||||||
if (!is_subtype_unlocked(type, cls)) {
|
if (!is_subtype_with_mro(lookup_tp_mro(type), type, cls)) {
|
||||||
goto clear;
|
goto clear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1442,7 +1453,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
|
||||||
}
|
}
|
||||||
PyTypeObject *base = (PyTypeObject*)ob;
|
PyTypeObject *base = (PyTypeObject*)ob;
|
||||||
|
|
||||||
if (is_subtype_unlocked(base, type) ||
|
if (is_subtype_with_mro(lookup_tp_mro(base), base, type) ||
|
||||||
/* In case of reentering here again through a custom mro()
|
/* In case of reentering here again through a custom mro()
|
||||||
the above check is not enough since it relies on
|
the above check is not enough since it relies on
|
||||||
base->tp_mro which would gonna be updated inside
|
base->tp_mro which would gonna be updated inside
|
||||||
|
@ -2303,37 +2314,41 @@ type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_subtype_unlocked(PyTypeObject *a, PyTypeObject *b)
|
is_subtype_with_mro(PyObject *a_mro, PyTypeObject *a, PyTypeObject *b)
|
||||||
{
|
{
|
||||||
PyObject *mro;
|
int res;
|
||||||
|
if (a_mro != NULL) {
|
||||||
ASSERT_TYPE_LOCK_HELD();
|
|
||||||
mro = lookup_tp_mro(a);
|
|
||||||
if (mro != NULL) {
|
|
||||||
/* Deal with multiple inheritance without recursion
|
/* Deal with multiple inheritance without recursion
|
||||||
by walking the MRO tuple */
|
by walking the MRO tuple */
|
||||||
Py_ssize_t i, n;
|
Py_ssize_t i, n;
|
||||||
assert(PyTuple_Check(mro));
|
assert(PyTuple_Check(a_mro));
|
||||||
n = PyTuple_GET_SIZE(mro);
|
n = PyTuple_GET_SIZE(a_mro);
|
||||||
|
res = 0;
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
|
if (PyTuple_GET_ITEM(a_mro, i) == (PyObject *)b) {
|
||||||
return 1;
|
res = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
/* a is not completely initialized yet; follow tp_base */
|
/* a is not completely initialized yet; follow tp_base */
|
||||||
return type_is_subtype_base_chain(a, b);
|
res = type_is_subtype_base_chain(a, b);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
|
PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
|
||||||
{
|
{
|
||||||
int res;
|
#ifdef Py_GIL_DISABLED
|
||||||
BEGIN_TYPE_LOCK();
|
PyObject *mro = _PyType_GetMRO(a);
|
||||||
res = is_subtype_unlocked(a, b);
|
int res = is_subtype_with_mro(mro, a, b);
|
||||||
END_TYPE_LOCK()
|
Py_XDECREF(mro);
|
||||||
return res;
|
return res;
|
||||||
|
#else
|
||||||
|
return is_subtype_with_mro(lookup_tp_mro(a), a, b);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Routines to do a method lookup in the type without looking in the
|
/* Routines to do a method lookup in the type without looking in the
|
||||||
|
@ -2826,7 +2841,7 @@ mro_check(PyTypeObject *type, PyObject *mro)
|
||||||
}
|
}
|
||||||
PyTypeObject *base = (PyTypeObject*)obj;
|
PyTypeObject *base = (PyTypeObject*)obj;
|
||||||
|
|
||||||
if (!is_subtype_unlocked(solid, solid_base(base))) {
|
if (!is_subtype_with_mro(lookup_tp_mro(solid), solid, solid_base(base))) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"mro() returned base with unsuitable layout ('%.500s')",
|
"mro() returned base with unsuitable layout ('%.500s')",
|
||||||
|
@ -7082,28 +7097,29 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
|
||||||
#undef COPYVAL
|
#undef COPYVAL
|
||||||
|
|
||||||
/* Setup fast subclass flags */
|
/* Setup fast subclass flags */
|
||||||
if (is_subtype_unlocked(base, (PyTypeObject*)PyExc_BaseException)) {
|
PyObject *mro = lookup_tp_mro(base);
|
||||||
|
if (is_subtype_with_mro(mro, base, (PyTypeObject*)PyExc_BaseException)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyType_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyType_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyLong_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyLong_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyBytes_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyBytes_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyUnicode_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyUnicode_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyTuple_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyTuple_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyList_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyList_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
|
||||||
}
|
}
|
||||||
else if (is_subtype_unlocked(base, &PyDict_Type)) {
|
else if (is_subtype_with_mro(mro, base, &PyDict_Type)) {
|
||||||
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10204,7 +10220,7 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
|
||||||
d = (PyWrapperDescrObject *)descr;
|
d = (PyWrapperDescrObject *)descr;
|
||||||
if ((specific == NULL || specific == d->d_wrapped) &&
|
if ((specific == NULL || specific == d->d_wrapped) &&
|
||||||
d->d_base->wrapper == p->wrapper &&
|
d->d_base->wrapper == p->wrapper &&
|
||||||
is_subtype_unlocked(type, PyDescr_TYPE(d)))
|
is_subtype_with_mro(lookup_tp_mro(type), type, PyDescr_TYPE(d)))
|
||||||
{
|
{
|
||||||
specific = d->d_wrapped;
|
specific = d->d_wrapped;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue