From: mpage Date: Fri, 29 Mar 2024 17:42:02 +0000 (-0700) Subject: gh-111926: Avoid locking in PyType_IsSubtype (#117275) X-Git-Tag: v3.13.0a6~104 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5d21d884b6ffa45dac50a5f9a07c41356a8478b4;p=thirdparty%2FPython%2Fcpython.git gh-111926: Avoid locking in PyType_IsSubtype (#117275) Read the MRO in a thread-unsafe way in `PyType_IsSubtype` to avoid locking. Fixing this is tracked in #117306. The motivation for this change is in support of making weakrefs thread-safe in free-threaded builds: `WeakValueDictionary` uses a special dictionary function, `_PyDict_DelItemIf` to remove dead weakrefs from the dictionary. `_PyDict_DelItemIf` removes a key if a user supplied predicate evaluates to true for the value associated with the key. Crucially for the `WeakValueDictionary` use case, the predicate evaluation + deletion sequence is atomic, provided that the predicate doesn’t suspend. The predicate used by `WeakValueDictionary` includes a subtype check, which we must ensure doesn't suspend in free-threaded builds. --- diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 82822784aaf4..2ef79fbf17b3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2341,14 +2341,7 @@ is_subtype_with_mro(PyObject *a_mro, PyTypeObject *a, PyTypeObject *b) int PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) { -#ifdef Py_GIL_DISABLED - PyObject *mro = _PyType_GetMRO(a); - int res = is_subtype_with_mro(mro, a, b); - Py_XDECREF(mro); - return res; -#else - return is_subtype_with_mro(lookup_tp_mro(a), a, b); -#endif + return is_subtype_with_mro(a->tp_mro, a, b); } /* Routines to do a method lookup in the type without looking in the