New submission from David Coles:

If a task that is waiting on an asyncio.Condition is cancelled after 
notification but before having successfully reacquired the associated lock, the 
acquire() will be cancelled causing wait() to return without the lock held 
(violating wait()'s contract and leaving the program in an inconsistent state).

This can be reproduced in cases where there's some contention on the 
Condition's lock. For example:

    import asyncio

    loop = asyncio.get_event_loop()
    cond = asyncio.Condition()

    @asyncio.coroutine
    def cond_wait_timeout(condition, timeout):
      wait_task = asyncio.async(condition.wait())
      loop.call_later(timeout, wait_task.cancel)
      try:
          yield from wait_task
          return True
      except asyncio.CancelledError:
          print("Timeout (locked: {0})".format(condition.locked()))
          return False

    @asyncio.coroutine
    def waiter():
      yield from cond.acquire()
      try:
          print("Wait")
          if (yield from cond_wait_timeout(cond, 1)):
              # Cause some lock contention
              print("Do work")
              yield from asyncio.sleep(1)
      finally:
          cond.release()

    @asyncio.coroutine
    def notifier():
      # Yield to the waiters
      yield from asyncio.sleep(0.1)

      yield from cond.acquire()
      try:
          print("Notify")
          cond.notify_all()
      finally:
          cond.release()

    loop.run_until_complete(asyncio.wait([waiter(), waiter(), notifier()]))


The most straightforward fix appears to be just to have wait() retry to acquire 
the lock, effectively ignoring cancellation at this point (since the condition 
has already finished waiting and just trying to reacquire the lock before 
returning).

----------
components: asyncio
files: asyncio-fix-wait-cancellation-race.patch
keywords: patch
messages: 231912
nosy: dcoles, gvanrossum, haypo, yselivanov
priority: normal
severity: normal
status: open
title: Cancelling wait() after notification leaves Condition in an inconsistent 
state
type: behavior
versions: Python 3.4
Added file: 
http://bugs.python.org/file37330/asyncio-fix-wait-cancellation-race.patch

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue22970>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to