Skip to content

Commit b2fff0e

Browse files
miss-islingtoniaalmkumaraditya303
authored
[3.13] gh-105836: Fix asyncio.run_coroutine_threadsafe leaving underlying cancelled asyncio task running (GH-141696) (#142359)
gh-105836: Fix `asyncio.run_coroutine_threadsafe` leaving underlying cancelled asyncio task running (GH-141696) (cherry picked from commit 14715e3) Co-authored-by: Kaisheng Xu <[email protected]> Co-authored-by: Kumar Aditya <[email protected]>
1 parent 85f4803 commit b2fff0e

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
@@ -383,7 +383,7 @@ def _set_state(future, other):
383383

384384
def _call_check_cancel(destination):
385385
if destination.cancelled():
386-
if source_loop is None or source_loop is dest_loop:
386+
if source_loop is None or source_loop is events._get_running_loop():
387387
source.cancel()
388388
else:
389389
source_loop.call_soon_threadsafe(source.cancel)
@@ -392,7 +392,7 @@ def _call_set_state(source):
392392
if (destination.cancelled() and
393393
dest_loop is not None and dest_loop.is_closed()):
394394
return
395-
if dest_loop is None or dest_loop is source_loop:
395+
if dest_loop is None or dest_loop is events._get_running_loop():
396396
_set_state(destination, source)
397397
else:
398398
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
@@ -3552,6 +3552,30 @@ def task_factory(loop, coro):
35523552
(loop, context), kwargs = callback.call_args
35533553
self.assertEqual(context['exception'], exc_context.exception)
35543554

3555+
def test_run_coroutine_threadsafe_and_cancel(self):
3556+
task = None
3557+
thread_future = None
3558+
# Use a custom task factory to capture the created Task
3559+
def task_factory(loop, coro):
3560+
nonlocal task
3561+
task = asyncio.Task(coro, loop=loop)
3562+
return task
3563+
3564+
self.addCleanup(self.loop.set_task_factory,
3565+
self.loop.get_task_factory())
3566+
3567+
async def target():
3568+
nonlocal thread_future
3569+
self.loop.set_task_factory(task_factory)
3570+
thread_future = asyncio.run_coroutine_threadsafe(asyncio.sleep(10), self.loop)
3571+
await asyncio.sleep(0)
3572+
3573+
thread_future.cancel()
3574+
3575+
self.loop.run_until_complete(target())
3576+
self.assertTrue(task.cancelled())
3577+
self.assertTrue(thread_future.cancelled())
3578+
35553579

35563580
class SleepTests(test_utils.TestCase):
35573581
def setUp(self):

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,7 @@ Xiang Zhang
20742074
Robert Xiao
20752075
Florent Xicluna
20762076
Yanbo, Xie
2077+
Kaisheng Xu
20772078
Xinhang Xu
20782079
Arnon Yaari
20792080
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)