summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorBar Harel <bzvi7919@gmail.com>2018-02-02 22:04:00 (GMT)
committerYury Selivanov <yury@magic.io>2018-02-02 22:04:00 (GMT)
commit2f79c014931cbb23b08a7d16c534a3cc9607ae14 (patch)
tree84bb7aa654ee9a7ee792ec897726da45da8ce276 /Lib/test
parent66771422d0541289d0b1287bc3c28e8b5609f6b4 (diff)
downloadcpython-2f79c014931cbb23b08a7d16c534a3cc9607ae14.zip
cpython-2f79c014931cbb23b08a7d16c534a3cc9607ae14.tar.gz
cpython-2f79c014931cbb23b08a7d16c534a3cc9607ae14.tar.bz2
bpo-32734: Fix asyncio.Lock multiple acquire safety issue (GH-5466)
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_asyncio/test_locks.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py
index 3c50697..3e3dd79 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -200,6 +200,56 @@ class LockTests(test_utils.TestCase):
self.assertTrue(tb.cancelled())
self.assertTrue(tc.done())
+ def test_cancel_release_race(self):
+ # Issue 32734
+ # Acquire 4 locks, cancel second, release first
+ # and 2 locks are taken at once.
+ lock = asyncio.Lock(loop=self.loop)
+ lock_count = 0
+ call_count = 0
+
+ async def lockit():
+ nonlocal lock_count
+ nonlocal call_count
+ 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()
+
+ t0 = self.loop.create_task(lockandtrigger())
+ t1 = self.loop.create_task(lockit())
+ t2 = self.loop.create_task(lockit())
+ t3 = self.loop.create_task(lockit())
+
+ # First loop acquires all
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(t0.done())
+
+ # Second loop calls trigger
+ test_utils.run_briefly(self.loop)
+ # Third loop calls cancellation
+ test_utils.run_briefly(self.loop)
+
+ # Make sure only one lock was taken
+ self.assertEqual(lock_count, 1)
+ # While 3 calls were made to lockit()
+ self.assertEqual(call_count, 3)
+ self.assertTrue(t1.cancelled() and t2.done())
+
+ # Cleanup the task that is stuck on acquire.
+ t3.cancel()
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(t3.cancelled())
+
+
+
def test_finished_waiter_cancelled(self):
lock = asyncio.Lock(loop=self.loop)