@@ -144,6 +144,100 @@ def foo():
144
144
else :
145
145
self .fail ("Main thread stack trace not found in result" )
146
146
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
+
147
241
@skip_if_not_supported
148
242
@unittest .skipIf (
149
243
sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
0 commit comments