Skip to content

Commit b0057b8

Browse files
authored
[3.14] gh-157058: Fix missing awaited-by edge in wait_for(fut, 0) (GH-157059) (#157323)
gh-157058: Fix missing awaited-by edge in wait_for(fut, 0)
1 parent 8129912 commit b0057b8

3 files changed

Lines changed: 34 additions & 0 deletions

File tree

Lib/asyncio/tasks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,18 @@ async def _cancel_and_wait(fut):
541541
cb = functools.partial(_release_waiter, waiter)
542542
fut.add_done_callback(cb)
543543

544+
# gh-157058: awaiting the waiter leaves no edge on fut, add it here
545+
cur_task = current_task()
546+
futures.future_add_to_awaited_by(fut, cur_task)
547+
544548
try:
545549
fut.cancel()
546550
# We cannot wait on *fut* directly to make
547551
# sure _cancel_and_wait itself is reliably cancellable.
548552
await waiter
549553
finally:
550554
fut.remove_done_callback(cb)
555+
futures.future_discard_from_awaited_by(fut, cur_task)
551556

552557

553558
class _AsCompletedIterator:

Lib/test/test_asyncio/test_graph.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,33 @@ async def main():
146146
'async generator CallStackTestBase.test_stack_async_gen.<locals>.gen()',
147147
stack_for_gen_nested_call[1])
148148

149+
async def test_stack_wait_for_non_positive_timeout(self):
150+
# gh-157058: wait_for(fut, 0) must still record the waiter
151+
cleanup = asyncio.Future()
152+
153+
async def worker():
154+
try:
155+
await asyncio.Future()
156+
finally:
157+
await cleanup
158+
159+
async def probe(t):
160+
await asyncio.wait_for(t, 0)
161+
162+
t = asyncio.ensure_future(worker())
163+
p = asyncio.create_task(probe(t), name='probe')
164+
for _ in range(5):
165+
await asyncio.sleep(0)
166+
167+
stack = capture_test_stack(fut=t)
168+
169+
cleanup.set_result(None)
170+
await asyncio.gather(p, t, return_exceptions=True)
171+
172+
self.assertEqual(stack[0][2], [
173+
['T<probe>', ['a _cancel_and_wait', 'a wait_for', 'a probe'], []],
174+
])
175+
149176
async def test_stack_gather(self):
150177

151178
stack_for_deep = None
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`asyncio.wait_for` with a non-positive timeout now records the waiter
2+
in the call graph.

0 commit comments

Comments
 (0)