(self)
| 145 | self.assertFalse(lock._waiters) |
| 146 | |
| 147 | async def test_cancel_race(self): |
| 148 | # Several tasks: |
| 149 | # - A acquires the lock |
| 150 | # - B is blocked in acquire() |
| 151 | # - C is blocked in acquire() |
| 152 | # |
| 153 | # Now, concurrently: |
| 154 | # - B is cancelled |
| 155 | # - A releases the lock |
| 156 | # |
| 157 | # If B's waiter is marked cancelled but not yet removed from |
| 158 | # _waiters, A's release() call will crash when trying to set |
| 159 | # B's waiter; instead, it should move on to C's waiter. |
| 160 | |
| 161 | # Setup: A has the lock, b and c are waiting. |
| 162 | lock = asyncio.Lock() |
| 163 | |
| 164 | async def lockit(name, blocker): |
| 165 | await lock.acquire() |
| 166 | try: |
| 167 | if blocker is not None: |
| 168 | await blocker |
| 169 | finally: |
| 170 | lock.release() |
| 171 | |
| 172 | fa = asyncio.get_running_loop().create_future() |
| 173 | ta = asyncio.create_task(lockit('A', fa)) |
| 174 | await asyncio.sleep(0) |
| 175 | self.assertTrue(lock.locked()) |
| 176 | tb = asyncio.create_task(lockit('B', None)) |
| 177 | await asyncio.sleep(0) |
| 178 | self.assertEqual(len(lock._waiters), 1) |
| 179 | tc = asyncio.create_task(lockit('C', None)) |
| 180 | await asyncio.sleep(0) |
| 181 | self.assertEqual(len(lock._waiters), 2) |
| 182 | |
| 183 | # Create the race and check. |
| 184 | # Without the fix this failed at the last assert. |
| 185 | fa.set_result(None) |
| 186 | tb.cancel() |
| 187 | self.assertTrue(lock._waiters[0].cancelled()) |
| 188 | await asyncio.sleep(0) |
| 189 | self.assertFalse(lock.locked()) |
| 190 | self.assertTrue(ta.done()) |
| 191 | self.assertTrue(tb.cancelled()) |
| 192 | await tc |
| 193 | |
| 194 | async def test_cancel_release_race(self): |
| 195 | # Issue 32734 |
nothing calls this directly
no test coverage detected