changeset: 101873:00a9de0f3fdc parent: 101871:d56b3e5ebfe2 parent: 101872:0bda9bc443ce user: Yury Selivanov date: Sat Jun 11 12:01:19 2016 -0400 files: Misc/NEWS description: Merge 3.5 (issue #22970) diff -r d56b3e5ebfe2 -r 00a9de0f3fdc Lib/asyncio/locks.py --- a/Lib/asyncio/locks.py Sat Jun 11 11:20:50 2016 -0400 +++ b/Lib/asyncio/locks.py Sat Jun 11 12:01:19 2016 -0400 @@ -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 -r d56b3e5ebfe2 -r 00a9de0f3fdc Lib/test/test_asyncio/test_locks.py --- a/Lib/test/test_asyncio/test_locks.py Sat Jun 11 11:20:50 2016 -0400 +++ b/Lib/test/test_asyncio/test_locks.py Sat Jun 11 12:01:19 2016 -0400 @@ -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(