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