Path: blob/master/tools/virtio/virtio-trace/trace-agent-rw.c
29269 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Read/write thread of a guest agent for virtio-trace3*4* Copyright (C) 2012 Hitachi, Ltd.5* Created by Yoshihiro Yunomae <[email protected]>6* Masami Hiramatsu <[email protected]>7*/89#define _GNU_SOURCE10#include <fcntl.h>11#include <stdio.h>12#include <stdlib.h>13#include <unistd.h>14#include <sys/syscall.h>15#include "trace-agent.h"1617#define READ_WAIT_USEC 1000001819void *rw_thread_info_new(void)20{21struct rw_thread_info *rw_ti;2223rw_ti = zalloc(sizeof(struct rw_thread_info));24if (rw_ti == NULL) {25pr_err("rw_thread_info zalloc error\n");26exit(EXIT_FAILURE);27}2829rw_ti->cpu_num = -1;30rw_ti->in_fd = -1;31rw_ti->out_fd = -1;32rw_ti->read_pipe = -1;33rw_ti->write_pipe = -1;34rw_ti->pipe_size = PIPE_INIT;3536return rw_ti;37}3839void *rw_thread_init(int cpu, const char *in_path, const char *out_path,40bool stdout_flag, unsigned long pipe_size,41struct rw_thread_info *rw_ti)42{43int data_pipe[2];4445rw_ti->cpu_num = cpu;4647/* set read(input) fd */48rw_ti->in_fd = open(in_path, O_RDONLY);49if (rw_ti->in_fd == -1) {50pr_err("Could not open in_fd (CPU:%d)\n", cpu);51goto error;52}5354/* set write(output) fd */55if (!stdout_flag) {56/* virtio-serial output mode */57rw_ti->out_fd = open(out_path, O_WRONLY);58if (rw_ti->out_fd == -1) {59pr_err("Could not open out_fd (CPU:%d)\n", cpu);60goto error;61}62} else63/* stdout mode */64rw_ti->out_fd = STDOUT_FILENO;6566if (pipe2(data_pipe, O_NONBLOCK) < 0) {67pr_err("Could not create pipe in rw-thread(%d)\n", cpu);68goto error;69}7071/*72* Size of pipe is 64kB in default based on fs/pipe.c.73* To read/write trace data speedy, pipe size is changed.74*/75if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) {76pr_err("Could not change pipe size in rw-thread(%d)\n", cpu);77goto error;78}7980rw_ti->read_pipe = data_pipe[1];81rw_ti->write_pipe = data_pipe[0];82rw_ti->pipe_size = pipe_size;8384return NULL;8586error:87exit(EXIT_FAILURE);88}8990/* Bind a thread to a cpu */91static void bind_cpu(int cpu_num)92{93cpu_set_t mask;9495CPU_ZERO(&mask);96CPU_SET(cpu_num, &mask);9798/* bind my thread to cpu_num by assigning zero to the first argument */99if (sched_setaffinity(0, sizeof(mask), &mask) == -1)100pr_err("Could not set CPU#%d affinity\n", (int)cpu_num);101}102103static void *rw_thread_main(void *thread_info)104{105ssize_t rlen, wlen;106ssize_t ret;107struct rw_thread_info *ts = (struct rw_thread_info *)thread_info;108109bind_cpu(ts->cpu_num);110111while (1) {112/* Wait for a read order of trace data by Host OS */113if (!global_run_operation) {114pthread_mutex_lock(&mutex_notify);115pthread_cond_wait(&cond_wakeup, &mutex_notify);116pthread_mutex_unlock(&mutex_notify);117}118119if (global_sig_receive)120break;121122/*123* Each thread read trace_pipe_raw of each cpu bounding the124* thread, so contention of multi-threads does not occur.125*/126rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL,127ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE);128129if (rlen < 0) {130pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num);131goto error;132} else if (rlen == 0) {133/*134* If trace data do not exist or are unreadable not135* for exceeding the page size, splice_read returns136* NULL. Then, this waits for being filled the data in a137* ring-buffer.138*/139usleep(READ_WAIT_USEC);140pr_debug("Read retry(cpu:%d)\n", ts->cpu_num);141continue;142}143144wlen = 0;145146do {147ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL,148rlen - wlen,149SPLICE_F_MOVE | SPLICE_F_MORE);150151if (ret < 0) {152pr_err("Splice_write in rw-thread(%d)\n",153ts->cpu_num);154goto error;155} else if (ret == 0)156/*157* When host reader is not in time for reading158* trace data, guest will be stopped. This is159* because char dev in QEMU is not supported160* non-blocking mode. Then, writer might be161* sleep in that case.162* This sleep will be removed by supporting163* non-blocking mode.164*/165sleep(1);166wlen += ret;167} while (wlen < rlen);168}169170return NULL;171172error:173exit(EXIT_FAILURE);174}175176177pthread_t rw_thread_run(struct rw_thread_info *rw_ti)178{179int ret;180pthread_t rw_thread_per_cpu;181182ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti);183if (ret != 0) {184pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num);185exit(EXIT_FAILURE);186}187188return rw_thread_per_cpu;189}190191192