@@ -144,6 +144,100 @@ def foo():
144144 else :
145145 self .fail ("Main thread stack trace not found in result" )
146146
147+ @skip_if_not_supported
148+ @unittest .skipIf (
149+ sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
150+ "Test only runs on Linux with process_vm_readv support" ,
151+ )
152+ def test_async_remote_stack_trace_all_tasks (self ):
153+ port = find_unused_port ()
154+ script = textwrap .dedent (
155+ f"""\
156+ import asyncio
157+ import time
158+ import sys
159+ import socket
160+ # Connect to the test process
161+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
162+ sock.connect(('localhost', { port } ))
163+
164+ def c5():
165+ sock.sendall(b"ready"); time.sleep(10_000) # same line number
166+
167+ async def c4():
168+ await asyncio.sleep(0)
169+ c5()
170+
171+ async def c3():
172+ await c4()
173+
174+ async def c2():
175+ await c3()
176+
177+ async def c1(task):
178+ await task
179+
180+ async def main():
181+ async with asyncio.TaskGroup() as tg:
182+ task = tg.create_task(c2(), name="c2_root")
183+ tg.create_task(c1(task), name="sub_main_1")
184+ tg.create_task(c1(task), name="sub_main_2")
185+
186+ def new_eager_loop():
187+ loop = asyncio.new_event_loop()
188+ eager_task_factory = asyncio.create_eager_task_factory(
189+ asyncio.Task)
190+ loop.set_task_factory(eager_task_factory)
191+ return loop
192+
193+ asyncio.run(main(), loop_factory={{TASK_FACTORY}})
194+ """
195+ )
196+ stack_trace = None
197+ for task_factory_variant in "asyncio.new_event_loop" , "new_eager_loop" :
198+ with (
199+ self .subTest (task_factory_variant = task_factory_variant ),
200+ os_helper .temp_dir () as work_dir ,
201+ ):
202+ script_dir = os .path .join (work_dir , "script_pkg" )
203+ os .mkdir (script_dir )
204+ server_socket = socket .socket (
205+ socket .AF_INET , socket .SOCK_STREAM
206+ )
207+ server_socket .setsockopt (
208+ socket .SOL_SOCKET , socket .SO_REUSEADDR , 1
209+ )
210+ server_socket .bind (("localhost" , port ))
211+ server_socket .settimeout (SHORT_TIMEOUT )
212+ server_socket .listen (1 )
213+ script_name = _make_test_script (
214+ script_dir ,
215+ "script" ,
216+ script .format (TASK_FACTORY = task_factory_variant ),
217+ )
218+ client_socket = None
219+ try :
220+ p = subprocess .Popen ([sys .executable , script_name ])
221+ client_socket , _ = server_socket .accept ()
222+ server_socket .close ()
223+ response = client_socket .recv (1024 )
224+ self .assertEqual (response , b"ready" )
225+ stack_trace = get_all_awaited_by (p .pid )
226+ except PermissionError :
227+ self .skipTest (
228+ "Insufficient permissions to read the stack trace"
229+ )
230+ finally :
231+ if client_socket is not None :
232+ client_socket .close ()
233+ p .kill ()
234+ p .terminate ()
235+ p .wait (timeout = SHORT_TIMEOUT )
236+
237+ self .assertGreater (len (stack_trace ), 0 )
238+
239+
240+
147241 @skip_if_not_supported
148242 @unittest .skipIf (
149243 sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
0 commit comments