mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
bpo-32841: Fix cancellation in awaiting asyncio.Condition (GH-5665) (GH-5683)
(cherry picked from commit 5746510b7a
)
Co-authored-by: Bar Harel <bzvi7919@gmail.com>
This commit is contained in:
parent
2be5435203
commit
a23eecab9a
3 changed files with 34 additions and 5 deletions
|
@ -349,12 +349,16 @@ class Condition(_ContextManagerMixin):
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# Must reacquire lock even if wait is cancelled
|
# Must reacquire lock even if wait is cancelled
|
||||||
|
cancelled = False
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
yield from self.acquire()
|
yield from self.acquire()
|
||||||
break
|
break
|
||||||
except futures.CancelledError:
|
except futures.CancelledError:
|
||||||
pass
|
cancelled = True
|
||||||
|
|
||||||
|
if cancelled:
|
||||||
|
raise futures.CancelledError
|
||||||
|
|
||||||
@coroutine
|
@coroutine
|
||||||
def wait_for(self, predicate):
|
def wait_for(self, predicate):
|
||||||
|
|
|
@ -190,11 +190,11 @@ class LockTests(test_utils.TestCase):
|
||||||
call_count += 1
|
call_count += 1
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
lock_count += 1
|
lock_count += 1
|
||||||
|
|
||||||
async def lockandtrigger():
|
async def lockandtrigger():
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
self.loop.call_soon(trigger)
|
self.loop.call_soon(trigger)
|
||||||
|
|
||||||
def trigger():
|
def trigger():
|
||||||
t1.cancel()
|
t1.cancel()
|
||||||
lock.release()
|
lock.release()
|
||||||
|
@ -224,8 +224,6 @@ class LockTests(test_utils.TestCase):
|
||||||
test_utils.run_briefly(self.loop)
|
test_utils.run_briefly(self.loop)
|
||||||
self.assertTrue(t3.cancelled())
|
self.assertTrue(t3.cancelled())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_finished_waiter_cancelled(self):
|
def test_finished_waiter_cancelled(self):
|
||||||
lock = asyncio.Lock(loop=self.loop)
|
lock = asyncio.Lock(loop=self.loop)
|
||||||
|
|
||||||
|
@ -557,6 +555,31 @@ class ConditionTests(test_utils.TestCase):
|
||||||
|
|
||||||
self.assertTrue(cond.locked())
|
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):
|
def test_wait_unacquired(self):
|
||||||
cond = asyncio.Condition(loop=self.loop)
|
cond = asyncio.Condition(loop=self.loop)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed `asyncio.Condition` issue which silently ignored cancellation after
|
||||||
|
notifying and cancelling a conditional lock. Patch by Bar Harel.
|
Loading…
Add table
Add a link
Reference in a new issue