summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorBar Harel <bzvi7919@gmail.com>2018-02-02 23:15:31 (GMT)
committerYury Selivanov <yury@magic.io>2018-02-02 23:15:31 (GMT)
commit7e4cf8e95d2971ae0d5fb417152183070184293f (patch)
tree4d83f97a0695d0b33846e6e10394bb83337a88ce /Lib/test
parentfbf8e823c02ac1c93a48609cc74e439e19ccb426 (diff)
downloadcpython-7e4cf8e95d2971ae0d5fb417152183070184293f.zip
cpython-7e4cf8e95d2971ae0d5fb417152183070184293f.tar.gz
cpython-7e4cf8e95d2971ae0d5fb417152183070184293f.tar.bz2
[3.6] bpo-32734: Fix asyncio.Lock multiple acquire safety issue (GH-5466) (#5502)
(cherry picked from commit d41e9e0952393e64f2f9756d778553d704191086)
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 c85e8b1..835d09f 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -176,6 +176,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)