Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Speed up ``set >= set``, ``set > set``, :meth:`set.issuperset`, :meth:`set.discard`
and :meth:`set.remove` on the free-threaded build by not re-entering a critical
section already held on the set.
25 changes: 20 additions & 5 deletions Objects/setobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,27 +411,39 @@ set_insert_clean(setentry *table, size_t mask, PyObject *key, Py_hash_t hash)
/* ======================================================================== */

static int
set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash, setentry **epp)
set_lookkey_lock_held(PySetObject *so, PyObject *key, Py_hash_t hash,
setentry **epp)
{
int status;
if (PyFrozenSet_CheckExact(so)) {
status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
set_compare_frozenset);
}
else {
Py_BEGIN_CRITICAL_SECTION(so);
do {
status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
set_compare_entry_lock_held);
} while (status == SET_LOOKKEY_CHANGED);
Py_END_CRITICAL_SECTION();
}
assert(status == SET_LOOKKEY_FOUND ||
status == SET_LOOKKEY_NO_MATCH ||
status == SET_LOOKKEY_ERROR);
return status;
}

static int
set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash, setentry **epp)
{
if (PyFrozenSet_CheckExact(so)) {
return set_lookkey_lock_held(so, key, hash, epp);
}
int status;
Py_BEGIN_CRITICAL_SECTION(so);
status = set_lookkey_lock_held(so, key, hash, epp);
Py_END_CRITICAL_SECTION();
return status;
}

#ifdef Py_GIL_DISABLED
static int
set_lookkey_threadsafe(PySetObject *so, PyObject *key, Py_hash_t hash)
Expand Down Expand Up @@ -581,7 +593,7 @@ set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
{
setentry *entry;
PyObject *old_key;
int status = set_lookkey(so, key, hash, &entry);
int status = set_lookkey_lock_held(so, key, hash, &entry);
if (status < 0) {
return -1;
}
Expand Down Expand Up @@ -2418,6 +2430,9 @@ set_issubset_impl(PySetObject *so, PyObject *other)
Py_ssize_t pos = 0;
int rv;

_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);

if (!PyAnySet_Check(other)) {
PyObject *tmp = set_intersection(so, other);
if (tmp == NULL) {
Expand Down Expand Up @@ -2460,7 +2475,7 @@ set_issuperset_impl(PySetObject *so, PyObject *other)
/*[clinic end generated code: output=ecf00ce552c09461 input=5f2e1f262e6e4ccc]*/
{
if (PyAnySet_Check(other)) {
return set_issubset(other, (PyObject *)so);
return set_issubset_impl((PySetObject *)other, (PyObject *)so);
}

PyObject *key, *it = PyObject_GetIter(other);
Expand Down
Loading