bpo-34872: Fix self-cancellation in C implementation of asyncio.Task#9679
Conversation
The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.
async def task1():
async def task2():
await task3 # task3 is never cancelled
asyncio.current_task().cancel()
await asyncio.create_task(task2())
The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.
Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.
| PyObject *r; | ||
| r = future_cancel(fut); | ||
| int is_true; | ||
| r = _PyObject_CallMethodId(fut, &PyId_cancel, NULL); |
There was a problem hiding this comment.
The fix is correct.
But I'd like to go one step forward: use Future_CheckExact and Task_CheckExact to call future_cancel() and _asyncio_Task_cancel_impl() as fast paths.
There was a problem hiding this comment.
Id keep it as simple as possible as it needs to be backported to 3.6 & 3.7. A proper refactoring for C code is needed anyways, and I'll add this optimization.
|
Sorry, @elprans and @1st1, I could not cleanly backport this to |
|
Sorry, @elprans and @1st1, I could not cleanly backport this to |
|
@elprans please submit two PRs to backport the change to 3.7 and 3.6. The automatic cherry-picking has failed :( |
|
GH-9690 is a backport of this pull request to the 3.6 branch. |
….Task (pythonGH-9679) The C implementation of asyncio.Task currently fails to perform the cancellation cleanup correctly in the following scenario. async def task1(): async def task2(): await task3 # task3 is never cancelled asyncio.current_task().cancel() await asyncio.create_task(task2()) The actuall error is a hardcoded call to `future_cancel()` instead of calling the `cancel()` method of a future-like object. Thanks to Vladimir Matveev for noticing the code discrepancy and to Yury Selivanov for coming up with a pathological scenario. (cherry picked from commit 548ce9d)
|
GH-9691 is a backport of this pull request to the 3.7 branch. |
….Task (pythonGH-9679) The C implementation of asyncio.Task currently fails to perform the cancellation cleanup correctly in the following scenario. async def task1(): async def task2(): await task3 # task3 is never cancelled asyncio.current_task().cancel() await asyncio.create_task(task2()) The actuall error is a hardcoded call to `future_cancel()` instead of calling the `cancel()` method of a future-like object. Thanks to Vladimir Matveev for noticing the code discrepancy and to Yury Selivanov for coming up with a pathological scenario.. (cherry picked from commit 548ce9d) Co-authored-by: Elvis Pranskevichus <elvis@magic.io>
….Task (GH-9679) (GH-9690) The C implementation of asyncio.Task currently fails to perform the cancellation cleanup correctly in the following scenario. async def task1(): async def task2(): await task3 # task3 is never cancelled asyncio.current_task().cancel() await asyncio.create_task(task2()) The actuall error is a hardcoded call to `future_cancel()` instead of calling the `cancel()` method of a future-like object. Thanks to Vladimir Matveev for noticing the code discrepancy and to Yury Selivanov for coming up with a pathological scenario. (cherry picked from commit 548ce9d) https://bugs.python.org/issue34872
….Task (GH-9679) (GH-9691) The C implementation of asyncio.Task currently fails to perform the cancellation cleanup correctly in the following scenario. async def task1(): async def task2(): await task3 # task3 is never cancelled asyncio.current_task().cancel() await asyncio.create_task(task2()) The actuall error is a hardcoded call to `future_cancel()` instead of calling the `cancel()` method of a future-like object. Thanks to Vladimir Matveev for noticing the code discrepancy and to Yury Selivanov for coming up with a pathological scenario.. (cherry picked from commit 548ce9d) Co-authored-by: Elvis Pranskevichus <elvis@magic.io> https://bugs.python.org/issue34872
The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.
The actuall error is a hardcoded call to
future_cancel()instead ofcalling the
cancel()method of a future-like object.Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.
https://bugs.python.org/issue34872