|  | /* | 
|  | * 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); | 
|  | } |