1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/ftrace.h> 3 #include <linux/tracepoint.h> 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/init.h> 7 #include <linux/rv.h> 8 #include <rv/instrumentation.h> 9 10 #define MODULE_NAME "wakeup" 11 12 #include <trace/events/syscalls.h> 13 #include <trace/events/sched.h> 14 #include <trace/events/lock.h> 15 #include <uapi/linux/futex.h> 16 17 #include <rv_trace.h> 18 #include <monitors/rtapp/rtapp.h> 19 20 21 #ifndef __NR_futex 22 #define __NR_futex (-__COUNTER__) 23 #endif 24 #ifndef __NR_futex_time64 25 #define __NR_futex_time64 (-__COUNTER__) 26 #endif 27 28 #include "wakeup.h" 29 #include <rv/ltl_monitor.h> 30 31 static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) 32 { 33 /* 34 * This includes "actual" real-time tasks and also PI-boosted 35 * tasks. A task being PI-boosted means it is blocking an "actual" 36 * real-task, therefore it should also obey the monitor's rule, 37 * otherwise the "actual" real-task may be delayed. 38 */ 39 ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); 40 } 41 42 static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) 43 { 44 ltl_atom_set(mon, LTL_WOKEN_BY_LOWER_PRIO, false); 45 ltl_atom_set(mon, LTL_WOKEN_BY_SOFTIRQ, false); 46 47 if (task_creation) { 48 ltl_atom_set(mon, LTL_BLOCK_ON_RT_MUTEX, false); 49 ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 50 } 51 52 ltl_atom_set(mon, LTL_USER_THREAD, !(task->flags & PF_KTHREAD)); 53 } 54 55 static void handle_sched_waking(void *data, struct task_struct *task) 56 { 57 if (in_task()) { 58 if (current->prio > task->prio) 59 ltl_atom_pulse(task, LTL_WOKEN_BY_LOWER_PRIO, true); 60 } else if (in_serving_softirq()) { 61 ltl_atom_pulse(task, LTL_WOKEN_BY_SOFTIRQ, true); 62 } 63 } 64 65 static void handle_contention_begin(void *data, void *lock, unsigned int flags) 66 { 67 if (flags & LCB_F_RT) 68 ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, true); 69 } 70 71 static void handle_contention_end(void *data, void *lock, int ret) 72 { 73 ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, false); 74 } 75 76 static void handle_sys_enter(void *data, struct pt_regs *regs, long id) 77 { 78 unsigned long args[6]; 79 int op, cmd; 80 81 switch (id) { 82 case __NR_futex: 83 case __NR_futex_time64: 84 syscall_get_arguments(current, regs, args); 85 op = args[1]; 86 cmd = op & FUTEX_CMD_MASK; 87 88 switch (cmd) { 89 case FUTEX_LOCK_PI: 90 case FUTEX_LOCK_PI2: 91 ltl_atom_update(current, LTL_FUTEX_LOCK_PI, true); 92 break; 93 } 94 break; 95 } 96 } 97 98 static void handle_sys_exit(void *data, struct pt_regs *regs, long ret) 99 { 100 ltl_atom_update(current, LTL_FUTEX_LOCK_PI, false); 101 } 102 103 static int enable_wakeup(void) 104 { 105 int retval; 106 107 retval = ltl_monitor_init(); 108 if (retval) 109 return retval; 110 111 rv_attach_trace_probe("rtapp_wakeup", sched_waking, handle_sched_waking); 112 rv_attach_trace_probe("rtapp_wakeup", contention_begin, handle_contention_begin); 113 rv_attach_trace_probe("rtapp_wakeup", contention_end, handle_contention_end); 114 rv_attach_trace_probe("rtapp_wakeup", sys_enter, handle_sys_enter); 115 rv_attach_trace_probe("rtapp_wakeup", sys_exit, handle_sys_exit); 116 117 return 0; 118 } 119 120 static void disable_wakeup(void) 121 { 122 rv_detach_trace_probe("rtapp_wakeup", sched_waking, handle_sched_waking); 123 rv_detach_trace_probe("rtapp_wakeup", contention_begin, handle_contention_begin); 124 rv_detach_trace_probe("rtapp_wakeup", contention_end, handle_contention_end); 125 rv_detach_trace_probe("rtapp_wakeup", sys_enter, handle_sys_enter); 126 rv_detach_trace_probe("rtapp_wakeup", sys_exit, handle_sys_exit); 127 128 ltl_monitor_destroy(); 129 } 130 131 static struct rv_monitor rv_wakeup = { 132 .name = "wakeup", 133 .description = "Monitor that real-time tasks are not woken by lower-priority tasks", 134 .enable = enable_wakeup, 135 .disable = disable_wakeup, 136 }; 137 138 static int __init register_wakeup(void) 139 { 140 return rv_register_monitor(&rv_wakeup, &rv_rtapp); 141 } 142 143 static void __exit unregister_wakeup(void) 144 { 145 rv_unregister_monitor(&rv_wakeup); 146 } 147 148 module_init(register_wakeup); 149 module_exit(unregister_wakeup); 150 151 MODULE_LICENSE("GPL"); 152 MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); 153 MODULE_DESCRIPTION("Monitor that real-time tasks are not woken by lower-priority tasks"); 154