xref: /linux/kernel/trace/rv/monitors/wakeup/wakeup.c (revision 55ee4b931a7ffedc886175d265dd6e6d08fd4151)
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