gh-120974: Make _asyncio._leave_task atomic in the free-threaded build (#122139)

* gh-120974: Make _asyncio._leave_task atomic in the free-threaded build

Update `_PyDict_DelItemIf` to allow for an argument to be passed to the
predicate.
This commit is contained in:
Sam Gross 2024-07-23 13:06:03 -04:00 committed by GitHub
parent e6b25e9a09
commit a15feded71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 46 deletions

View file

@ -2508,7 +2508,7 @@ delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
values->size = size;
}
static int
static void
delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
PyObject *old_value, uint64_t new_version)
{
@ -2550,7 +2550,6 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
Py_DECREF(old_value);
ASSERT_CONSISTENT(mp);
return 0;
}
int
@ -2593,7 +2592,8 @@ delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
PyInterpreterState *interp = _PyInterpreterState_GET();
uint64_t new_version = _PyDict_NotifyEvent(
interp, PyDict_EVENT_DELETED, mp, key, NULL);
return delitem_common(mp, hash, ix, old_value, new_version);
delitem_common(mp, hash, ix, old_value, new_version);
return 0;
}
int
@ -2608,7 +2608,8 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
static int
delitemif_lock_held(PyObject *op, PyObject *key,
int (*predicate)(PyObject *value))
int (*predicate)(PyObject *value, void *arg),
void *arg)
{
Py_ssize_t ix;
PyDictObject *mp;
@ -2618,24 +2619,20 @@ delitemif_lock_held(PyObject *op, PyObject *key,
ASSERT_DICT_LOCKED(op);
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
assert(key);
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
mp = (PyDictObject *)op;
ix = _Py_dict_lookup(mp, key, hash, &old_value);
if (ix == DKIX_ERROR)
return -1;
if (ix == DKIX_EMPTY || old_value == NULL) {
_PyErr_SetKeyError(key);
if (ix == DKIX_ERROR) {
return -1;
}
if (ix == DKIX_EMPTY || old_value == NULL) {
return 0;
}
res = predicate(old_value);
res = predicate(old_value, arg);
if (res == -1)
return -1;
@ -2643,7 +2640,8 @@ delitemif_lock_held(PyObject *op, PyObject *key,
PyInterpreterState *interp = _PyInterpreterState_GET();
uint64_t new_version = _PyDict_NotifyEvent(
interp, PyDict_EVENT_DELETED, mp, key, NULL);
return delitem_common(mp, hash, ix, old_value, new_version);
delitem_common(mp, hash, ix, old_value, new_version);
return 1;
} else {
return 0;
}
@ -2655,11 +2653,13 @@ delitemif_lock_held(PyObject *op, PyObject *key,
*/
int
_PyDict_DelItemIf(PyObject *op, PyObject *key,
int (*predicate)(PyObject *value))
int (*predicate)(PyObject *value, void *arg),
void *arg)
{
assert(PyDict_Check(op));
int res;
Py_BEGIN_CRITICAL_SECTION(op);
res = delitemif_lock_held(op, key, predicate);
res = delitemif_lock_held(op, key, predicate, arg);
Py_END_CRITICAL_SECTION();
return res;
}