This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author JohannesEbke
Recipients JohannesEbke, gvanrossum, vstinner, yselivanov
Date 2016-05-03.12:50:05
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1462279806.1.0.880381545595.issue26923@psf.upfronthosting.co.za>
In-reply-to
Content
In a very specific case, asyncio.gather causes a cancel() call on the Task waiting on the _GatheringFuture to return a false positive. An example program demonstrating this is attached.

The context: asyncio.gather creates a _GatheringFuture with a list of child Futures. Each child Future carries a done callback that updates the _GatheringFuture, and once the last child done callback is executed, the _GatheringFuture sets its result.

The specific situation: When the last child future changes state to done it schedules its done callbacks, but does not immediately execute them. If the Task waiting on the gather is then cancelled before the last child done callback has run, the cancel method in asyncio/tasks.py:578 determines that the _GatheringFuture inspects itself and sees that it is not done() yet, and proceeds to cancel all child futures - which has no effect, since all of them are already done(). It still returns True, so the Tasks thinks all is well, and proceeds with its execution.

The behaviour I would expect is that if cancel() is called on the _GatheringFuture, and all children return False on cancel(), then _GatheringFuture.cancel() should also return False, i.e.:

def cancel(self):
    if self.done():
        return False
    at_least_one_child_cancelled = False
    for child in self._children:
        if child.cancel():
            at_least_one_child_cancelled = True
    return at_least_one_child_cancelled

If I replace _GatheringFuture.cancel with the above variant, the bug disappears for me.

More context: We hit this bug sporadically in an integration test of aioredis, where some timings conspired to make it appear with a chance of about 1 in 10. The minimal example calls the cancellation in a done_callback, so that it always hits the window. This was not the way the bug was discovered.
History
Date User Action Args
2016-05-03 12:50:06JohannesEbkesetrecipients: + JohannesEbke, gvanrossum, vstinner, yselivanov
2016-05-03 12:50:06JohannesEbkesetmessageid: <1462279806.1.0.880381545595.issue26923@psf.upfronthosting.co.za>
2016-05-03 12:50:05JohannesEbkelinkissue26923 messages
2016-05-03 12:50:05JohannesEbkecreate