18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Controller of read/write threads for virtio-trace
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Hitachi, Ltd.
68c2ecf20Sopenharmony_ci * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
78c2ecf20Sopenharmony_ci *            Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define _GNU_SOURCE
118c2ecf20Sopenharmony_ci#include <fcntl.h>
128c2ecf20Sopenharmony_ci#include <poll.h>
138c2ecf20Sopenharmony_ci#include <signal.h>
148c2ecf20Sopenharmony_ci#include <stdio.h>
158c2ecf20Sopenharmony_ci#include <stdlib.h>
168c2ecf20Sopenharmony_ci#include <unistd.h>
178c2ecf20Sopenharmony_ci#include "trace-agent.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define HOST_MSG_SIZE		256
208c2ecf20Sopenharmony_ci#define EVENT_WAIT_MSEC		100
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic volatile sig_atomic_t global_signal_val;
238c2ecf20Sopenharmony_cibool global_sig_receive;	/* default false */
248c2ecf20Sopenharmony_cibool global_run_operation;	/* default false*/
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Handle SIGTERM/SIGINT/SIGQUIT to exit */
278c2ecf20Sopenharmony_cistatic void signal_handler(int sig)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	global_signal_val = sig;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciint rw_ctl_init(const char *ctl_path)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	int ctl_fd;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	ctl_fd = open(ctl_path, O_RDONLY);
378c2ecf20Sopenharmony_ci	if (ctl_fd == -1) {
388c2ecf20Sopenharmony_ci		pr_err("Cannot open ctl_fd\n");
398c2ecf20Sopenharmony_ci		goto error;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return ctl_fd;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cierror:
458c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int wait_order(int ctl_fd)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct pollfd poll_fd;
518c2ecf20Sopenharmony_ci	int ret = 0;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	while (!global_sig_receive) {
548c2ecf20Sopenharmony_ci		poll_fd.fd = ctl_fd;
558c2ecf20Sopenharmony_ci		poll_fd.events = POLLIN;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		if (global_signal_val) {
608c2ecf20Sopenharmony_ci			global_sig_receive = true;
618c2ecf20Sopenharmony_ci			pr_info("Receive interrupt %d\n", global_signal_val);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci			/* Wakes rw-threads when they are sleeping */
648c2ecf20Sopenharmony_ci			if (!global_run_operation)
658c2ecf20Sopenharmony_ci				pthread_cond_broadcast(&cond_wakeup);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci			ret = -1;
688c2ecf20Sopenharmony_ci			break;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		if (ret < 0) {
728c2ecf20Sopenharmony_ci			pr_err("Polling error\n");
738c2ecf20Sopenharmony_ci			goto error;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		if (ret)
778c2ecf20Sopenharmony_ci			break;
788c2ecf20Sopenharmony_ci	};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return ret;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cierror:
838c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/*
878c2ecf20Sopenharmony_ci * contol read/write threads by handling global_run_operation
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_civoid *rw_ctl_loop(int ctl_fd)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	ssize_t rlen;
928c2ecf20Sopenharmony_ci	char buf[HOST_MSG_SIZE];
938c2ecf20Sopenharmony_ci	int ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* Setup signal handlers */
968c2ecf20Sopenharmony_ci	signal(SIGTERM, signal_handler);
978c2ecf20Sopenharmony_ci	signal(SIGINT, signal_handler);
988c2ecf20Sopenharmony_ci	signal(SIGQUIT, signal_handler);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	while (!global_sig_receive) {
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		ret = wait_order(ctl_fd);
1038c2ecf20Sopenharmony_ci		if (ret < 0)
1048c2ecf20Sopenharmony_ci			break;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		rlen = read(ctl_fd, buf, sizeof(buf));
1078c2ecf20Sopenharmony_ci		if (rlen < 0) {
1088c2ecf20Sopenharmony_ci			pr_err("read data error in ctl thread\n");
1098c2ecf20Sopenharmony_ci			goto error;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		if (rlen == 2 && buf[0] == '1') {
1138c2ecf20Sopenharmony_ci			/*
1148c2ecf20Sopenharmony_ci			 * If host writes '1' to a control path,
1158c2ecf20Sopenharmony_ci			 * this controller wakes all read/write threads.
1168c2ecf20Sopenharmony_ci			 */
1178c2ecf20Sopenharmony_ci			global_run_operation = true;
1188c2ecf20Sopenharmony_ci			pthread_cond_broadcast(&cond_wakeup);
1198c2ecf20Sopenharmony_ci			pr_debug("Wake up all read/write threads\n");
1208c2ecf20Sopenharmony_ci		} else if (rlen == 2 && buf[0] == '0') {
1218c2ecf20Sopenharmony_ci			/*
1228c2ecf20Sopenharmony_ci			 * If host writes '0' to a control path, read/write
1238c2ecf20Sopenharmony_ci			 * threads will wait for notification from Host.
1248c2ecf20Sopenharmony_ci			 */
1258c2ecf20Sopenharmony_ci			global_run_operation = false;
1268c2ecf20Sopenharmony_ci			pr_debug("Stop all read/write threads\n");
1278c2ecf20Sopenharmony_ci		} else
1288c2ecf20Sopenharmony_ci			pr_info("Invalid host notification: %s\n", buf);
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return NULL;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cierror:
1348c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
1358c2ecf20Sopenharmony_ci}
136