1- # Copyright (c) 2024 , Oracle and/or its affiliates.
1+ # Copyright (c) 2025 , Oracle and/or its affiliates.
22# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
33import argparse
4+ import typing
45
6+ import drgn
57from drgn import Program
68from drgn .helpers .common import escape_ascii_string
79from drgn .helpers .linux .cpumask import for_each_online_cpu
810from drgn .helpers .linux .percpu import per_cpu
911
1012from drgn_tools .bt import bt
13+ from drgn_tools .bt import bt_has_any
1114from drgn_tools .corelens import CorelensModule
15+ from drgn_tools .table import print_table
1216from drgn_tools .task import task_lastrun2now
1317from drgn_tools .util import timestamp_str
1418
@@ -17,7 +21,7 @@ def scan_lockup(
1721 prog : Program , min_run_time_seconds : int = 1 , skip_swapper : bool = True
1822) -> None :
1923 """
20- Scan potential lockups on cpus.
24+ Scan potential lockups on cpus and tasks waiting for RCU .
2125
2226 :param prog: drgn program
2327 :param min_run_time_seconds: int
@@ -47,13 +51,52 @@ def scan_lockup(
4751 print ()
4852 nr_processes += 1
4953
50- print (
51- f"We found { nr_processes } processes running more than { min_run_time_seconds } seconds."
52- )
54+ print (f"We found { nr_processes } processes running more than { min_run_time_seconds } seconds" )
55+
56+ dump_tasks_waiting_rcu_gp (prog , min_run_time_seconds )
57+
58+
59+ def tasks_waiting_rcu_gp (prog : Program ) -> typing .List [typing .Tuple [drgn .Object , drgn .StackFrame ]]:
60+ """
61+ Detects tasks waiting RCU grace period
62+
63+ :param prog: drgn program
64+ """
65+ rcu_gp_fn = ["percpu_ref_switch_to_atomic_sync" ]
66+ return bt_has_any (prog , rcu_gp_fn )
67+
68+
69+ def dump_tasks_waiting_rcu_gp (prog : Program , min_run_time_seconds : int ) -> None :
70+ """
71+ Prints tasks waiting on rcu grace period with details
72+
73+ :param prog: drgn program
74+ :param min_run_time_seconds: int
75+ """
76+ tasks_waiting = tasks_waiting_rcu_gp (prog )
77+ output = [["TASK" , "NAME" , "PID" , "PENDING_TIME" ]]
78+ tasks_pids = set () # remove duplicates
79+ if tasks_waiting :
80+ for t , _ in tasks_waiting :
81+ pending_time = timestamp_str (task_lastrun2now (t ))
82+ pid = t .pid .value_ ()
83+ if pid not in tasks_pids and task_lastrun2now (t ) > min_run_time_seconds * 1e9 :
84+ output .append (
85+ [
86+ hex (t .value_ ()),
87+ escape_ascii_string (t .comm .string_ ()),
88+ pid ,
89+ pending_time
90+ ]
91+ )
92+ tasks_pids .add (pid )
93+ print ()
94+ print (f"We found below tasks waiting for rcu grace period over { min_run_time_seconds } seconds:" )
95+ print_table (output )
5396
5497
5598class LockUp (CorelensModule ):
56- """Print tasks which have been on-cpu for too long"""
99+ """Print tasks which have been on-cpu for too long (possible RCU blockers) and tasks waiting RCU grace period if any """
57100
58101 name = "lockup"
59102
0 commit comments