tracing: Add TRACE_EVENT_FN example
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Mon, 9 Feb 2015 21:32:19 +0000 (16:32 -0500)
committerSteven Rostedt <rostedt@goodmis.org>
Mon, 9 Feb 2015 23:05:39 +0000 (18:05 -0500)
If a function should be called before a tracepoint is enabled
and/or after it is disabled, the TRACE_EVENT_FN() serves this
purpose. But it is not well documented. Having it as a sample would
help developers to know how to use it.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
samples/trace_events/trace-events-sample.c
samples/trace_events/trace-events-sample.h

index c396a49..39d4484 100644 (file)
@@ -49,6 +49,52 @@ static int simple_thread(void *arg)
 }
 
 static struct task_struct *simple_tsk;
+static struct task_struct *simple_tsk_fn;
+
+static void simple_thread_func_fn(int cnt)
+{
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(HZ);
+
+       /* More silly tracepoints */
+       trace_foo_bar_with_fn("Look at me", cnt);
+}
+
+static int simple_thread_fn(void *arg)
+{
+       int cnt = 0;
+
+       while (!kthread_should_stop())
+               simple_thread_func_fn(cnt++);
+
+       return 0;
+}
+
+static DEFINE_MUTEX(thread_mutex);
+
+void foo_bar_reg(void)
+{
+       pr_info("Starting thread for foo_bar_fn\n");
+       /*
+        * We shouldn't be able to start a trace when the module is
+        * unloading (there's other locks to prevent that). But
+        * for consistency sake, we still take the thread_mutex.
+        */
+       mutex_lock(&thread_mutex);
+       simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn");
+       mutex_unlock(&thread_mutex);
+}
+
+void foo_bar_unreg(void)
+{
+       pr_info("Killing thread for foo_bar_fn\n");
+       /* protect against module unloading */
+       mutex_lock(&thread_mutex);
+       if (simple_tsk_fn)
+               kthread_stop(simple_tsk_fn);
+       simple_tsk_fn = NULL;
+       mutex_unlock(&thread_mutex);
+}
 
 static int __init trace_event_init(void)
 {
@@ -62,6 +108,11 @@ static int __init trace_event_init(void)
 static void __exit trace_event_exit(void)
 {
        kthread_stop(simple_tsk);
+       mutex_lock(&thread_mutex);
+       if (simple_tsk_fn)
+               kthread_stop(simple_tsk_fn);
+       simple_tsk_fn = NULL;
+       mutex_unlock(&thread_mutex);
 }
 
 module_init(trace_event_init);
index c323234..d0be841 100644 (file)
@@ -270,6 +270,50 @@ TRACE_EVENT_CONDITION(foo_bar_with_cond,
 
        TP_printk("foo %s %d", __get_str(foo), __entry->bar)
 );
+
+void foo_bar_reg(void);
+void foo_bar_unreg(void);
+
+/*
+ * Now in the case that some function needs to be called when the
+ * tracepoint is enabled and/or when it is disabled, the
+ * TRACE_EVENT_FN() serves this purpose. This is just like TRACE_EVENT()
+ * but adds two more parameters at the end:
+ *
+ * TRACE_EVENT_FN( name, proto, args, struct, assign, printk, reg, unreg)
+ *
+ * reg and unreg are functions with the prototype of:
+ *
+ *    void reg(void)
+ *
+ * The reg function gets called before the tracepoint is enabled, and
+ * the unreg function gets called after the tracepoint is disabled.
+ *
+ * Note, reg and unreg are allowed to be NULL. If you only need to
+ * call a function before enabling, or after disabling, just set one
+ * function and pass in NULL for the other parameter.
+ */
+TRACE_EVENT_FN(foo_bar_with_fn,
+
+       TP_PROTO(const char *foo, int bar),
+
+       TP_ARGS(foo, bar),
+
+       TP_STRUCT__entry(
+               __string(       foo,    foo             )
+               __field(        int,    bar             )
+       ),
+
+       TP_fast_assign(
+               __assign_str(foo, foo);
+               __entry->bar    = bar;
+       ),
+
+       TP_printk("foo %s %d", __get_str(foo), __entry->bar),
+
+       foo_bar_reg, foo_bar_unreg
+);
+
 #endif
 
 /***** NOTICE! The #if protection ends here. *****/