diff options
Diffstat (limited to 'tools/virtio/virtio-trace/trace-agent-ctl.c')
| -rw-r--r-- | tools/virtio/virtio-trace/trace-agent-ctl.c | 137 | 
1 files changed, 137 insertions, 0 deletions
diff --git a/tools/virtio/virtio-trace/trace-agent-ctl.c b/tools/virtio/virtio-trace/trace-agent-ctl.c new file mode 100644 index 00000000000..a2d0403c4f9 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent-ctl.c @@ -0,0 +1,137 @@ +/* + * Controller of read/write threads for virtio-trace + * + * Copyright (C) 2012 Hitachi, Ltd. + * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> + *            Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> + * + * Licensed under GPL version 2 only. + * + */ + +#define _GNU_SOURCE +#include <fcntl.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "trace-agent.h" + +#define HOST_MSG_SIZE		256 +#define EVENT_WAIT_MSEC		100 + +static volatile sig_atomic_t global_signal_val; +bool global_sig_receive;	/* default false */ +bool global_run_operation;	/* default false*/ + +/* Handle SIGTERM/SIGINT/SIGQUIT to exit */ +static void signal_handler(int sig) +{ +	global_signal_val = sig; +} + +int rw_ctl_init(const char *ctl_path) +{ +	int ctl_fd; + +	ctl_fd = open(ctl_path, O_RDONLY); +	if (ctl_fd == -1) { +		pr_err("Cannot open ctl_fd\n"); +		goto error; +	} + +	return ctl_fd; + +error: +	exit(EXIT_FAILURE); +} + +static int wait_order(int ctl_fd) +{ +	struct pollfd poll_fd; +	int ret = 0; + +	while (!global_sig_receive) { +		poll_fd.fd = ctl_fd; +		poll_fd.events = POLLIN; + +		ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC); + +		if (global_signal_val) { +			global_sig_receive = true; +			pr_info("Receive interrupt %d\n", global_signal_val); + +			/* Wakes rw-threads when they are sleeping */ +			if (!global_run_operation) +				pthread_cond_broadcast(&cond_wakeup); + +			ret = -1; +			break; +		} + +		if (ret < 0) { +			pr_err("Polling error\n"); +			goto error; +		} + +		if (ret) +			break; +	}; + +	return ret; + +error: +	exit(EXIT_FAILURE); +} + +/* + * contol read/write threads by handling global_run_operation + */ +void *rw_ctl_loop(int ctl_fd) +{ +	ssize_t rlen; +	char buf[HOST_MSG_SIZE]; +	int ret; + +	/* Setup signal handlers */ +	signal(SIGTERM, signal_handler); +	signal(SIGINT, signal_handler); +	signal(SIGQUIT, signal_handler); + +	while (!global_sig_receive) { + +		ret = wait_order(ctl_fd); +		if (ret < 0) +			break; + +		rlen = read(ctl_fd, buf, sizeof(buf)); +		if (rlen < 0) { +			pr_err("read data error in ctl thread\n"); +			goto error; +		} + +		if (rlen == 2 && buf[0] == '1') { +			/* +			 * If host writes '1' to a control path, +			 * this controller wakes all read/write threads. +			 */ +			global_run_operation = true; +			pthread_cond_broadcast(&cond_wakeup); +			pr_debug("Wake up all read/write threads\n"); +		} else if (rlen == 2 && buf[0] == '0') { +			/* +			 * If host writes '0' to a control path, read/write +			 * threads will wait for notification from Host. +			 */ +			global_run_operation = false; +			pr_debug("Stop all read/write threads\n"); +		} else +			pr_info("Invalid host notification: %s\n", buf); +	} + +	return NULL; + +error: +	exit(EXIT_FAILURE); +}  | 
