aboutsummaryrefslogtreecommitdiff
path: root/tracecmd/trace-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'tracecmd/trace-stream.c')
-rw-r--r--tracecmd/trace-stream.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/tracecmd/trace-stream.c b/tracecmd/trace-stream.c
new file mode 100644
index 00000000..ee310f3d
--- /dev/null
+++ b/tracecmd/trace-stream.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "trace-local.h"
+
+/*
+ * Stream runs for a single machine. We are going to cheat
+ * and use the trace-output and trace-input code to create
+ * our pevent. First just create a trace.dat file and then read
+ * it to create the pevent and handle.
+ */
+struct tracecmd_input *
+trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
+ struct hook_list *hooks,
+ tracecmd_handle_init_func handle_init, int global)
+{
+ struct tracecmd_input *trace_input;
+ struct tracecmd_output *trace_output;
+ static FILE *fp = NULL;
+ static int tfd;
+ static int ofd;
+ long flags;
+
+ if (instance->handle) {
+ trace_input = instance->handle;
+ goto make_pipe;
+ }
+
+ if (!fp) {
+ fp = tmpfile();
+ if (!fp)
+ return NULL;
+ tfd = fileno(fp);
+
+ ofd = dup(tfd);
+ trace_output = tracecmd_output_create_fd(ofd);
+ if (!trace_output) {
+ fclose(fp);
+ return NULL;
+ }
+ tracecmd_output_write_headers(trace_output, NULL);
+ tracecmd_output_free(trace_output);
+ }
+
+ lseek(ofd, 0, SEEK_SET);
+
+ trace_input = tracecmd_alloc_fd(ofd, 0);
+ if (!trace_input) {
+ close(ofd);
+ goto fail;
+ }
+
+ if (tracecmd_read_headers(trace_input, TRACECMD_FILE_PRINTK) < 0)
+ goto fail_free_input;
+
+ if (handle_init)
+ handle_init(trace_input, hooks, global);
+
+ make_pipe:
+ /* Do not block on this pipe */
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ if (tracecmd_make_pipe(trace_input, cpu, fd, cpus) < 0)
+ goto fail_free_input;
+
+ instance->handle = trace_input;
+
+ return trace_input;
+
+ fail_free_input:
+ tracecmd_close(trace_input);
+ fail:
+ fclose(fp);
+
+ return NULL;
+}
+
+int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv)
+{
+ struct tep_record *record;
+ struct pid_record_data *pid;
+ struct pid_record_data *last_pid;
+ fd_set rfds;
+ int top_rfd = 0;
+ int nr_fd;
+ int ret;
+ int i;
+
+ last_pid = NULL;
+
+ again:
+ for (i = 0; i < nr_pids; i++) {
+ pid = &pids[i];
+
+ if (!pid->record)
+ pid->record = tracecmd_read_data(pid->instance->handle, pid->cpu);
+ record = pid->record;
+ if (!record && errno == EINVAL)
+ /* pipe has closed */
+ pid->closed = 1;
+
+ if (record &&
+ (!last_pid || record->ts < last_pid->record->ts))
+ last_pid = pid;
+ }
+ if (last_pid) {
+ trace_show_data(last_pid->instance->handle, last_pid->record);
+ tracecmd_free_record(last_pid->record);
+ last_pid->record = NULL;
+ return 1;
+ }
+
+ nr_fd = 0;
+ FD_ZERO(&rfds);
+
+ for (i = 0; i < nr_pids; i++) {
+ /* Do not process closed pipes */
+ if (pids[i].closed)
+ continue;
+ nr_fd++;
+ if (pids[i].brass[0] > top_rfd)
+ top_rfd = pids[i].brass[0];
+
+ FD_SET(pids[i].brass[0], &rfds);
+ }
+
+ if (!nr_fd)
+ return 0;
+
+ ret = select(top_rfd + 1, &rfds, NULL, NULL, tv);
+
+ if (ret > 0)
+ goto again;
+
+ return ret;
+}