classification
Title: asyncio: wrap_future() doesn't handle cancellation correctly
Type: Stage: resolved
Components: asyncio Versions: Python 3.7, Python 3.6, Python 3.5
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: gvanrossum, vstinner, yselivanov
Priority: normal Keywords:

Created on 2016-09-21 07:50 by vstinner, last changed 2017-06-28 01:54 by vstinner. This issue is now closed.

Messages (2)
msg277107 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2016-09-21 07:50
I noticed the following warning in test_asyncio (see above). It understand that when the asyncio Future ("destination" in _chain_future) is cancelled, _call_check_cancel() calls source_loop.call_soon_threadsafe(source.cancel) where source is a concurrent.futures.Future object.

Then futures.Future.cancel() calls self._invoke_callbacks() which calls _call_set_state() of _chain_future(). _call_set_state() calls dest_loop.call_soon_threadsafe(_set_state, destination, source) but at this point, the event loop is closed. Morever, destination (the asyncio future) is already cancelled, but it doesn't make sense to try to copy the state: source and destination are already cancelled.

I suggest to modify _call_set_state() to do nothing if destination is already cancelled:

    def _call_set_state(source):
        if destination.cancelled():
            return
        (...)

*But* I see that futures.Future has a set_running_or_notify_cancel() method which seems to be important to call. Maybe we should call it in this case?

    def _call_set_state(source):
        if destination.cancelled():
            source.set_running_or_notify_cancel()
            return
        (...)

--

The warning:


http://buildbot.python.org/all/builders/AMD64%20Windows8%203.6/builds/43/steps/test/logs/stdio

test_sock_sendall (test.test_asyncio.test_selector_events.BaseSelectorEventLoopTests) ... exception calling callback for <Future at 0xec840d1e28 state=finished returned NoneType>
Traceback (most recent call last):
  File "D:\buildarea\3.6.bolen-windows8\build\lib\concurrent\futures\_base.py", line 297, in _invoke_callbacks
    callback(self)
  File "D:\buildarea\3.6.bolen-windows8\build\lib\asyncio\futures.py", line 462, in _call_set_state
    dest_loop.call_soon_threadsafe(_set_state, destination, source)
  File "D:\buildarea\3.6.bolen-windows8\build\lib\asyncio\base_events.py", line 603, in call_soon_threadsafe
    handle = self._call_soon(callback, args)
  File "D:\buildarea\3.6.bolen-windows8\build\lib\asyncio\base_events.py", line 577, in _call_soon
    self._check_closed()
  File "D:\buildarea\3.6.bolen-windows8\build\lib\asyncio\base_events.py", line 356, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
ok
msg297137 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2017-06-28 01:54
I'm sorry, but I'm not interested anymore to work on asyncio, and I'm unable to say if the bug was fixed since I reported it or not :-/ But I saw work on cancellation. So maybe it was already fixed. I now just close the issue.
History
Date User Action Args
2017-06-28 01:54:42vstinnersetstatus: open -> closed
resolution: out of date
messages: + msg297137

stage: resolved
2016-09-21 07:50:41vstinnercreate