1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 #include <linux/kthread.h> 4 5 /* 6 * Any file that uses trace points, must include the header. 7 * But only one file, must include the header by defining 8 * CREATE_TRACE_POINTS first. This will make the C code that 9 * creates the handles for the trace points. 10 */ 11 #define CREATE_TRACE_POINTS 12 #include "trace-events-sample.h" 13 14 static const char *random_strings[] = { 15 "Mother Goose", 16 "Snoopy", 17 "Gandalf", 18 "Frodo", 19 "One ring to rule them all" 20 }; 21 22 static void do_simple_thread_func(int cnt, const char *fmt, ...) 23 { 24 unsigned long bitmask[1] = {0xdeadbeefUL}; 25 va_list va; 26 int array[6]; 27 int len = cnt % 5; 28 int i; 29 30 set_current_state(TASK_INTERRUPTIBLE); 31 schedule_timeout(HZ); 32 33 for (i = 0; i < len; i++) 34 array[i] = i + 1; 35 array[i] = 0; 36 37 va_start(va, fmt); 38 39 /* Silly tracepoints */ 40 trace_foo_bar("hello", cnt, array, random_strings[len], 41 current->cpus_ptr, fmt, &va); 42 43 va_end(va); 44 45 trace_foo_with_template_simple("HELLO", cnt); 46 47 trace_foo_bar_with_cond("Some times print", cnt); 48 49 trace_foo_with_template_cond("prints other times", cnt); 50 51 trace_foo_with_template_print("I have to be different", cnt); 52 53 trace_foo_rel_loc("Hello __rel_loc", cnt, bitmask, current->cpus_ptr); 54 } 55 56 static void simple_thread_func(int cnt) 57 { 58 do_simple_thread_func(cnt, "iter=%d", cnt); 59 } 60 61 static int simple_thread(void *arg) 62 { 63 int cnt = 0; 64 65 while (!kthread_should_stop()) 66 simple_thread_func(cnt++); 67 68 return 0; 69 } 70 71 static struct task_struct *simple_tsk; 72 static struct task_struct *simple_tsk_fn; 73 74 static void simple_thread_func_fn(int cnt) 75 { 76 set_current_state(TASK_INTERRUPTIBLE); 77 schedule_timeout(HZ); 78 79 /* More silly tracepoints */ 80 trace_foo_bar_with_fn("Look at me", cnt); 81 trace_foo_with_template_fn("Look at me too", cnt); 82 } 83 84 static int simple_thread_fn(void *arg) 85 { 86 int cnt = 0; 87 88 while (!kthread_should_stop()) 89 simple_thread_func_fn(cnt++); 90 91 return 0; 92 } 93 94 static DEFINE_MUTEX(thread_mutex); 95 static int simple_thread_cnt; 96 97 int foo_bar_reg(void) 98 { 99 mutex_lock(&thread_mutex); 100 if (simple_thread_cnt++) 101 goto out; 102 103 pr_info("Starting thread for foo_bar_fn\n"); 104 /* 105 * We shouldn't be able to start a trace when the module is 106 * unloading (there's other locks to prevent that). But 107 * for consistency sake, we still take the thread_mutex. 108 */ 109 simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn"); 110 if (IS_ERR_OR_NULL(simple_tsk_fn)) { 111 pr_err("Failed to create simple_thread_fn\n"); 112 simple_tsk_fn = NULL; 113 } 114 out: 115 mutex_unlock(&thread_mutex); 116 return 0; 117 } 118 119 void foo_bar_unreg(void) 120 { 121 mutex_lock(&thread_mutex); 122 if (--simple_thread_cnt) 123 goto out; 124 125 pr_info("Killing thread for foo_bar_fn\n"); 126 if (simple_tsk_fn) 127 kthread_stop(simple_tsk_fn); 128 simple_tsk_fn = NULL; 129 out: 130 mutex_unlock(&thread_mutex); 131 } 132 133 static int __init trace_event_init(void) 134 { 135 simple_tsk = kthread_run(simple_thread, NULL, "event-sample"); 136 if (IS_ERR(simple_tsk)) 137 return -1; 138 139 return 0; 140 } 141 142 static void __exit trace_event_exit(void) 143 { 144 kthread_stop(simple_tsk); 145 mutex_lock(&thread_mutex); 146 if (simple_tsk_fn) 147 kthread_stop(simple_tsk_fn); 148 simple_tsk_fn = NULL; 149 mutex_unlock(&thread_mutex); 150 } 151 152 module_init(trace_event_init); 153 module_exit(trace_event_exit); 154 155 MODULE_AUTHOR("Steven Rostedt"); 156 MODULE_DESCRIPTION("trace-events-sample"); 157 MODULE_LICENSE("GPL"); 158