trace-cmd: allow for custom show and handle init

External applications that need to hook into the streaming infrastructure need a
way to have the handle init'ed in a specific way and need a way to provide their
own read function so they can intercept events.  This patch adds the neccessary
definitions and hooks.  Thanks,

Link: http://lkml.kernel.org/r/1448053053-24188-6-git-send-email-jbacik@fb.com

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
diff --git a/trace-cmd.h b/trace-cmd.h
index e427d90..6a22910 100644
--- a/trace-cmd.h
+++ b/trace-cmd.h
@@ -61,6 +61,7 @@
 struct tracecmd_input;
 struct tracecmd_output;
 struct tracecmd_recorder;
+struct hook_list;
 
 static inline int tracecmd_host_bigendian(void)
 {
@@ -103,6 +104,11 @@
 	int long_size;
 };
 
+typedef void (*tracecmd_show_data_func)(struct tracecmd_input *handle,
+					struct pevent_record *record);
+typedef void (*tracecmd_handle_init_func)(struct tracecmd_input *handle,
+					  struct hook_list *hook, int global);
+
 struct tracecmd_input *tracecmd_alloc(const char *file);
 struct tracecmd_input *tracecmd_alloc_fd(int fd);
 struct tracecmd_input *tracecmd_open(const char *file);
@@ -193,6 +199,10 @@
 int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo);
 struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle);
 bool tracecmd_get_use_trace_clock(struct tracecmd_input *handle);
+tracecmd_show_data_func
+tracecmd_get_show_data_func(struct tracecmd_input *handle);
+void tracecmd_set_show_data_func(struct tracecmd_input *handle,
+				 tracecmd_show_data_func func);
 
 char *tracecmd_get_tracing_file(const char *name);
 void tracecmd_put_tracing_file(char *name);
diff --git a/trace-input.c b/trace-input.c
index e7d447b..b90b31e 100644
--- a/trace-input.c
+++ b/trace-input.c
@@ -125,6 +125,9 @@
 	size_t			ftrace_files_start;
 	size_t			event_files_start;
 	size_t			total_file_size;
+
+	/* For custom profilers. */
+	tracecmd_show_data_func	show_data_func;
 };
 
 __thread struct tracecmd_input *tracecmd_curr_thread_handle;
@@ -3203,3 +3206,23 @@
 {
 	return handle->use_trace_clock;
 }
+
+/**
+ * tracecmd_get_show_data_func - return the show data func
+ * @handle: input handle for the trace.dat file
+ */
+tracecmd_show_data_func
+tracecmd_get_show_data_func(struct tracecmd_input *handle)
+{
+	return handle->show_data_func;
+}
+
+/**
+ * tracecmd_set_show_data_func - set the show data func
+ * @handle: input handle for the trace.dat file
+ */
+void tracecmd_set_show_data_func(struct tracecmd_input *handle,
+				 tracecmd_show_data_func func)
+{
+	handle->show_data_func = func;
+}
diff --git a/trace-local.h b/trace-local.h
index aa03221..46aa979 100644
--- a/trace-local.h
+++ b/trace-local.h
@@ -79,8 +79,6 @@
 
 struct hook_list;
 
-int trace_profile_record(struct tracecmd_input *handle,
-			 struct pevent_record *record, int cpu);
 void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hooks,
 			int global);
 int trace_profile(void);
@@ -88,12 +86,11 @@
 
 struct tracecmd_input *
 trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
-		  int profile, struct hook_list *hooks, int global);
-int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv,
-		      int profile);
+		  struct hook_list *hooks,
+		  tracecmd_handle_init_func handle_init, int global);
+int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv);
 
-void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record,
-		     int profile);
+void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record);
 
 /* --- event interation --- */
 
diff --git a/trace-profile.c b/trace-profile.c
index 507a0c3..0af27cd 100644
--- a/trace-profile.c
+++ b/trace-profile.c
@@ -745,8 +745,8 @@
 	return NULL;
 }
 
