[New-bugs-announce] [issue22970] Cancelling wait() after notification leaves Condition in an inconsistent state

David Coles report at bugs.python.org
Mon Dec 1 04:29:42 CET 2014


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 <report at bugs.python.org>
<http://bugs.python.org/issue22970>
_______________________________________


More information about the New-bugs-announce mailing list