gh-140476: optimize PySet_Add for frozenset in free-threading (#140440)

Avoids critical section in `PySet_Add` when adding items to newly created frozensets.

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
Alper 2025-11-11 12:27:21 -08:00 committed by GitHub
parent b5196fa15a
commit 298e9074cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 9 deletions

View file

@ -0,0 +1,2 @@
Optimize :c:func:`PySet_Add` for :class:`frozenset` in :term:`free threaded
<free threading>` build.

View file

@ -2775,17 +2775,24 @@ PySet_Discard(PyObject *set, PyObject *key)
int int
PySet_Add(PyObject *anyset, PyObject *key) PySet_Add(PyObject *anyset, PyObject *key)
{ {
if (!PySet_Check(anyset) && if (PySet_Check(anyset)) {
(!PyFrozenSet_Check(anyset) || !_PyObject_IsUniquelyReferenced(anyset))) { int rv;
PyErr_BadInternalCall(); Py_BEGIN_CRITICAL_SECTION(anyset);
return -1; rv = set_add_key((PySetObject *)anyset, key);
Py_END_CRITICAL_SECTION();
return rv;
} }
int rv; if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) {
Py_BEGIN_CRITICAL_SECTION(anyset); // We can only change frozensets if they are uniquely referenced. The
rv = set_add_key((PySetObject *)anyset, key); // API limits the usage of `PySet_Add` to "fill in the values of brand
Py_END_CRITICAL_SECTION(); // new frozensets before they are exposed to other code". In this case,
return rv; // this can be done without a lock.
return set_add_key((PySetObject *)anyset, key);
}
PyErr_BadInternalCall();
return -1;
} }
int int