xref: /openbmc/linux/tools/virtio/virtio-trace/trace-agent-ctl.c (revision ea68a3e9d14e9e0bf017d178fb4bd53b6deb1482)
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 */
signal_handler(int sig)27  static void signal_handler(int sig)
28  {
29  	global_signal_val = sig;
30  }
31  
rw_ctl_init(const char * ctl_path)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  
wait_order(int ctl_fd)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   */
rw_ctl_loop(int ctl_fd)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