[Python-checkins] cpython (3.5): Issue #22970: asyncio: Fix inconsistency cancelling Condition.wait.

yury.selivanov python-checkins at python.org
Sat Jun 11 12:01:28 EDT 2016


https://hg.python.org/cpython/rev/0bda9bc443ce
changeset:   101872:0bda9bc443ce
branch:      3.5
parent:      101870:9512cfd53903
user:        Yury Selivanov <yury at magic.io>
date:        Sat Jun 11 12:00:07 2016 -0400
summary:
  Issue #22970: asyncio: Fix inconsistency cancelling Condition.wait.

Patch by David Coles.

files:
  Lib/asyncio/locks.py                |   8 ++++-
  Lib/test/test_asyncio/test_locks.py |  25 +++++++++++++++++
  Misc/NEWS                           |   3 ++
  3 files changed, 35 insertions(+), 1 deletions(-)


diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
--- a/Lib/asyncio/locks.py
+++ b/Lib/asyncio/locks.py
@@ -329,7 +329,13 @@
                 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
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -457,6 +457,31 @@
         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
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -524,6 +524,9 @@
   _conn_lost.
   Patch by Łukasz Langa.
 
+- Issue #22970: asyncio: Fix inconsistency cancelling Condition.wait.
+  Patch by David Coles.
+
 IDLE
 ----
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list