classification
Title: task.cancel unbound recursion if task is deadlocked
Type: Stage:
Components: asyncio Versions: Python 3.10, Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Dima.Tisnek, asvetlov, chris.jerdonek, crusaderky, yselivanov
Priority: normal Keywords:

Created on 2019-03-28 02:52 by Dima.Tisnek, last changed 2021-01-21 08:35 by Dima.Tisnek.

Messages (2)
msg339006 - (view) Author: Dima Tisnek (Dima.Tisnek) * Date: 2019-03-28 02:52
Cancelling a deadlocked group of tasks results in MaximumRecursionError

Inspired by https://stackoverflow.com/questions/55341189/handling-asyncio-deadlocks

Given the following test-asyncio.py:

```
import asyncio


async def test():
    async def f():
        await g_task

    async def g():
        await f_task

    f_task = asyncio.create_task(f())
    g_task = asyncio.create_task(g())

    async def release():
        await asyncio.sleep(5)
        f_task.cancel()

    await asyncio.gather(f_task, g_task, release())

asyncio.run(test())
```

Results in:

```
Traceback (most recent call last):
  File ".../python3.8/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File ".../python3.8/asyncio/base_events.py", line 589, in run_until_complete
    return future.result()
  File "test-asyncio.py", line 18, in test
    await asyncio.gather(f_task, g_task, release())
  File "test-asyncio.py", line 16, in release
    f_task.cancel()
RecursionError: maximum recursion depth exceeded while calling a Python object

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test-asyncio.py", line 20, in <module>
    asyncio.run(test())
  File ".../python3.8/asyncio/runners.py", line 46, in run
    _cancel_all_tasks(loop)
  File ".../python3.8/asyncio/runners.py", line 59, in _cancel_all_tasks
    task.cancel()
RecursionError: maximum recursion depth exceeded while calling a Python object
Exception in default exception handler
Traceback (most recent call last):
  File ".../python3.8/asyncio/base_events.py", line 1644, in call_exception_handler
    self.default_exception_handler(context)
  File ".../python3.8/asyncio/base_events.py", line 1615, in default_exception_handler
    value = repr(value)
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  [Previous line repeated 326 more times]
  File ".../python3.8/asyncio/base_tasks.py", line 9, in _task_repr_info
    info = base_futures._future_repr_info(task)
  File ".../python3.8/asyncio/base_futures.py", line 57, in _future_repr_info
    info.append(_format_callbacks(future._callbacks))
  File ".../python3.8/asyncio/base_futures.py", line 36, in _format_callbacks
    cb = '{}, {}'.format(format_cb(cb[0][0]), format_cb(cb[1][0]))
  File ".../python3.8/asyncio/base_futures.py", line 31, in format_cb
    return format_helpers._format_callback_source(callback, ())
  File ".../python3.8/asyncio/format_helpers.py", line 23, in _format_callback_source
    func_repr = _format_callback(func, args, None)
  File ".../python3.8/asyncio/format_helpers.py", line 56, in _format_callback
    func_repr += _format_args_and_kwargs(args, kwargs)
  File ".../python3.8/asyncio/format_helpers.py", line 41, in _format_args_and_kwargs
    return '({})'.format(', '.join(items))
RecursionError: maximum recursion depth exceeded while calling a Python object
Exception in default exception handler
Traceback (most recent call last):
  File ".../python3.8/asyncio/base_events.py", line 1644, in call_exception_handler
    self.default_exception_handler(context)
  File ".../python3.8/asyncio/base_events.py", line 1615, in default_exception_handler
    value = repr(value)
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  File ".../python3.8/asyncio/base_tasks.py", line 21, in _task_repr_info
    info.insert(3, f'wait_for={task._fut_waiter!r}')
  [Previous line repeated 326 more times]
  File ".../python3.8/asyncio/base_tasks.py", line 9, in _task_repr_info
    info = base_futures._future_repr_info(task)
  File ".../python3.8/asyncio/base_futures.py", line 57, in _future_repr_info
    info.append(_format_callbacks(future._callbacks))
  File ".../python3.8/asyncio/base_futures.py", line 36, in _format_callbacks
    cb = '{}, {}'.format(format_cb(cb[0][0]), format_cb(cb[1][0]))
  File ".../python3.8/asyncio/base_futures.py", line 31, in format_cb
    return format_helpers._format_callback_source(callback, ())
  File ".../python3.8/asyncio/format_helpers.py", line 23, in _format_callback_source
    func_repr = _format_callback(func, args, None)
  File ".../python3.8/asyncio/format_helpers.py", line 56, in _format_callback
    func_repr += _format_args_and_kwargs(args, kwargs)
  File ".../python3.8/asyncio/format_helpers.py", line 41, in _format_args_and_kwargs
    return '({})'.format(', '.join(items))
RecursionError: maximum recursion depth exceeded while calling a Python object
```
msg385395 - (view) Author: Dima Tisnek (Dima.Tisnek) * Date: 2021-01-21 08:35
Py3.10: tested on v3.10.0a3:8bae2a958e and v3.10.0a4:445f7f54b1
History
Date User Action Args
2021-01-21 08:35:59Dima.Tisneksettitle: task.cancel unbound recursion -> task.cancel unbound recursion if task is deadlocked
2021-01-21 08:35:35Dima.Tisneksetmessages: + msg385395
versions: + Python 3.10
2020-05-19 01:09:07chris.jerdoneksetnosy: + chris.jerdonek
2019-06-24 11:36:30crusaderkysetnosy: + crusaderky
2019-03-28 02:52:54Dima.Tisnekcreate