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