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 | |