https://github.com/python/cpython/commit/298e9074cdffb09d518e6aceea556e8f4a8a745d
commit: 298e9074cdffb09d518e6aceea556e8f4a8a745d
branch: main
author: Alper <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-11-12T01:57:21+05:30
summary:

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 <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst
M Objects/setobject.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst
new file mode 100644
index 00000000000000..a24033208c558c
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst
@@ -0,0 +1,2 @@
+Optimize :c:func:`PySet_Add` for :class:`frozenset` in :term:`free threaded
+<free threading>` build.
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 2401176576eb62..85f4d7d403178a 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -2775,17 +2775,24 @@ PySet_Discard(PyObject *set, PyObject *key)
 int
 PySet_Add(PyObject *anyset, PyObject *key)
 {
-    if (!PySet_Check(anyset) &&
-        (!PyFrozenSet_Check(anyset) || 
!_PyObject_IsUniquelyReferenced(anyset))) {
-        PyErr_BadInternalCall();
-        return -1;
+    if (PySet_Check(anyset)) {
+        int rv;
+        Py_BEGIN_CRITICAL_SECTION(anyset);
+        rv = set_add_key((PySetObject *)anyset, key);
+        Py_END_CRITICAL_SECTION();
+        return rv;
     }
 
-    int rv;
-    Py_BEGIN_CRITICAL_SECTION(anyset);
-    rv = set_add_key((PySetObject *)anyset, key);
-    Py_END_CRITICAL_SECTION();
-    return rv;
+    if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) {
+        // We can only change frozensets if they are uniquely referenced. The
+        // API limits the usage of `PySet_Add` to "fill in the values of brand
+        // new frozensets before they are exposed to other code". In this case,
+        // this can be done without a lock.
+        return set_add_key((PySetObject *)anyset, key);
+    }
+
+    PyErr_BadInternalCall();
+    return -1;
 }
 
 int

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to