diff options
author | Yury Selivanov <yury@magic.io> | 2017-06-09 21:08:23 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-09 21:08:23 (GMT) |
commit | d913d1c31733eff5969835e46ae13e2d156dbb1c (patch) | |
tree | 946c31193becaf4f136a9e8cb0c3e74e862388c2 /Lib/asyncio/locks.py | |
parent | 3fc2fa8cb909cb58325f56deb5cd500d278e4102 (diff) | |
download | cpython-d913d1c31733eff5969835e46ae13e2d156dbb1c.zip cpython-d913d1c31733eff5969835e46ae13e2d156dbb1c.tar.gz cpython-d913d1c31733eff5969835e46ae13e2d156dbb1c.tar.bz2 |
Fix waiter cancellation in asyncio.Lock (#1031) (#2038)
Avoid a deadlock when the waiter who is about to take the lock is
cancelled
Issue #27585
Diffstat (limited to 'Lib/asyncio/locks.py')
-rw-r--r-- | Lib/asyncio/locks.py | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py index deefc93..9266183 100644 --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -176,6 +176,10 @@ class Lock(_ContextManagerMixin): yield from fut self._locked = True return True + except futures.CancelledError: + if not self._locked: + self._wake_up_first() + raise finally: self._waiters.remove(fut) @@ -192,14 +196,17 @@ class Lock(_ContextManagerMixin): """ if self._locked: self._locked = False - # Wake up the first waiter who isn't cancelled. - for fut in self._waiters: - if not fut.done(): - fut.set_result(True) - break + self._wake_up_first() else: raise RuntimeError('Lock is not acquired.') + def _wake_up_first(self): + """Wake up the first waiter who isn't cancelled.""" + for fut in self._waiters: + if not fut.done(): + fut.set_result(True) + break + class Event: """Asynchronous equivalent to threading.Event. |