]> Pileus Git - ~andy/linux/blobdiff - tools/virtio/virtio-trace/trace-agent-ctl.c
tools: Add guest trace agent as a user tool
[~andy/linux] / tools / virtio / virtio-trace / trace-agent-ctl.c
diff --git a/tools/virtio/virtio-trace/trace-agent-ctl.c b/tools/virtio/virtio-trace/trace-agent-ctl.c
new file mode 100644 (file)
index 0000000..a2d0403
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Controller of read/write threads for virtio-trace
+ *
+ * Copyright (C) 2012 Hitachi, Ltd.
+ * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
+ *            Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "trace-agent.h"
+
+#define HOST_MSG_SIZE          256
+#define EVENT_WAIT_MSEC                100
+
+static volatile sig_atomic_t global_signal_val;
+bool global_sig_receive;       /* default false */
+bool global_run_operation;     /* default false*/
+
+/* Handle SIGTERM/SIGINT/SIGQUIT to exit */
+static void signal_handler(int sig)
+{
+       global_signal_val = sig;
+}
+
+int rw_ctl_init(const char *ctl_path)
+{
+       int ctl_fd;
+
+       ctl_fd = open(ctl_path, O_RDONLY);
+       if (ctl_fd == -1) {
+               pr_err("Cannot open ctl_fd\n");
+               goto error;
+       }
+
+       return ctl_fd;
+
+error:
+       exit(EXIT_FAILURE);
+}
+
+static int wait_order(int ctl_fd)
+{
+       struct pollfd poll_fd;
+       int ret = 0;
+
+       while (!global_sig_receive) {
+               poll_fd.fd = ctl_fd;
+               poll_fd.events = POLLIN;
+
+               ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC);
+
+               if (global_signal_val) {
+                       global_sig_receive = true;
+                       pr_info("Receive interrupt %d\n", global_signal_val);
+
+                       /* Wakes rw-threads when they are sleeping */
+                       if (!global_run_operation)
+                               pthread_cond_broadcast(&cond_wakeup);
+
+                       ret = -1;
+                       break;
+               }
+
+               if (ret < 0) {
+                       pr_err("Polling error\n");
+                       goto error;
+               }
+
+               if (ret)
+                       break;
+       };
+
+       return ret;
+
+error:
+       exit(EXIT_FAILURE);
+}
+
+/*
+ * contol read/write threads by handling global_run_operation
+ */
+void *rw_ctl_loop(int ctl_fd)
+{
+       ssize_t rlen;
+       char buf[HOST_MSG_SIZE];
+       int ret;
+
+       /* Setup signal handlers */
+       signal(SIGTERM, signal_handler);
+       signal(SIGINT, signal_handler);
+       signal(SIGQUIT, signal_handler);
+
+       while (!global_sig_receive) {
+
+               ret = wait_order(ctl_fd);
+               if (ret < 0)
+                       break;
+
+               rlen = read(ctl_fd, buf, sizeof(buf));
+               if (rlen < 0) {
+                       pr_err("read data error in ctl thread\n");
+                       goto error;
+               }
+
+               if (rlen == 2 && buf[0] == '1') {
+                       /*
+                        * If host writes '1' to a control path,
+                        * this controller wakes all read/write threads.
+                        */
+                       global_run_operation = true;
+                       pthread_cond_broadcast(&cond_wakeup);
+                       pr_debug("Wake up all read/write threads\n");
+               } else if (rlen == 2 && buf[0] == '0') {
+                       /*
+                        * If host writes '0' to a control path, read/write
+                        * threads will wait for notification from Host.
+                        */
+                       global_run_operation = false;
+                       pr_debug("Stop all read/write threads\n");
+               } else
+                       pr_info("Invalid host notification: %s\n", buf);
+       }
+
+       return NULL;
+
+error:
+       exit(EXIT_FAILURE);
+}