Skip to content

Commit a23eeca

Browse files
miss-islingtonbharel
authored andcommitted
bpo-32841: Fix cancellation in awaiting asyncio.Condition (GH-5665) (GH-5683)
(cherry picked from commit 5746510) Co-authored-by: Bar Harel <[email protected]>
1 parent 2be5435 commit a23eeca

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

Lib/asyncio/locks.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,16 @@ def wait(self):
349349

350350
finally:
351351
# Must reacquire lock even if wait is cancelled
352+
cancelled = False
352353
while True:
353354
try:
354355
yield from self.acquire()
355356
break
356357
except futures.CancelledError:
357-
pass
358+
cancelled = True
359+
360+
if cancelled:
361+
raise futures.CancelledError
358362

359363
@coroutine
360364
def wait_for(self, predicate):

Lib/test/test_asyncio/test_locks.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ async def lockit():
190190
call_count += 1
191191
await lock.acquire()
192192
lock_count += 1
193-
193+
194194
async def lockandtrigger():
195195
await lock.acquire()
196196
self.loop.call_soon(trigger)
197-
197+
198198
def trigger():
199199
t1.cancel()
200200
lock.release()
@@ -224,8 +224,6 @@ def trigger():
224224
test_utils.run_briefly(self.loop)
225225
self.assertTrue(t3.cancelled())
226226

227-
228-
229227
def test_finished_waiter_cancelled(self):
230228
lock = asyncio.Lock(loop=self.loop)
231229

@@ -557,6 +555,31 @@ def test_wait_cancel_contested(self):
557555

558556
self.assertTrue(cond.locked())
559557

558+
def test_wait_cancel_after_notify(self):
559+
# See bpo-32841
560+
cond = asyncio.Condition(loop=self.loop)
561+
waited = False
562+
563+
async def wait_on_cond():
564+
nonlocal waited
565+
async with cond:
566+
waited = True # Make sure this area was reached
567+
await cond.wait()
568+
569+
waiter = asyncio.ensure_future(wait_on_cond(), loop=self.loop)
570+
test_utils.run_briefly(self.loop) # Start waiting
571+
572+
self.loop.run_until_complete(cond.acquire())
573+
cond.notify()
574+
test_utils.run_briefly(self.loop) # Get to acquire()
575+
waiter.cancel()
576+
test_utils.run_briefly(self.loop) # Activate cancellation
577+
cond.release()
578+
test_utils.run_briefly(self.loop) # Cancellation should occur
579+
580+
self.assertTrue(waiter.cancelled())
581+
self.assertTrue(waited)
582+
560583
def test_wait_unacquired(self):
561584
cond = asyncio.Condition(loop=self.loop)
562585
self.assertRaises(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed `asyncio.Condition` issue which silently ignored cancellation after
2+
notifying and cancelling a conditional lock. Patch by Bar Harel.

0 commit comments

Comments
 (0)