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 simple_thread_func(int cnt) 23 { 24 unsigned long bitmask[1] = {0xdeadbeefUL}; 25 int array[6]; 26 int len = cnt % 5; 27 int i; 28 29 set_current_state(TASK_INTERRUPTIBLE); 30 schedule_timeout(HZ); 31 32 for (i = 0; i < len; i++) 33 array[i] = i + 1; 34 array[i] = 0; 35 36 /* Silly tracepoints */ 37 trace_foo_bar("hello", cnt, array, random_strings[len], 38 current->cpus_ptr); 39 40 trace_foo_with_template_simple("HELLO", cnt); 41 42 trace_foo_bar_with_cond("Some times print", cnt); 43 44 trace_foo_with_template_cond("prints other times", cnt); 45 46 trace_foo_with_template_print("I have to be different", cnt); 47 48 trace_foo_rel_loc("Hello __rel_loc", cnt, bitmask); 49 } 50 51 static int simple_thread(void *arg) 52 { 53 int cnt = 0; 54 55 while (!kthread_should_stop()) 56 simple_thread_func(cnt++); 57 58 return 0; 59 } 60 61 static struct task_struct *simple_tsk; 62 static struct task_struct *simple_tsk_fn; 63 64 static void simple_thread_func_fn(int cnt) 65 { 66 set_current_state(TASK_INTERRUPTIBLE); 67 schedule_timeout(HZ); 68 69 /* More silly tracepoints */ 70 trace_foo_bar_with_fn("Look at me", cnt); 71 trace_foo_with_template_fn("Look at me too", cnt); 72 } 73 74 static int simple_thread_fn(void *arg) 75 { 76 int cnt = 0; 77 78 while (!kthread_should_stop()) 79 simple_thread_func_fn(cnt++); 80 81 return 0; 82 } 83 84 static DEFINE_MUTEX(thread_mutex); 85 static int simple_thread_cnt; 86 87 int foo_bar_reg(void) 88 { 89 mutex_lock(&thread_mutex); 90 if (simple_thread_cnt++) 91 goto out; 92 93 pr_info("Starting thread for foo_bar_fn\n"); 94 /* 95 * We shouldn't be able to start a trace when the module is 96 * unloading (there's other locks to prevent that). But 97 * for consistency sake, we still take the thread_mutex. 98 */ 99 simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn"); 100 out: 101 mutex_unlock(&thread_mutex); 102 return 0; 103 } 104 105 void foo_bar_unreg(void) 106 { 107 mutex_lock(&thread_mutex); 108 if (--simple_thread_cnt) 109 goto out; 110 111 pr_info("Killing thread for foo_bar_fn\n"); 112 if (simple_tsk_fn) 113 kthread_stop(simple_tsk_fn); 114 simple_tsk_fn = NULL; 115 out: 116 mutex_unlock(&thread_mutex); 117 } 118 119 static int __init trace_event_init(void) 120 { 121 simple_tsk = kthread_run(simple_thread, NULL, "event-sample"); 122 if (IS_ERR(simple_tsk)) 123 return -1; 124 125 return 0; 126 } 127 128 static void __exit trace_event_exit(void) 129 { 130 kthread_stop(simple_tsk); 131 mutex_lock(&thread_mutex); 132 if (simple_tsk_fn) 133 kthread_stop(simple_tsk_fn); 134 simple_tsk_fn = NULL; 135 mutex_unlock(&thread_mutex); 136 } 137 138 module_init(trace_event_init); 139 module_exit(trace_event_exit); 140 141 MODULE_AUTHOR("Steven Rostedt"); 142 MODULE_DESCRIPTION("trace-events-sample"); 143 MODULE_LICENSE("GPL"); 144