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 out: 111 mutex_unlock(&thread_mutex); 112 return 0; 113 } 114 115 void foo_bar_unreg(void) 116 { 117 mutex_lock(&thread_mutex); 118 if (--simple_thread_cnt) 119 goto out; 120 121 pr_info("Killing thread for foo_bar_fn\n"); 122 if (simple_tsk_fn) 123 kthread_stop(simple_tsk_fn); 124 simple_tsk_fn = NULL; 125 out: 126 mutex_unlock(&thread_mutex); 127 } 128 129 static int __init trace_event_init(void) 130 { 131 simple_tsk = kthread_run(simple_thread, NULL, "event-sample"); 132 if (IS_ERR(simple_tsk)) 133 return -1; 134 135 return 0; 136 } 137 138 static void __exit trace_event_exit(void) 139 { 140 kthread_stop(simple_tsk); 141 mutex_lock(&thread_mutex); 142 if (simple_tsk_fn) 143 kthread_stop(simple_tsk_fn); 144 simple_tsk_fn = NULL; 145 mutex_unlock(&thread_mutex); 146 } 147 148 module_init(trace_event_init); 149 module_exit(trace_event_exit); 150 151 MODULE_AUTHOR("Steven Rostedt"); 152 MODULE_DESCRIPTION("trace-events-sample"); 153 MODULE_LICENSE("GPL"); 154