[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