-int trace_profile_record(struct tracecmd_input *handle,
-			 struct pevent_record *record, int cpu)
+static void trace_profile_record(struct tracecmd_input *handle,
+				struct pevent_record *record)
 {
 	static struct handle_data *last_handle;
 	struct pevent_record *stack_record;
@@ -755,6 +755,7 @@
 	struct handle_data *h;
 	struct pevent *pevent;
 	unsigned long long pid;
+	int cpu = record->cpu;
 	int id;
 
 	if (last_handle && last_handle->handle == handle)
@@ -779,7 +780,7 @@
 	event_data = find_event_data(h, id);
 
 	if (!event_data)
-		return -1;
+		return;
 
 
 	/* Get this current PID */
@@ -787,7 +788,7 @@
 
 	task = find_task(h, pid);
 	if (!task)
-		return -1;
+		return;
 	stack_record = task->last_stack;
 
 	if (event_data->handle_event)
@@ -800,8 +801,6 @@
 		free_record(stack_record);
 		task->last_stack = NULL;
 	}
-
-	return 0;
 }
 
 static struct event_data *
@@ -1302,6 +1301,7 @@
 	int ret;
 	int i;
 
+	tracecmd_set_show_data_func(handle, trace_profile_record);
 	h = malloc(sizeof(*h));
 	if (!h) {
 		warning("Could not allocate handle");
diff --git a/trace-read.c b/trace-read.c
index 40055a3..685a81b 100644
--- a/trace-read.c
+++ b/trace-read.c
@@ -761,9 +761,9 @@
 	trace_hash_free(&wakeup_hash);
 }
 
-void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record,
-		     int profile)
+void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record)
 {
+	tracecmd_show_data_func func = tracecmd_get_show_data_func(handle);
 	struct pevent *pevent;
 	struct trace_seq s;
 	int cpu = record->cpu;
@@ -772,15 +772,15 @@
 	unsigned long long diff_ts;
 	char buf[50];
 
-	pevent = tracecmd_get_pevent(handle);
-
 	test_save(record, cpu);
 
-	if (profile) {
-		trace_profile_record(handle, record, cpu);
+	if (func) {
+		func(handle, record);
 		return;
 	}
 
+	pevent = tracecmd_get_pevent(handle);
+
 	trace_seq_init(&s);
 	if (record->missed_events > 0)
 		trace_seq_printf(&s, "CPU:%d [%lld EVENTS DROPPED]\n",
@@ -1219,7 +1219,7 @@
 		}
 		if (last_record) {
 			print_handle_file(last_handle);
-			trace_show_data(last_handle->handle, last_record, profile);
+			trace_show_data(last_handle->handle, last_record);
 			free_handle_record(last_handle);
 		}
 	} while (last_record);
diff --git a/trace-record.c b/trace-record.c
index 84a6707..bd60892 100644
--- a/trace-record.c
+++ b/trace-record.c
@@ -66,9 +66,10 @@
 	TRACE_TYPE_START	= (1 << 1),
 	TRACE_TYPE_STREAM	= (1 << 2),
 	TRACE_TYPE_EXTRACT	= (1 << 3),
-	TRACE_TYPE_PROFILE	= (1 << 4) | TRACE_TYPE_STREAM,
 };
 
+static tracecmd_handle_init_func handle_init = NULL;
+
 static int rt_prio;
 
 static int keep;
@@ -603,7 +604,6 @@
 static void stop_threads(enum trace_type type)
 {
 	struct timeval tv = { 0, 0 };
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 	int ret;
 	int i;
 
@@ -620,7 +620,7 @@
 	/* Flush out the pipes */
 	if (type & TRACE_TYPE_STREAM) {
 		do {
-			ret = trace_stream_read(pids, recorder_threads, &tv, profile);
+			ret = trace_stream_read(pids, recorder_threads, &tv);
 		} while (ret > 0);
 	}
 
@@ -990,7 +990,6 @@
 {
 	struct timeval tv = { 1, 0 };
 	int ret;
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 
 	if (type & TRACE_TYPE_STREAM)
 		options |= WNOHANG;
@@ -1001,7 +1000,7 @@
 			return ret;
 
 		if (type & TRACE_TYPE_STREAM)
-			trace_stream_read(pids, recorder_threads, &tv, profile);
+			trace_stream_read(pids, recorder_threads, &tv);
 	} while (1);
 }
 #ifndef NO_PTRACE
