Implement functions of initialization, finalization and processing
of control command messages coming from control file descriptors.
Allocate control file descriptor as descriptor at struct pollfd
object of evsel_list for atomic poll() operation.

Signed-off-by: Alexey Budankov <alexey.budan...@linux.intel.com>
---
 tools/perf/util/evlist.c | 140 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  18 +++++
 2 files changed, 158 insertions(+)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 36eb50aba1f5..fe900d82815c 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1714,3 +1714,143 @@ struct evsel *perf_evlist__reset_weak_group(struct 
evlist *evsel_list,
        }
        return leader;
 }
+
+int evlist__initialize_ctlfd(struct evlist *evlist, int fd, int ack)
+{
+       if (fd == -1) {
+               pr_debug("Control descriptor is not initialized\n");
+               return 0;
+       }
+
+       evlist->ctl_fd.pos = perf_evlist__add_pollfd(&evlist->core, fd, NULL, 
POLLIN,
+                                                    
fdarray_flag__nonfilterable);
+       if (evlist->ctl_fd.pos < 0) {
+               evlist->ctl_fd.pos = -1;
+               pr_err("Failed to add ctl fd entry: %m\n");
+               return -1;
+       }
+
+       evlist->ctl_fd.fd = fd;
+       evlist->ctl_fd.ack = ack;
+
+       return 0;
+}
+
+bool evlist__ctlfd_initialized(struct evlist *evlist)
+{
+       return evlist->ctl_fd.pos >= 0;
+}
+
+int evlist__finalize_ctlfd(struct evlist *evlist)
+{
+       struct pollfd *entries = evlist->core.pollfd.entries;
+
+       if (!evlist__ctlfd_initialized(evlist))
+               return 0;
+
+       entries[evlist->ctl_fd.pos].fd = -1;
+       entries[evlist->ctl_fd.pos].events = 0;
+       entries[evlist->ctl_fd.pos].revents = 0;
+
+       evlist->ctl_fd.pos = -1;
+       evlist->ctl_fd.ack = -1;
+       evlist->ctl_fd.fd = -1;
+
+       return 0;
+}
+
+static int evlist__ctlfd_recv(struct evlist *evlist, enum evlist_ctl_cmd *cmd,
+                             char *cmd_data, size_t data_size)
+{
+       int err;
+       char c;
+       size_t bytes_read = 0;
+
+       memset(cmd_data, 0, data_size);
+       data_size--;
+
+       do {
+               err = read(evlist->ctl_fd.fd, &c, 1);
+               if (err > 0) {
+                       if (c == '\n' || c == '\0')
+                               break;
+                       cmd_data[bytes_read++] = c;
+                       if (bytes_read == data_size)
+                               break;
+               } else {
+                       if (err == -1)
+                               pr_err("Failed to read from ctlfd %d: %m\n", 
evlist->ctl_fd.fd);
+                       break;
+               }
+       } while (1);
+
+       pr_debug("Message from ctl_fd: \"%s%s\"\n", cmd_data,
+                bytes_read == data_size ? "" : c == '\n' ? "\\n" : "\\0");
+
+       if (err > 0) {
+               if (!strncmp(cmd_data, EVLIST_CTL_CMD_ENABLE_TAG,
+                            (sizeof(EVLIST_CTL_CMD_ENABLE_TAG)-1))) {
+                       *cmd = EVLIST_CTL_CMD_ENABLE;
+               } else if (!strncmp(cmd_data, EVLIST_CTL_CMD_DISABLE_TAG,
+                                   (sizeof(EVLIST_CTL_CMD_DISABLE_TAG)-1))) {
+                       *cmd = EVLIST_CTL_CMD_DISABLE;
+               }
+       }
+
+       return err;
+}
+
+static int evlist__ctlfd_ack(struct evlist *evlist)
+{
+       int err;
+
+       if (evlist->ctl_fd.ack == -1)
+               return 0;
+
+       err = write(evlist->ctl_fd.ack, EVLIST_CTL_CMD_ACK_TAG,
+                   sizeof(EVLIST_CTL_CMD_ACK_TAG));
+       if (err == -1)
+               pr_err("failed to write to ctl_ack_fd %d: %m\n", 
evlist->ctl_fd.ack);
+
+       return err;
+}
+
+int evlist__ctlfd_process(struct evlist *evlist, enum evlist_ctl_cmd *cmd)
+{
+       int err = 0;
+       char cmd_data[EVLIST_CTL_CMD_MAX_LEN];
+       int ctlfd_pos = evlist->ctl_fd.pos;
+       struct pollfd *entries = evlist->core.pollfd.entries;
+
+       if (!evlist__ctlfd_initialized(evlist) || !entries[ctlfd_pos].revents)
+               return 0;
+
+       if (entries[ctlfd_pos].revents & POLLIN) {
+               err = evlist__ctlfd_recv(evlist, cmd, cmd_data,
+                                        EVLIST_CTL_CMD_MAX_LEN);
+               if (err > 0) {
+                       switch (*cmd) {
+                       case EVLIST_CTL_CMD_ENABLE:
+                               evlist__enable(evlist);
+                               break;
+                       case EVLIST_CTL_CMD_DISABLE:
+                               evlist__disable(evlist);
+                               break;
+                       case EVLIST_CTL_CMD_ACK:
+                       case EVLIST_CTL_CMD_UNSUPPORTED:
+                       default:
+                               pr_debug("ctlfd: unsupported %d\n", *cmd);
+                               break;
+                       }
+                       if (!(*cmd == EVLIST_CTL_CMD_ACK || *cmd == 
EVLIST_CTL_CMD_UNSUPPORTED))
+                               evlist__ctlfd_ack(evlist);
+               }
+       }
+
+       if (entries[ctlfd_pos].revents & (POLLHUP | POLLERR))
+               evlist__finalize_ctlfd(evlist);
+       else
+               entries[ctlfd_pos].revents = 0;
+
+       return err;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index fe1fe40e044b..cc628798734d 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -359,4 +359,22 @@ void perf_evlist__force_leader(struct evlist *evlist);
 struct evsel *perf_evlist__reset_weak_group(struct evlist *evlist,
                                                 struct evsel *evsel,
                                                bool close);
+#define EVLIST_CTL_CMD_ENABLE_TAG  "enable"
+#define EVLIST_CTL_CMD_DISABLE_TAG "disable"
+#define EVLIST_CTL_CMD_ACK_TAG     "ack\n"
+
+#define EVLIST_CTL_CMD_MAX_LEN 64
+
+enum evlist_ctl_cmd {
+       EVLIST_CTL_CMD_UNSUPPORTED = 0,
+       EVLIST_CTL_CMD_ENABLE,
+       EVLIST_CTL_CMD_DISABLE,
+       EVLIST_CTL_CMD_ACK
+};
+
+int evlist__initialize_ctlfd(struct evlist *evlist, int ctl_fd, int 
ctl_fd_ack);
+int evlist__finalize_ctlfd(struct evlist *evlist);
+bool evlist__ctlfd_initialized(struct evlist *evlist);
+int evlist__ctlfd_process(struct evlist *evlist, enum evlist_ctl_cmd *cmd);
+
 #endif /* __PERF_EVLIST_H */
-- 
2.24.1


Reply via email to