Skip to content

Commit 280de36

Browse files
authored
gh-116868: Avoid locking in PyType_IsSubtype (#116829)
Make PyType_IsSubType not acquire lock
1 parent ebf29b3 commit 280de36

File tree

1 file changed

+48
-32
lines changed

1 file changed

+48
-32
lines changed

Objects/typeobject.c

+48-32
Original file line numberDiff line numberDiff line change
@@ -373,12 +373,23 @@ lookup_tp_mro(PyTypeObject *self)
373373
PyObject *
374374
_PyType_GetMRO(PyTypeObject *self)
375375
{
376-
PyObject *mro;
376+
#ifdef Py_GIL_DISABLED
377+
PyObject *mro = _Py_atomic_load_ptr_relaxed(&self->tp_mro);
378+
if (mro == NULL) {
379+
return NULL;
380+
}
381+
if (_Py_TryIncref(&self->tp_mro, mro)) {
382+
return mro;
383+
}
384+
377385
BEGIN_TYPE_LOCK();
378386
mro = lookup_tp_mro(self);
379-
Py_INCREF(mro);
387+
Py_XINCREF(mro);
380388
END_TYPE_LOCK()
381389
return mro;
390+
#else
391+
return Py_XNewRef(lookup_tp_mro(self));
392+
#endif
382393
}
383394

384395
static inline void
@@ -911,7 +922,7 @@ PyType_Modified(PyTypeObject *type)
911922
}
912923

913924
static int
914-
is_subtype_unlocked(PyTypeObject *a, PyTypeObject *b);
925+
is_subtype_with_mro(PyObject *a_mro, PyTypeObject *a, PyTypeObject *b);
915926

916927
static void
917928
type_mro_modified(PyTypeObject *type, PyObject *bases) {
@@ -957,7 +968,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
957968
PyObject *b = PyTuple_GET_ITEM(bases, i);
958969
PyTypeObject *cls = _PyType_CAST(b);
959970

960-
if (!is_subtype_unlocked(type, cls)) {
971+
if (!is_subtype_with_mro(lookup_tp_mro(type), type, cls)) {
961972
goto clear;
962973
}
963974
}
@@ -1442,7 +1453,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
14421453
}
14431454
PyTypeObject *base = (PyTypeObject*)ob;
14441455

1445-
if (is_subtype_unlocked(base, type) ||
1456+
if (is_subtype_with_mro(lookup_tp_mro(base), base, type) ||
14461457
/* In case of reentering here again through a custom mro()
14471458
the above check is not enough since it relies on
14481459
base->tp_mro which would gonna be updated inside
@@ -2303,37 +2314,41 @@ type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b)
23032314
}
23042315

23052316
static int
2306-
is_subtype_unlocked(PyTypeObject *a, PyTypeObject *b)
2317+
is_subtype_with_mro(PyObject *a_mro, PyTypeObject *a, PyTypeObject *b)
23072318
{
2308-
PyObject *mro;
2309-
2310-
ASSERT_TYPE_LOCK_HELD();
2311-
mro = lookup_tp_mro(a);
2312-
if (mro != NULL) {
2319+
int res;
2320+
if (a_mro != NULL) {
23132321
/* Deal with multiple inheritance without recursion
23142322
by walking the MRO tuple */
23152323
Py_ssize_t i, n;
2316-
assert(PyTuple_Check(mro));
2317-
n = PyTuple_GET_SIZE(mro);
2324+
assert(PyTuple_Check(a_mro));
2325+
n = PyTuple_GET_SIZE(a_mro);
2326+
res = 0;
23182327
for (i = 0; i < n; i++) {
2319-
if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
2320-
return 1;
2328+
if (PyTuple_GET_ITEM(a_mro, i) == (PyObject *)b) {
2329+
res = 1;
2330+
break;
2331+
}
23212332
}
2322-
return 0;
23232333
}
2324-
else
2334+
else {
23252335
/* a is not completely initialized yet; follow tp_base */
2326-
return type_is_subtype_base_chain(a, b);
2336+
res = type_is_subtype_base_chain(a, b);
2337+
}
2338+
return res;
23272339
}
23282340

