Skip to content

Commit de92aab

Browse files
committed
Address review
1 parent 51fa194 commit de92aab

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

Lib/test/test_external_inspection.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,11 @@ async def main():
434434
# no synchronization. That occasionally leads to invalid
435435
# reads. Here we avoid making the test flaky.
436436
msg = str(re)
437-
if msg.startswith("Unknown error reading memory"):
437+
if msg.startswith("Task list appears corrupted"):
438+
continue
439+
elif msg.startswith("Invalid linked list structure reading remote memory"):
440+
continue
441+
elif msg.startswith("Unknown error reading memory"):
438442
continue
439443
elif msg.startswith("Unhandled frame owner"):
440444
continue
@@ -445,6 +449,8 @@ async def main():
445449
self.assertEqual(len(all_awaited_by), 2)
446450
# expected: a tuple with the thread ID and the awaited_by list
447451
self.assertEqual(len(all_awaited_by[0]), 2)
452+
# expected: no tasks in the fallback per-interp task list
453+
self.assertEqual(all_awaited_by[1], (0, []))
448454
entries = all_awaited_by[0][1]
449455
# expected: at least 1000 pending tasks
450456
self.assertGreaterEqual(len(entries), 1000)

Modules/_testexternalinspection.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,13 +1490,21 @@ append_awaited_by_for_thread(
14901490
return -1;
14911491
}
14921492

1493-
size_t iteration_count = 0;
1494-
const size_t MAX_ITERATIONS = 100000; // Reasonable upper bound
1495-
while ((uintptr_t)task_node.next != head_addr) {
1496-
if (++iteration_count > MAX_ITERATIONS) {
1497-
PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted");
1498-
return -1;
1499-
}
1493+
size_t iteration_count = 0;
1494+
const size_t MAX_ITERATIONS = 2 << 15; // A reasonable upper bound
1495+
while ((uintptr_t)task_node.next != head_addr) {
1496+
if (++iteration_count > MAX_ITERATIONS) {
1497+
PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted");
1498+
return -1;
1499+
}
1500+
1501+
if (task_node.next == NULL) {
1502+
PyErr_SetString(
1503+
PyExc_RuntimeError,
1504+
"Invalid linked list structure reading remote memory");
1505+
return -1;
1506+
}
1507+
15001508
uintptr_t task_addr = (uintptr_t)task_node.next
15011509
- async_offsets->asyncio_task_object.task_node;
15021510

@@ -1698,6 +1706,11 @@ get_all_awaited_by(PyObject* self, PyObject* args)
16981706
head_addr = interpreter_state_addr
16991707
+ local_async_debug.asyncio_interpreter_state.asyncio_tasks_head;
17001708

1709+
// On top of a per-thread task lists used by default by asyncio to avoid
1710+
// contention, there is also a fallback per-interpreter list of tasks;
1711+
// any tasks still pending when a thread is destroyed will be moved to the
1712+
// per-interpreter task list. It's unlikely we'll find anything here, but
1713+
// interesting for debugging.
17011714
if (append_awaited_by(pid, 0, head_addr, &local_debug_offsets,
17021715
&local_async_debug, result))
17031716
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy