1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 *
5 */
6 #include <stdio.h>
7 #include <poll.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <errno.h>
11
12 #include <sys/time.h>
13 #include <sys/types.h>
14
15 #include "trace-local.h"
16
17 /*
18 * Stream runs for a single machine. We are going to cheat
19 * and use the trace-output and trace-input code to create
20 * our pevent. First just create a trace.dat file and then read
21 * it to create the pevent and handle.
22 */
23 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)24 trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
25 struct hook_list *hooks,
26 tracecmd_handle_init_func handle_init, int global)
27 {
28 struct tracecmd_output *trace_output;
29 struct tracecmd_input *trace_input;
30 static FILE *fp = NULL;
31 static int tfd;
32 long flags;
33
34 if (instance->handle) {
35 trace_input = instance->handle;
36 goto make_pipe;
37 }
38
39 if (!fp) {
40 fp = tmpfile();
41 if (!fp)
42 return NULL;
43 tfd = fileno(fp);
44
45 trace_output = tracecmd_output_create_fd(tfd);
46 if (!trace_output)
47 goto fail;
48
49 tracecmd_output_write_headers(trace_output, NULL);
50 tracecmd_output_flush(trace_output);
51 /* Don't close the descriptor, use it for reading */
52 tracecmd_output_free(trace_output);
53 }
54
55 lseek(tfd, 0, SEEK_SET);
56
57 trace_input = tracecmd_alloc_fd(tfd, 0);
58 if (!trace_input)
59 goto fail;
60
61 if (tracecmd_read_headers(trace_input, TRACECMD_FILE_PRINTK) < 0)
62 goto fail_free_input;
63
64 if (handle_init)
65 handle_init(trace_input, hooks, global);
66
67 make_pipe:
68 /* Do not block on this pipe */
69 flags = fcntl(fd, F_GETFL);
70 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
71
72 if (tracecmd_make_pipe(trace_input, cpu, fd, cpus) < 0)
73 goto fail_free_input;
74
75 instance->handle = trace_input;
76
77 return trace_input;
78
79 fail_free_input:
80 tracecmd_close(trace_input);
81 fail:
82 fclose(fp);
83 fp = NULL; /* Try again later? */
84 return NULL;
85 }
86
trace_stream_read(struct pid_record_data * pids,int nr_pids,long sleep_us)87 int trace_stream_read(struct pid_record_data *pids, int nr_pids, long sleep_us)
88 {
89 struct pid_record_data *last_pid;
90 struct pid_record_data *pid;
91 struct tep_record *record;
92 struct pollfd pollfd[nr_pids];
93 long sleep_ms = sleep_us > 0 ? (sleep_us + 999) / 1000 : sleep_us;
94 int ret;
95 int i;
96
97 if (!nr_pids)
98 return 0;
99
100 last_pid = NULL;
101
102 again:
103 for (i = 0; i < nr_pids; i++) {
104 pid = &pids[i];
105
106 if (!pid->record)
107 pid->record = tracecmd_read_data(pid->instance->handle, pid->cpu);
108 record = pid->record;
109 if (!record && errno == EINVAL)
110 /* pipe has closed */
111 pid->closed = 1;
112
113 if (record &&
114 (!last_pid || record->ts < last_pid->record->ts))
115 last_pid = pid;
116 }
117 if (last_pid) {
118 trace_show_data(last_pid->instance->handle, last_pid->record);
119 tracecmd_free_record(last_pid->record);
120 last_pid->record = NULL;
121 return 1;
122 }
123
124 for (i = 0; i < nr_pids; i++) {
125 /* Do not process closed pipes */
126 if (pids[i].closed) {
127 memset(pollfd + i, 0, sizeof(*pollfd));
128 continue;
129 }
130
131 pollfd[i].fd = pids[i].brass[0];
132 pollfd[i].events = POLLIN;
133 }
134
135 ret = poll(pollfd, nr_pids, sleep_ms);
136 if (ret > 0)
137 goto again;
138
139 return ret;
140 }
141