23292341
int
23302342
PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
23312343
{
2332-
int res;
2333-
BEGIN_TYPE_LOCK();
2334-
res = is_subtype_unlocked(a, b);
2335-
END_TYPE_LOCK()
2344+
#ifdef Py_GIL_DISABLED
2345+
PyObject *mro = _PyType_GetMRO(a);
2346+
int res = is_subtype_with_mro(mro, a, b);
2347+
Py_XDECREF(mro);
23362348
return res;
2349+
#else
2350+
return is_subtype_with_mro(lookup_tp_mro(a), a, b);
2351+
#endif
23372352
}
23382353

23392354
/* Routines to do a method lookup in the type without looking in the
@@ -2826,7 +2841,7 @@ mro_check(PyTypeObject *type, PyObject *mro)
28262841
}
28272842
PyTypeObject *base = (PyTypeObject*)obj;
28282843

2829-
if (!is_subtype_unlocked(solid, solid_base(base))) {
2844+
if (!is_subtype_with_mro(lookup_tp_mro(solid), solid, solid_base(base))) {
28302845
PyErr_Format(
28312846
PyExc_TypeError,
28322847
"mro() returned base with unsuitable layout ('%.500s')",
@@ -7082,28 +7097,29 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
70827097
#undef COPYVAL
70837098

70847099
/* Setup fast subclass flags */
7085-
if (is_subtype_unlocked(base, (PyTypeObject*)PyExc_BaseException)) {
7100+
PyObject *mro = lookup_tp_mro(base);
7101+
if (is_subtype_with_mro(mro, base, (PyTypeObject*)PyExc_BaseException)) {
70867102
type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
70877103
}
7088-
else if (is_subtype_unlocked(base, &PyType_Type)) {
7104+
else if (is_subtype_with_mro(mro, base, &PyType_Type)) {
70897105
type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
70907106
}
7091-
else if (is_subtype_unlocked(base, &PyLong_Type)) {
7107+
else if (is_subtype_with_mro(mro, base, &PyLong_Type)) {
70927108
type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
70937109
}
7094-
else if (is_subtype_unlocked(base, &PyBytes_Type)) {
7110+
else if (is_subtype_with_mro(mro, base, &PyBytes_Type)) {
70957111
type->tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS;
70967112
}
7097-
else if (is_subtype_unlocked(base, &PyUnicode_Type)) {
7113+
else if (is_subtype_with_mro(mro, base, &PyUnicode_Type)) {
70987114
type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS;
70997115
}
7100-
else if (is_subtype_unlocked(base, &PyTuple_Type)) {
7116+
else if (is_subtype_with_mro(mro, base, &PyTuple_Type)) {
71017117
type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
71027118
}
7103-
else if (is_subtype_unlocked(base, &PyList_Type)) {
7119+
else if (is_subtype_with_mro(mro, base, &PyList_Type)) {
71047120
type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
71057121
}
7106-
else if (is_subtype_unlocked(base, &PyDict_Type)) {
7122+
else if (is_subtype_with_mro(mro, base, &PyDict_Type)) {
71077123
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
71087124
}
71097125

@@ -10204,7 +10220,7 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1020410220
d = (PyWrapperDescrObject *)descr;
1020510221
if ((specific == NULL || specific == d->d_wrapped) &&
1020610222
d->d_base->wrapper == p->wrapper &&
10207-
is_subtype_unlocked(type, PyDescr_TYPE(d)))
10223+
is_subtype_with_mro(lookup_tp_mro(type), type, PyDescr_TYPE(d)))
1020810224
{
1020910225
specific = d->d_wrapped;
1021010226
}

0 commit comments

Comments
 (0)