~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/virtio/virtio-trace/trace-agent-rw.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <yoshihiro.yunomae.ez@hitachi.com>
  7  *            Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php