1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/ftrace.h> 3 #include <linux/tracepoint.h> 4 #include <linux/init.h> 5 #include <linux/irqflags.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/rv.h> 9 #include <linux/sched/deadline.h> 10 #include <linux/sched/rt.h> 11 #include <rv/instrumentation.h> 12 13 #define MODULE_NAME "sleep" 14 15 #include <trace/events/syscalls.h> 16 #include <trace/events/sched.h> 17 #include <trace/events/lock.h> 18 #include <uapi/linux/futex.h> 19 #include <rv_trace.h> 20 #include <monitors/rtapp/rtapp.h> 21 22 #include "sleep.h" 23 #include <rv/ltl_monitor.h> 24 25 static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) 26 { 27 /* 28 * This includes "actual" real-time tasks and also PI-boosted 29 * tasks. A task being PI-boosted means it is blocking an "actual" 30 * real-task, therefore it should also obey the monitor's rule, 31 * otherwise the "actual" real-task may be delayed. 32 */ 33 ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); 34 } 35 36 static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) 37 { 38 ltl_atom_set(mon, LTL_SLEEP, false); 39 ltl_atom_set(mon, LTL_WAKE, false); 40 ltl_atom_set(mon, LTL_ABORT_SLEEP, false); 41 ltl_atom_set(mon, LTL_WOKEN_BY_HARDIRQ, false); 42 ltl_atom_set(mon, LTL_WOKEN_BY_NMI, false); 43 ltl_atom_set(mon, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, false); 44 45 if (task_creation) { 46 ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); 47 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 48 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 49 ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 50 ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); 51 ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 52 ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 53 ltl_atom_set(mon, LTL_BLOCK_ON_RT_MUTEX, false); 54 } 55 56 if (task->flags & PF_KTHREAD) { 57 ltl_atom_set(mon, LTL_KERNEL_THREAD, true); 58 59 /* kernel tasks do not do syscall */ 60 ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 61 ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 62 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 63 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 64 ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 65 ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); 66 67 if (strstarts(task->comm, "migration/")) 68 ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, true); 69 else 70 ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); 71 72 if (strstarts(task->comm, "rcu")) 73 ltl_atom_set(mon, LTL_TASK_IS_RCU, true); 74 else 75 ltl_atom_set(mon, LTL_TASK_IS_RCU, false); 76 } else { 77 ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); 78 ltl_atom_set(mon, LTL_KERNEL_THREAD, false); 79 ltl_atom_set(mon, LTL_TASK_IS_RCU, false); 80 ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); 81 } 82 83 } 84 85 static void handle_sched_set_state(void *data, struct task_struct *task, int state) 86 { 87 if (state & TASK_INTERRUPTIBLE) 88 ltl_atom_pulse(task, LTL_SLEEP, true); 89 else if (state == TASK_RUNNING) 90 ltl_atom_pulse(task, LTL_ABORT_SLEEP, true); 91 } 92 93 static void handle_sched_wakeup(void *data, struct task_struct *task) 94 { 95 ltl_atom_pulse(task, LTL_WAKE, true); 96 } 97 98 static void handle_sched_waking(void *data, struct task_struct *task) 99 { 100 if (this_cpu_read(hardirq_context)) { 101 ltl_atom_pulse(task, LTL_WOKEN_BY_HARDIRQ, true); 102 } else if (in_task()) { 103 if (current->prio <= task->prio) 104 ltl_atom_pulse(task, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, true); 105 } else if (in_nmi()) { 106 ltl_atom_pulse(task, LTL_WOKEN_BY_NMI, true); 107 } 108 } 109 110 static void handle_contention_begin(void *data, void *lock, unsigned int flags) 111 { 112 if (flags & LCB_F_RT) 113 ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, true); 114 } 115 116 static void handle_contention_end(void *data, void *lock, int ret) 117 { 118 ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, false); 119 } 120 121 static void handle_sys_enter(void *data, struct pt_regs *regs, long id) 122 { 123 struct ltl_monitor *mon; 124 unsigned long args[6]; 125 int op, cmd; 126 127 mon = ltl_get_monitor(current); 128 129 switch (id) { 130 case __NR_clock_nanosleep: 131 #ifdef __NR_clock_nanosleep_time64 132 case __NR_clock_nanosleep_time64: 133 #endif 134 syscall_get_arguments(current, regs, args); 135 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, args[0] == CLOCK_MONOTONIC); 136 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, args[0] == CLOCK_TAI); 137 ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, args[1] == TIMER_ABSTIME); 138 ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, true); 139 break; 140 141 case __NR_futex: 142 #ifdef __NR_futex_time64 143 case __NR_futex_time64: 144 #endif 145 syscall_get_arguments(current, regs, args); 146 op = args[1]; 147 cmd = op & FUTEX_CMD_MASK; 148 149 switch (cmd) { 150 case FUTEX_LOCK_PI: 151 case FUTEX_LOCK_PI2: 152 ltl_atom_update(current, LTL_FUTEX_LOCK_PI, true); 153 break; 154 case FUTEX_WAIT: 155 case FUTEX_WAIT_BITSET: 156 case FUTEX_WAIT_REQUEUE_PI: 157 ltl_atom_update(current, LTL_FUTEX_WAIT, true); 158 break; 159 } 160 break; 161 } 162 } 163 164 static void handle_sys_exit(void *data, struct pt_regs *regs, long ret) 165 { 166 struct ltl_monitor *mon = ltl_get_monitor(current); 167 168 ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 169 ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 170 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 171 ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 172 ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 173 ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, false); 174 } 175 176 static void handle_kthread_stop(void *data, struct task_struct *task) 177 { 178 /* FIXME: this could race with other tracepoint handlers */ 179 ltl_atom_update(task, LTL_KTHREAD_SHOULD_STOP, true); 180 } 181 182 static int enable_sleep(void) 183 { 184 int retval; 185 186 retval = ltl_monitor_init(); 187 if (retval) 188 return retval; 189 190 rv_attach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); 191 rv_attach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); 192 rv_attach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); 193 rv_attach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); 194 rv_attach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); 195 rv_attach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_stop); 196 rv_attach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); 197 rv_attach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); 198 return 0; 199 } 200 201 static void disable_sleep(void) 202 { 203 rv_detach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); 204 rv_detach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); 205 rv_detach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); 206 rv_detach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); 207 rv_detach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); 208 rv_detach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_stop); 209 rv_detach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); 210 rv_detach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); 211 212 ltl_monitor_destroy(); 213 } 214 215 static struct rv_monitor rv_sleep = { 216 .name = "sleep", 217 .description = "Monitor that RT tasks do not undesirably sleep", 218 .enable = enable_sleep, 219 .disable = disable_sleep, 220 }; 221 222 static int __init register_sleep(void) 223 { 224 return rv_register_monitor(&rv_sleep, &rv_rtapp); 225 } 226 227 static void __exit unregister_sleep(void) 228 { 229 rv_unregister_monitor(&rv_sleep); 230 } 231 232 module_init(register_sleep); 233 module_exit(unregister_sleep); 234 235 MODULE_LICENSE("GPL"); 236 MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); 237 MODULE_DESCRIPTION("sleep: Monitor that RT tasks do not undesirably sleep"); 238