Skip to content

Commit 298e907

Browse files
pythongh-140476: optimize PySet_Add for frozenset in free-threading (python#140440)
Avoids critical section in `PySet_Add` when adding items to newly created frozensets. Co-authored-by: Kumar Aditya <[email protected]>
1 parent b5196fa commit 298e907

File tree

2 files changed

+18
-9
lines changed

2 files changed

+18
-9
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Optimize :c:func:`PySet_Add` for :class:`frozenset` in :term:`free threaded
2+
<free threading>` build.

Objects/setobject.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,17 +2775,24 @@ PySet_Discard(PyObject *set, PyObject *key)
27752775
int
27762776
PySet_Add(PyObject *anyset, PyObject *key)
27772777
{
2778-
if (!PySet_Check(anyset) &&
2779-
(!PyFrozenSet_Check(anyset) || !_PyObject_IsUniquelyReferenced(anyset))) {
2780-
PyErr_BadInternalCall();
2781-
return -1;
2778+
if (PySet_Check(anyset)) {
2779+
int rv;
2780+
Py_BEGIN_CRITICAL_SECTION(anyset);
2781+
rv = set_add_key((PySetObject *)anyset, key);
2782+
Py_END_CRITICAL_SECTION();
2783+
return rv;
27822784
}
27832785

2784-
int rv;
2785-
Py_BEGIN_CRITICAL_SECTION(anyset);
2786-
rv = set_add_key((PySetObject *)anyset, key);
2787-
Py_END_CRITICAL_SECTION();
2788-
return rv;
2786+
if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) {
2787+
// We can only change frozensets if they are uniquely referenced. The
2788+
// API limits the usage of `PySet_Add` to "fill in the values of brand
2789+
// new frozensets before they are exposed to other code". In this case,
2790+
// this can be done without a lock.
2791+
return set_add_key((PySetObject *)anyset, key);
2792+
}
2793+
2794+
PyErr_BadInternalCall();
2795+
return -1;
27892796
}
27902797

27912798
int

0 commit comments

Comments
 (0)