summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYury Selivanov <yury@magic.io>2016-06-11 12:00:07 -0400
committerYury Selivanov <yury@magic.io>2016-06-11 12:00:07 -0400
commit76e3aa4006a7fe203b5e8c52009a14db054f5d81 (patch)
treed49a9cd6f90ae7873d72b27a23d86993bb4f9c97
parentbed123f2dca32db59eb448c453c4c002f1cce77b (diff)
downloadcpython-76e3aa4006a7fe203b5e8c52009a14db054f5d81.tar.gz
Issue #22970: asyncio: Fix inconsistency cancelling Condition.wait.
Patch by David Coles.
-rw-r--r--Lib/asyncio/locks.py8
-rw-r--r--Lib/test/test_asyncio/test_locks.py25
-rw-r--r--Misc/NEWS3
3 files changed, 35 insertions, 1 deletions
diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
index 842d6210d5..741aaf27c5 100644
--- a/Lib/asyncio/locks.py
+++ b/Lib/asyncio/locks.py
@@ -329,7 +329,13 @@ class Condition(_ContextManagerMixin):
self._waiters.remove(fut)
finally:
- yield from self.acquire()
+ # Must reacquire lock even if wait is cancelled
+ while True:
+ try:
+ yield from self.acquire()
+ break
+ except futures.CancelledError:
+ pass
@coroutine
def wait_for(self, predicate):
diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py
index cdf5d9d3b6..d3bdc51385 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -457,6 +457,31 @@ class ConditionTests(test_utils.TestCase):
self.assertFalse(cond._waiters)
self.assertTrue(cond.locked())
+ def test_wait_cancel_contested(self):
+ cond = asyncio.Condition(loop=self.loop)
+
+ self.loop.run_until_complete(cond.acquire())
+ self.assertTrue(cond.locked())
+
+ wait_task = asyncio.Task(cond.wait(), loop=self.loop)
+ test_utils.run_briefly(self.loop)
+ self.assertFalse(cond.locked())
+
+ # Notify, but contest the lock before cancelling
+ self.loop.run_until_complete(cond.acquire())
+ self.assertTrue(cond.locked())
+ cond.notify()
+ self.loop.call_soon(wait_task.cancel)
+ self.loop.call_soon(cond.release)
+
+ try:
+ self.loop.run_until_complete(wait_task)
+ except asyncio.CancelledError:
+ # Should not happen, since no cancellation points
+ pass
+
+ self.assertTrue(cond.locked())
+
def test_wait_unacquired(self):
cond = asyncio.Condition(loop=self.loop)
self.assertRaises(
diff --git a/Misc/NEWS b/Misc/NEWS
index c40fc4b25c..1ed87ac6b8 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -524,6 +524,9 @@ Library
_conn_lost.
Patch by Ɓukasz Langa.
+- Issue #22970: asyncio: Fix inconsistency cancelling Condition.wait.
+ Patch by David Coles.
+
IDLE
----