brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · ddfe787 Raw
191 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Read/write thread of a guest agent for virtio-trace4 *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_SOURCE11#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	10000019 20void *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 40void *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	} else64		/* 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 87error:88	exit(EXIT_FAILURE);89}90 91/* Bind a thread to a cpu */92static 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 104static 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 the125		 * 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 not136			 * for exceeding the page size, splice_read returns137			 * NULL. Then, this waits for being filled the data in a138			 * 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 reading159				 * trace data, guest will be stopped. This is160				 * because char dev in QEMU is not supported161				 * non-blocking mode. Then, writer might be162				 * sleep in that case.163				 * This sleep will be removed by supporting164				 * non-blocking mode.165				 */166				sleep(1);167			wlen += ret;168		} while (wlen < rlen);169	}170 171	return NULL;172 173error:174	exit(EXIT_FAILURE);175}176 177 178pthread_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