Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/virtio/virtio-trace/trace-agent-rw.c
29269 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Read/write thread of a guest agent for virtio-trace
4
*
5
* Copyright (C) 2012 Hitachi, Ltd.
6
* Created by Yoshihiro Yunomae <[email protected]>
7
* Masami Hiramatsu <[email protected]>
8
*/
9
10
#define _GNU_SOURCE
11
#include <fcntl.h>
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <unistd.h>
15
#include <sys/syscall.h>
16
#include "trace-agent.h"
17
18
#define READ_WAIT_USEC 100000
19
20
void *rw_thread_info_new(void)
21
{
22
struct rw_thread_info *rw_ti;
23
24
rw_ti = zalloc(sizeof(struct rw_thread_info));
25
if (rw_ti == NULL) {
26
pr_err("rw_thread_info zalloc error\n");
27
exit(EXIT_FAILURE);
28
}
29
30
rw_ti->cpu_num = -1;
31
rw_ti->in_fd = -1;
32
rw_ti->out_fd = -1;
33
rw_ti->read_pipe = -1;
34
rw_ti->write_pipe = -1;
35
rw_ti->pipe_size = PIPE_INIT;
36
37
return rw_ti;
38
}
39
40
void *rw_thread_init(int cpu, const char *in_path, const char *out_path,
41
bool stdout_flag, unsigned long pipe_size,
42
struct rw_thread_info *rw_ti)
43
{
44
int data_pipe[2];
45
46
rw_ti->cpu_num = cpu;
47
48
/* set read(input) fd */
49
rw_ti->in_fd = open(in_path, O_RDONLY);
50
if (rw_ti->in_fd == -1) {
51
pr_err("Could not open in_fd (CPU:%d)\n", cpu);
52
goto error;
53
}
54
55
/* set write(output) fd */
56
if (!stdout_flag) {
57
/* virtio-serial output mode */
58
rw_ti->out_fd = open(out_path, O_WRONLY);
59
if (rw_ti->out_fd == -1) {
60
pr_err("Could not open out_fd (CPU:%d)\n", cpu);
61
goto error;
62
}
63
} else
64
/* stdout mode */
65
rw_ti->out_fd = STDOUT_FILENO;
66
67
if (pipe2(data_pipe, O_NONBLOCK) < 0) {
68
pr_err("Could not create pipe in rw-thread(%d)\n", cpu);
69
goto error;
70
}
71
72
/*
73
* Size of pipe is 64kB in default based on fs/pipe.c.
74
* To read/write trace data speedy, pipe size is changed.
75
*/
76
if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) {
77
pr_err("Could not change pipe size in rw-thread(%d)\n", cpu);
78
goto error;
79
}
80
81
rw_ti->read_pipe = data_pipe[1];
82
rw_ti->write_pipe = data_pipe[0];
83
rw_ti->pipe_size = pipe_size;
84
85
return NULL;
86
87
error:
88
exit(EXIT_FAILURE);
89
}
90
91
/* Bind a thread to a cpu */
92
static void bind_cpu(int cpu_num)
93
{
94
cpu_set_t mask;
95
96
CPU_ZERO(&mask);
97
CPU_SET(cpu_num, &mask);
98
99
/* bind my thread to cpu_num by assigning zero to the first argument */
100
if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
101
pr_err("Could not set CPU#%d affinity\n", (int)cpu_num);
102
}
103
104
static void *rw_thread_main(void *thread_info)
105
{
106
ssize_t rlen, wlen;
107
ssize_t ret;
108
struct rw_thread_info *ts = (struct rw_thread_info *)thread_info;
109
110
bind_cpu(ts->cpu_num);
111
112
while (1) {
113
/* Wait for a read order of trace data by Host OS */
114
if (!global_run_operation) {
115
pthread_mutex_lock(&mutex_notify);
116
pthread_cond_wait(&cond_wakeup, &mutex_notify);
117
pthread_mutex_unlock(&mutex_notify);
118
}
119
120
if (global_sig_receive)
121
break;
122
123
/*
124
* Each thread read trace_pipe_raw of each cpu bounding the
125
* thread, so contention of multi-threads does not occur.
126
*/
127
rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL,
128
ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE);
129
130
if (rlen < 0) {
131
pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num);
132
goto error;
133
} else if (rlen == 0) {
134
/*
135
* If trace data do not exist or are unreadable not
136
* for exceeding the page size, splice_read returns
137
* NULL. Then, this waits for being filled the data in a
138
* ring-buffer.
139
*/
140
usleep(READ_WAIT_USEC);
141
pr_debug("Read retry(cpu:%d)\n", ts->cpu_num);
142
continue;
143
}
144
145
wlen = 0;
146
147
do {
148
ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL,
149
rlen - wlen,
150
SPLICE_F_MOVE | SPLICE_F_MORE);
151
152
if (ret < 0) {
153
pr_err("Splice_write in rw-thread(%d)\n",
154
ts->cpu_num);
155
goto error;
156
} else if (ret == 0)
157
/*
158
* When host reader is not in time for reading
159
* trace data, guest will be stopped. This is
160
* because char dev in QEMU is not supported
161
* non-blocking mode. Then, writer might be
162
* sleep in that case.
163
* This sleep will be removed by supporting
164
* non-blocking mode.
165
*/
166
sleep(1);
167
wlen += ret;
168
} while (wlen < rlen);
169
}
170
171
return NULL;
172
173
error:
174
exit(EXIT_FAILURE);
175
}
176
177
178
pthread_t rw_thread_run(struct rw_thread_info *rw_ti)
179
{
180
int ret;
181
pthread_t rw_thread_per_cpu;
182
183
ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti);
184
if (ret != 0) {
185
pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num);
186
exit(EXIT_FAILURE);
187
}
188
189
return rw_thread_per_cpu;
190
}
191
192