Skip to content

Commit 14715e3

Browse files
gh-105836: Fix asyncio.run_coroutine_threadsafe leaving underlying cancelled asyncio task running (#141696)
Co-authored-by: Kumar Aditya <[email protected]>
1 parent 56a442d commit 14715e3

File tree

4 files changed

+29
-2
lines changed

4 files changed

+29
-2
lines changed

Lib/asyncio/futures.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def _set_state(future, other):
389389

390390
def _call_check_cancel(destination):
391391
if destination.cancelled():
392-
if source_loop is None or source_loop is dest_loop:
392+
if source_loop is None or source_loop is events._get_running_loop():
393393
source.cancel()
394394
else:
395395
source_loop.call_soon_threadsafe(source.cancel)
@@ -398,7 +398,7 @@ def _call_set_state(source):
398398
if (destination.cancelled() and
399399
dest_loop is not None and dest_loop.is_closed()):
400400
return
401-
if dest_loop is None or dest_loop is source_loop:
401+
if dest_loop is None or dest_loop is events._get_running_loop():
402402
_set_state(destination, source)
403403
else:
404404
if dest_loop.is_closed():

Lib/test/test_asyncio/test_tasks.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3680,6 +3680,30 @@ def task_factory(loop, coro):
36803680
(loop, context), kwargs = callback.call_args
36813681
self.assertEqual(context['exception'], exc_context.exception)
36823682

3683+
def test_run_coroutine_threadsafe_and_cancel(self):
3684+
task = None
3685+
thread_future = None
3686+
# Use a custom task factory to capture the created Task
3687+
def task_factory(loop, coro):
3688+
nonlocal task
3689+
task = asyncio.Task(coro, loop=loop)
3690+
return task
3691+
3692+
self.addCleanup(self.loop.set_task_factory,
3693+
self.loop.get_task_factory())
3694+
3695+
async def target():
3696+
nonlocal thread_future
3697+
self.loop.set_task_factory(task_factory)
3698+
thread_future = asyncio.run_coroutine_threadsafe(asyncio.sleep(10), self.loop)
3699+
await asyncio.sleep(0)
3700+
3701+
thread_future.cancel()
3702+
3703+
self.loop.run_until_complete(target())
3704+
self.assertTrue(task.cancelled())
3705+
self.assertTrue(thread_future.cancelled())
3706+
36833707

36843708
class SleepTests(test_utils.TestCase):
36853709
def setUp(self):

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,6 +2119,7 @@ Xiang Zhang
21192119
Robert Xiao
21202120
Florent Xicluna
21212121
Yanbo, Xie
2122+
Kaisheng Xu
21222123
Xinhang Xu
21232124
Arnon Yaari
21242125
Alakshendra Yadav
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :meth:`asyncio.run_coroutine_threadsafe` leaving underlying cancelled
2+
asyncio task running.

0 commit comments

Comments
 (0)