[Python-checkins] bpo-32841: Fix cancellation in awaiting asyncio.Condition (GH-5665) (GH-5683)

Andrew Svetlov webhook-mailer at python.org
Wed Feb 14 05:10:25 EST 2018


https://github.com/python/cpython/commit/a23eecab9a0b724bdfde83d159ac2415927f042a
commit: a23eecab9a0b724bdfde83d159ac2415927f042a
branch: 3.6
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: Andrew Svetlov <andrew.svetlov at gmail.com>
date: 2018-02-14T12:10:18+02:00
summary:

bpo-32841: Fix cancellation in awaiting asyncio.Condition (GH-5665) (GH-5683)

(cherry picked from commit 5746510b7aef423fa4afc92b2abb919307b1dbb9)

Co-authored-by: Bar Harel <bzvi7919 at gmail.com>

files:
A Misc/NEWS.d/next/Library/2018-02-14-00-21-24.bpo-32841.bvHDOc.rst
M Lib/asyncio/locks.py
M Lib/test/test_asyncio/test_locks.py

diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
index 14d21ff4e6f7..8ee7e2ea045f 100644
--- a/Lib/asyncio/locks.py
+++ b/Lib/asyncio/locks.py
@@ -349,12 +349,16 @@ def wait(self):
 
         finally:
             # Must reacquire lock even if wait is cancelled
+            cancelled = False
             while True:
                 try:
                     yield from self.acquire()
                     break
                 except futures.CancelledError:
-                    pass
+                    cancelled = True
+
+            if cancelled:
+                raise futures.CancelledError
 
     @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 835d09ffc5d2..8686395da16f 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -190,11 +190,11 @@ def test_cancel_release_race(self):
             call_count += 1
             await lock.acquire()
             lock_count += 1
-  
+
         async def lockandtrigger():
             await lock.acquire()
             self.loop.call_soon(trigger)
-          
+
         def trigger():
             t1.cancel()
             lock.release()
@@ -224,8 +224,6 @@ def trigger():
         test_utils.run_briefly(self.loop)
         self.assertTrue(t3.cancelled())
 
-
-
     def test_finished_waiter_cancelled(self):
         lock = asyncio.Lock(loop=self.loop)
 
@@ -557,6 +555,31 @@ def test_wait_cancel_contested(self):
 
         self.assertTrue(cond.locked())
 
+    def test_wait_cancel_after_notify(self):
+        # See bpo-32841
+        cond = asyncio.Condition(loop=self.loop)
+        waited = False
+
+        async def wait_on_cond():
+            nonlocal waited
+            async with cond:
+                waited = True  # Make sure this area was reached
+                await cond.wait()
+
+        waiter = asyncio.ensure_future(wait_on_cond(), loop=self.loop)
+        test_utils.run_briefly(self.loop)  # Start waiting
+
+        self.loop.run_until_complete(cond.acquire())
+        cond.notify()
+        test_utils.run_briefly(self.loop)  # Get to acquire()
+        waiter.cancel()
+        test_utils.run_briefly(self.loop)  # Activate cancellation
+        cond.release()
+        test_utils.run_briefly(self.loop)  # Cancellation should occur
+
+        self.assertTrue(waiter.cancelled())
+        self.assertTrue(waited)
+
     def test_wait_unacquired(self):
         cond = asyncio.Condition(loop=self.loop)
         self.assertRaises(
diff --git a/Misc/NEWS.d/next/Library/2018-02-14-00-21-24.bpo-32841.bvHDOc.rst b/Misc/NEWS.d/next/Library/2018-02-14-00-21-24.bpo-32841.bvHDOc.rst
new file mode 100644
index 000000000000..a6d45669d027
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-02-14-00-21-24.bpo-32841.bvHDOc.rst
@@ -0,0 +1,2 @@
+Fixed `asyncio.Condition` issue which silently ignored cancellation after
+notifying and cancelling a conditional lock. Patch by Bar Harel.



More information about the Python-checkins mailing list