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 24 static volatile sig_atomic_t global_signal_val; 25 bool global_sig_receive; /* default false */ 26 bool global_run_operation; /* default false*/ 27 28 /* Handle SIGTERM/SIGINT/SIGQUIT to exit */ 29 static void signal_handler(int sig) 30 { 31 global_signal_val = sig; 32 } 33 34 int 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 46 error: 47 exit(EXIT_FAILURE); 48 } 49 50 static 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 84 error: 85 exit(EXIT_FAILURE); 86 } 87 88 /* 89 * contol read/write threads by handling global_run_operation 90 */ 91 void *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 135 error: 136 exit(EXIT_FAILURE); 137 } 138