54
54
#include <internal/pycore_debug_offsets.h> // _Py_DebugOffsets
55
55
#include <internal/pycore_frame.h> // FRAME_SUSPENDED_YIELD_FROM
56
56
#include <internal/pycore_interpframe.h> // FRAME_OWNED_BY_CSTACK
57
+ #include <internal/pycore_llist.h> // struct llist_node
57
58
#include <internal/pycore_stackref.h> // Py_TAG_BITS
58
59
59
60
#ifndef HAVE_PROCESS_VM_READV
@@ -68,11 +69,17 @@ struct _Py_AsyncioModuleDebugOffsets {
68
69
uint64_t task_is_task ;
69
70
uint64_t task_awaited_by_is_set ;
70
71
uint64_t task_coro ;
72
+ uint64_t task_node ;
71
73
} asyncio_task_object ;
74
+ struct _asyncio_interpreter_state {
75
+ uint64_t size ;
76
+ uint64_t asyncio_tasks_head ;
77
+ } asyncio_interpreter_state ;
72
78
struct _asyncio_thread_state {
73
79
uint64_t size ;
74
80
uint64_t asyncio_running_loop ;
75
81
uint64_t asyncio_running_task ;
82
+ uint64_t asyncio_tasks_head ;
76
83
} asyncio_thread_state ;
77
84
};
78
85
@@ -1464,6 +1471,240 @@ find_running_task(
1464
1471
return 0 ;
1465
1472
}
1466
1473
1474
+ static int
1475
+ append_awaited_by_for_thread (
1476
+ int pid ,
1477
+ uintptr_t head_addr ,
1478
+ struct _Py_DebugOffsets * debug_offsets ,
1479
+ struct _Py_AsyncioModuleDebugOffsets * async_offsets ,
1480
+ PyObject * result
1481
+ ) {
1482
+ struct llist_node task_node ;
1483
+
1484
+ if (0 > read_memory (
1485
+ pid ,
1486
+ head_addr ,
1487
+ sizeof (task_node ),
1488
+ & task_node ))
1489
+ {
1490
+ return -1 ;
1491
+ }
1492
+
1493
+ while ((uintptr_t )task_node .next != head_addr ) {
1494
+ uintptr_t task_addr = (uintptr_t )task_node .next
1495
+ - async_offsets -> asyncio_task_object .task_node ;
1496
+
1497
+ PyObject * tn = parse_task_name (
1498
+ pid ,
1499
+ debug_offsets ,
1500
+ async_offsets ,
1501
+ task_addr );
1502
+ if (tn == NULL ) {
1503
+ return -1 ;
1504
+ }
1505
+
1506
+ PyObject * current_awaited_by = PyList_New (0 );
1507
+ if (current_awaited_by == NULL ) {
1508
+ Py_DECREF (tn );
1509
+ return -1 ;
1510
+ }
1511
+
1512
+ PyObject * result_item = PyTuple_New (2 );
1513
+ if (result_item == NULL ) {
1514
+ Py_DECREF (tn );
1515
+ Py_DECREF (current_awaited_by );
1516
+ return -1 ;
1517
+ }
1518
+
1519
+ PyTuple_SET_ITEM (result_item , 0 , tn ); // steals ref
1520
+ PyTuple_SET_ITEM (result_item , 1 , current_awaited_by ); // steals ref
1521
+ if (PyList_Append (result , result_item )) {
1522
+ Py_DECREF (result_item );
1523
+ return -1 ;
1524
+ }
1525
+ Py_DECREF (result_item );
1526
+
1527
+ if (parse_task_awaited_by (pid , debug_offsets , async_offsets ,
1528
+ task_addr , current_awaited_by ))
1529
+ {
1530
+ return -1 ;
1531
+ }
1532
+
1533
+ // onto the next one...
1534
+ if (0 > read_memory (
1535
+ pid ,
1536
+ (uintptr_t )task_node .next ,
1537
+ sizeof (task_node ),
1538
+ & task_node ))
1539
+ {
1540
+ return -1 ;
1541
+ }
1542
+ }
1543
+
1544
+ return 0 ;
1545
+ }
1546
+
1547
+ static int
1548
+ append_awaited_by (
1549
+ int pid ,
1550
+ unsigned long tid ,
1551
+ uintptr_t head_addr ,
1552
+ struct _Py_DebugOffsets * debug_offsets ,
1553
+ struct _Py_AsyncioModuleDebugOffsets * async_offsets ,
1554
+ PyObject * result )
1555
+ {
1556
+ PyObject * tid_py = PyLong_FromUnsignedLong (tid );
1557
+ if (tid_py == NULL ) {
1558
+ return -1 ;
1559
+ }
1560
+
1561
+ PyObject * result_item = PyTuple_New (2 );
1562
+ if (result_item == NULL ) {
1563
+ Py_DECREF (tid_py );
1564
+ return -1 ;
1565
+ }
1566
+
1567
+ PyObject * awaited_by_for_thread = PyList_New (0 );
1568
+ if (awaited_by_for_thread == NULL ) {
1569
+ Py_DECREF (tid_py );
1570
+ Py_DECREF (result_item );
1571
+ return -1 ;
1572
+ }
1573
+
1574
+ PyTuple_SET_ITEM (result_item , 0 , tid_py ); // steals ref
1575
+ PyTuple_SET_ITEM (result_item , 1 , awaited_by_for_thread ); // steals ref
1576
+ if (PyList_Append (result , result_item )) {
1577
+ Py_DECREF (result_item );
1578
+ return -1 ;
1579
+ }
1580
+ Py_DECREF (result_item );
1581
+
1582
+ if (append_awaited_by_for_thread (
1583
+ pid ,
1584
+ head_addr ,
1585
+ debug_offsets ,
1586
+ async_offsets ,
1587
+ awaited_by_for_thread ))
1588
+ {
1589
+ return -1 ;
1590
+ }
1591
+
1592
+ return 0 ;
1593
+ }
1594
+
1595
+ static PyObject *
1596
+ get_all_awaited_by (PyObject * self , PyObject * args )
1597
+ {
1598
+ #if (!defined(__linux__ ) && !defined(__APPLE__ )) || \
1599
+ (defined(__linux__ ) && !HAVE_PROCESS_VM_READV )
1600
+ PyErr_SetString (
1601
+ PyExc_RuntimeError ,
1602
+ "get_all_awaited_by is not implemented on this platform" );
1603
+ return NULL ;
1604
+ #endif
1605
+
1606
+ int pid ;
1607
+
1608
+ if (!PyArg_ParseTuple (args , "i" , & pid )) {
1609
+ return NULL ;
1610
+ }
1611
+
1612
+ uintptr_t runtime_start_addr = get_py_runtime (pid );
1613
+ if (runtime_start_addr == 0 ) {
1614
+ if (!PyErr_Occurred ()) {
1615
+ PyErr_SetString (
1616
+ PyExc_RuntimeError , "Failed to get .PyRuntime address" );
1617
+ }
1618
+ return NULL ;
1619
+ }
1620
+ struct _Py_DebugOffsets local_debug_offsets ;
1621
+
1622
+ if (read_offsets (pid , & runtime_start_addr , & local_debug_offsets )) {
1623
+ return NULL ;
1624
+ }
1625
+
1626
+ struct _Py_AsyncioModuleDebugOffsets local_async_debug ;
1627
+ if (read_async_debug (pid , & local_async_debug )) {
1628
+ return NULL ;
1629
+ }
1630
+
1631
+ PyObject * result = PyList_New (0 );
1632
+ if (result == NULL ) {
1633
+ return NULL ;
1634
+ }
1635
+
1636
+ off_t interpreter_state_list_head =
1637
+ local_debug_offsets .runtime_state .interpreters_head ;
1638
+
1639
+ uintptr_t interpreter_state_addr ;
1640
+ if (0 > read_memory (
1641
+ pid ,
1642
+ runtime_start_addr + interpreter_state_list_head ,
1643
+ sizeof (void * ),
1644
+ & interpreter_state_addr ))
1645
+ {
1646
+ goto result_err ;
1647
+ }
1648
+
1649
+ uintptr_t thread_state_addr ;
1650
+ unsigned long tid = 0 ;
1651
+ if (0 > read_memory (
1652
+ pid ,
1653
+ interpreter_state_addr
1654
+ + local_debug_offsets .interpreter_state .threads_head ,
1655
+ sizeof (void * ),
1656
+ & thread_state_addr ))
1657
+ {
1658
+ goto result_err ;
1659
+ }
1660
+
1661
+ uintptr_t head_addr ;
1662
+ while (thread_state_addr != 0 ) {
1663
+ if (0 > read_memory (
1664
+ pid ,
1665
+ thread_state_addr
1666
+ + local_debug_offsets .thread_state .native_thread_id ,
1667
+ sizeof (tid ),
1668
+ & tid ))
1669
+ {
1670
+ goto result_err ;
1671
+ }
1672
+
1673
+ head_addr = thread_state_addr
1674
+ + local_async_debug .asyncio_thread_state .asyncio_tasks_head ;
1675
+
1676
+ if (append_awaited_by (pid , tid , head_addr , & local_debug_offsets ,
1677
+ & local_async_debug , result ))
1678
+ {
1679
+ goto result_err ;
1680
+ }
1681
+
1682
+ if (0 > read_memory (
1683
+ pid ,
1684
+ thread_state_addr + local_debug_offsets .thread_state .next ,
1685
+ sizeof (void * ),
1686
+ & thread_state_addr ))
1687
+ {
1688
+ goto result_err ;
1689
+ }
1690
+ }
1691
+
1692
+ head_addr = interpreter_state_addr
1693
+ + local_async_debug .asyncio_interpreter_state .asyncio_tasks_head ;
1694
+
1695
+ if (append_awaited_by (pid , 0 , head_addr , & local_debug_offsets ,
1696
+ & local_async_debug , result ))
1697
+ {
1698
+ goto result_err ;
1699
+ }
1700
+
1701
+ return result ;
1702
+
1703
+ result_err :
1704
+ Py_DECREF (result );
1705
+ return NULL ;
1706
+ }
1707
+
1467
1708
static PyObject *
1468
1709
get_stack_trace (PyObject * self , PyObject * args )
1469
1710
{
@@ -1686,6 +1927,8 @@ static PyMethodDef methods[] = {
1686
1927
"Get the Python stack from a given PID" },
1687
1928
{"get_async_stack_trace" , get_async_stack_trace , METH_VARARGS ,
1688
1929
"Get the asyncio stack from a given PID" },
1930
+ {"get_all_awaited_by" , get_all_awaited_by , METH_VARARGS ,
1931
+ "Get all tasks and their awaited_by from a given PID" },
1689
1932
{NULL , NULL , 0 , NULL },
1690
1933
};
1691
1934
0 commit comments