@@ -1182,12 +1181,11 @@
 static void trace_or_sleep(enum trace_type type)
 {
 	struct timeval tv = { 1 , 0 };
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 
 	if (do_ptrace && filter_pid >= 0)
 		ptrace_wait(type, filter_pid);
 	else if (type & TRACE_TYPE_STREAM)
-		trace_stream_read(pids, recorder_threads, &tv, profile);
+		trace_stream_read(pids, recorder_threads, &tv);
 	else
 		sleep(10);
 }
@@ -2851,7 +2849,6 @@
 
 static void start_threads(enum trace_type type, int global)
 {
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 	struct buffer_instance *instance;
 	int *brass = NULL;
 	int i = 0;
@@ -2877,7 +2874,7 @@
 					die("pipe");
 				pids[i].stream = trace_stream_init(instance, x,
 								   brass[0], cpu_count,
-								   profile, hooks,
+								   hooks, handle_init,
 								   global);
 				if (!pids[i].stream)
 					die("Creating stream for %d", i);
@@ -4213,8 +4210,8 @@
 	else if ((stream = strcmp(argv[1], "stream") == 0))
 		; /* do nothing */
 	else if ((profile = strcmp(argv[1], "profile") == 0)) {
+		handle_init = trace_init_profile;
 		events = 1;
-
 	} else if (strcmp(argv[1], "stop") == 0) {
 		for (;;) {
 			int c;
@@ -4608,6 +4605,7 @@
 			recorder_flags |= TRACECMD_RECORD_NOSPLICE;
 			break;
 		case OPT_profile:
+			handle_init = trace_init_profile;
 			instance->profile = 1;
 			events = 1;
 			break;
@@ -4738,8 +4736,7 @@
 	else if (extract)
 		type = TRACE_TYPE_EXTRACT;
 	else if (profile)
-		/* PROFILE includes the STREAM bit */
-		type = TRACE_TYPE_PROFILE;
+		type = TRACE_TYPE_STREAM;
 	else
 		type = TRACE_TYPE_START;
 
diff --git a/trace-stream.c b/trace-stream.c
index 9ebe65b..0dbeaf2 100644
--- a/trace-stream.c
+++ b/trace-stream.c
@@ -35,7 +35,8 @@
  */
 struct tracecmd_input *
 trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
-		  int profile, struct hook_list *hooks, int global)
+		  struct hook_list *hooks,
+		  tracecmd_handle_init_func handle_init, int global)
 {
 	struct tracecmd_input *trace_input;
 	struct tracecmd_output *trace_output;
@@ -75,8 +76,8 @@
 	if (tracecmd_read_headers(trace_input) < 0)
 		goto fail_free_input;
 
-	if (profile)
-		trace_init_profile(trace_input, hooks, global);
+	if (handle_init)
+		handle_init(trace_input, hooks, global);
 
  make_pipe:
 	/* Do not block on this pipe */
@@ -98,8 +99,7 @@
 	return NULL;
 }
 
-int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv,
-		      int profile)
+int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv)
 {
 	struct pevent_record *record;
 	struct pid_record_data *pid;
@@ -127,7 +127,7 @@
 			last_pid = pid;
 	}
 	if (last_pid) {
-		trace_show_data(last_pid->instance->handle, last_pid->record, profile);
+		trace_show_data(last_pid->instance->handle, last_pid->record);
 		free_record(last_pid->record);
 		last_pid->record = NULL;
 		return 1;