mirror of
https://github.com/python/cpython.git
synced 2025-10-17 20:28:43 +00:00
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:
parent
e6b25e9a09
commit
a15feded71
4 changed files with 49 additions and 46 deletions
|
@ -1994,30 +1994,36 @@ enter_task(asyncio_state *state, PyObject *loop, PyObject *task)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
err_leave_task(PyObject *item, PyObject *task)
|
||||
{
|
||||
PyErr_Format(
|
||||
PyExc_RuntimeError,
|
||||
"Leaving task %R does not match the current task %R.",
|
||||
task, item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
leave_task_predicate(PyObject *item, void *task)
|
||||
{
|
||||
if (item != task) {
|
||||
return err_leave_task(item, (PyObject *)task);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
leave_task(asyncio_state *state, PyObject *loop, PyObject *task)
|
||||
/*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/
|
||||
{
|
||||
PyObject *item;
|
||||
Py_hash_t hash;
|
||||
hash = PyObject_Hash(loop);
|
||||
if (hash == -1) {
|
||||
return -1;
|
||||
int res = _PyDict_DelItemIf(state->current_tasks, loop,
|
||||
leave_task_predicate, task);
|
||||
if (res == 0) {
|
||||
// task was not found
|
||||
return err_leave_task(Py_None, task);
|
||||
}
|
||||
item = _PyDict_GetItem_KnownHash(state->current_tasks, loop, hash);
|
||||
if (item != task) {
|
||||
if (item == NULL) {
|
||||
/* Not entered, replace with None */
|
||||
item = Py_None;
|
||||
}
|
||||
PyErr_Format(
|
||||
PyExc_RuntimeError,
|
||||
"Leaving task %R does not match the current task %R.",
|
||||
task, item, NULL);
|
||||
return -1;
|
||||
}
|
||||
return _PyDict_DelItem_KnownHash(state->current_tasks, loop, hash);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
|
@ -31,7 +31,7 @@ _weakref_getweakrefcount_impl(PyObject *module, PyObject *object)
|
|||
|
||||
|
||||
static int
|
||||
is_dead_weakref(PyObject *value)
|
||||
is_dead_weakref(PyObject *value, void *unused)
|
||||
{
|
||||
if (!PyWeakref_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "not a weakref");
|
||||
|
@ -56,15 +56,8 @@ _weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct,
|
|||
PyObject *key)
|
||||
/*[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]*/
|
||||
{
|
||||
if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) {
|
||||
if (PyErr_ExceptionMatches(PyExc_KeyError))
|
||||
/* This function is meant to allow safe weak-value dicts
|
||||
with GC in another thread (see issue #28427), so it's
|
||||
ok if the key doesn't exist anymore.
|
||||
*/
|
||||
PyErr_Clear();
|
||||
else
|
||||
return NULL;
|
||||
if (_PyDict_DelItemIf(dct, key, is_dead_weakref, NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue