root/tools/virtio/virtio-trace/trace-agent-rw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rw_thread_info_new
  2. rw_thread_init
  3. bind_cpu
  4. rw_thread_main
  5. rw_thread_run

   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 }

/* [<][>][^][v][top][bottom][index][help] */