Skip to content

Commit 8e0b360

Browse files
gh-128002: use _PyObject_SetMaybeWeakref when creating tasks in asyncio (#128885)
1 parent fc6bc1e commit 8e0b360

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

Lib/test/test_asyncio/test_free_threading.py

+33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import threading
23
import unittest
34
from threading import Thread
45
from unittest import TestCase
@@ -58,6 +59,38 @@ def runner():
5859
with threading_helper.start_threads(threads):
5960
pass
6061

62+
def test_all_tasks_different_thread(self) -> None:
63+
loop = None
64+
started = threading.Event()
65+
66+
async def coro():
67+
await asyncio.sleep(0.01)
68+
69+
lock = threading.Lock()
70+
tasks = set()
71+
72+
async def main():
73+
nonlocal tasks, loop
74+
loop = asyncio.get_running_loop()
75+
started.set()
76+
for i in range(1000):
77+
with lock:
78+
asyncio.create_task(coro())
79+
tasks = self.all_tasks(loop)
80+
81+
runner = threading.Thread(target=lambda: asyncio.run(main()))
82+
83+
def check():
84+
started.wait()
85+
with lock:
86+
self.assertSetEqual(tasks & self.all_tasks(loop), tasks)
87+
88+
threads = [threading.Thread(target=check) for _ in range(10)]
89+
threads.append(runner)
90+
91+
with threading_helper.start_threads(threads):
92+
pass
93+
6194
def test_run_coroutine_threadsafe(self) -> None:
6295
results = []
6396

Modules/_asynciomodule.c

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "pycore_llist.h" // struct llist_node
1010
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
1111
#include "pycore_moduleobject.h" // _PyModule_GetState()
12+
#include "pycore_object.h" // _PyObject_SetMaybeWeakref
1213
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
1314
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
1415
#include "pycore_pystate.h" // _PyThreadState_GET()
@@ -2466,6 +2467,11 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
24662467
if (task_call_step_soon(state, self, NULL)) {
24672468
return -1;
24682469
}
2470+
#ifdef Py_GIL_DISABLED
2471+
// This is required so that _Py_TryIncref(self)
2472+
// works correctly in non-owning threads.
2473+
_PyObject_SetMaybeWeakref((PyObject *)self);
2474+
#endif
24692475
register_task(state, self);
24702476
return 0;
24712477
}

0 commit comments

Comments
 (0)