]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-128002: use `_PyObject_SetMaybeWeakref` when creating tasks in asyncio (#128885)
authorKumar Aditya <kumaraditya@python.org>
Fri, 24 Jan 2025 15:42:56 +0000 (21:12 +0530)
committerGitHub <noreply@github.com>
Fri, 24 Jan 2025 15:42:56 +0000 (21:12 +0530)
Lib/test/test_asyncio/test_free_threading.py
Modules/_asynciomodule.c

index 05106a2c2fe3f68af41433e790e03ddad54203d3..c91719cb577c2f00d0c77657585f943daa8adf81 100644 (file)
@@ -1,4 +1,5 @@
 import asyncio
+import threading
 import unittest
 from threading import Thread
 from unittest import TestCase
@@ -58,6 +59,38 @@ class TestFreeThreading:
         with threading_helper.start_threads(threads):
             pass
 
+    def test_all_tasks_different_thread(self) -> None:
+        loop = None
+        started = threading.Event()
+
+        async def coro():
+            await asyncio.sleep(0.01)
+
+        lock = threading.Lock()
+        tasks = set()
+
+        async def main():
+            nonlocal tasks, loop
+            loop = asyncio.get_running_loop()
+            started.set()
+            for i in range(1000):
+                with lock:
+                    asyncio.create_task(coro())
+                    tasks = self.all_tasks(loop)
+
+        runner = threading.Thread(target=lambda: asyncio.run(main()))
+
+        def check():
+            started.wait()
+            with lock:
+                self.assertSetEqual(tasks & self.all_tasks(loop), tasks)
+
+        threads = [threading.Thread(target=check) for _ in range(10)]
+        threads.append(runner)
+
+        with threading_helper.start_threads(threads):
+            pass
+
     def test_run_coroutine_threadsafe(self) -> None:
         results = []
 
index c821860d9e4f70d08a6678bc5c1df53372605053..d5d49658555f1ad514cf3ef59b5d97feeced9462 100644 (file)
@@ -9,6 +9,7 @@
 #include "pycore_llist.h"         // struct llist_node
 #include "pycore_modsupport.h"    // _PyArg_CheckPositional()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
+#include "pycore_object.h"        // _PyObject_SetMaybeWeakref
 #include "pycore_pyerrors.h"      // _PyErr_ClearExcState()
 #include "pycore_pylifecycle.h"   // _Py_IsInterpreterFinalizing()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
@@ -2466,6 +2467,11 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
     if (task_call_step_soon(state, self, NULL)) {
         return -1;
     }
+#ifdef Py_GIL_DISABLED
+    // This is required so that _Py_TryIncref(self)
+    // works correctly in non-owning threads.
+    _PyObject_SetMaybeWeakref((PyObject *)self);
+#endif
     register_task(state, self);
     return 0;
 }