1/* 2 * Controller of read/write threads for virtio-trace 3 * 4 * Copyright (C) 2012 Hitachi, Ltd. 5 * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> 6 * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> 7 * 8 * Licensed under GPL version 2 only. 9 * 10 */ 11 12#define _GNU_SOURCE 13#include <fcntl.h> 14#include <poll.h> 15#include <signal.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <unistd.h> 19#include "trace-agent.h" 20 21#define HOST_MSG_SIZE 256 22#define EVENT_WAIT_MSEC 100 23 24static volatile sig_atomic_t global_signal_val; 25bool global_sig_receive; /* default false */ 26bool global_run_operation; /* default false*/ 27 28/* Handle SIGTERM/SIGINT/SIGQUIT to exit */ 29static void signal_handler(int sig) 30{ 31 global_signal_val = sig; 32} 33 34int rw_ctl_init(const char *ctl_path) 35{ 36 int ctl_fd; 37 38 ctl_fd = open(ctl_path, O_RDONLY); 39 if (ctl_fd == -1) { 40 pr_err("Cannot open ctl_fd\n"); 41 goto error; 42 } 43 44 return ctl_fd; 45 46error: 47 exit(EXIT_FAILURE); 48} 49 50static int wait_order(int ctl_fd) 51{ 52 struct pollfd poll_fd; 53 int ret = 0; 54 55 while (!global_sig_receive) { 56 poll_fd.fd = ctl_fd; 57 poll_fd.events = POLLIN; 58 59 ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC); 60 61 if (global_signal_val) { 62 global_sig_receive = true; 63 pr_info("Receive interrupt %d\n", global_signal_val); 64 65 /* Wakes rw-threads when they are sleeping */ 66 if (!global_run_operation) 67 pthread_cond_broadcast(&cond_wakeup); 68 69 ret = -1; 70 break; 71 } 72 73 if (ret < 0) { 74 pr_err("Polling error\n"); 75 goto error; 76 } 77 78 if (ret) 79 break; 80 }; 81 82 return ret; 83 84error: 85 exit(EXIT_FAILURE); 86} 87 88/* 89 * contol read/write threads by handling global_run_operation 90 */ 91void *rw_ctl_loop(int ctl_fd) 92{ 93 ssize_t rlen; 94 char buf[HOST_MSG_SIZE]; 95 int ret; 96 97 /* Setup signal handlers */ 98 signal(SIGTERM, signal_handler); 99 signal(SIGINT, signal_handler); 100 signal(SIGQUIT, signal_handler); 101 102 while (!global_sig_receive) { 103 104 ret = wait_order(ctl_fd); 105 if (ret < 0) 106 break; 107 108 rlen = read(ctl_fd, buf, sizeof(buf)); 109 if (rlen < 0) { 110 pr_err("read data error in ctl thread\n"); 111 goto error; 112 } 113 114 if (rlen == 2 && buf[0] == '1') { 115 /* 116 * If host writes '1' to a control path, 117 * this controller wakes all read/write threads. 118 */ 119 global_run_operation = true; 120 pthread_cond_broadcast(&cond_wakeup); 121 pr_debug("Wake up all read/write threads\n"); 122 } else if (rlen == 2 && buf[0] == '0') { 123 /* 124 * If host writes '0' to a control path, read/write 125 * threads will wait for notification from Host. 126 */ 127 global_run_operation = false; 128 pr_debug("Stop all read/write threads\n"); 129 } else 130 pr_info("Invalid host notification: %s\n", buf); 131 } 132 133 return NULL; 134 135error: 136 exit(EXIT_FAILURE); 137} 138