diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/evlist.c | 55 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 2 | ||||
-rw-r--r-- | tools/perf/util/record.h | 1 | ||||
-rw-r--r-- | tools/perf/util/stat.h | 1 |
4 files changed, 56 insertions, 3 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 47d1045a19af..00593e5f2a9d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1727,12 +1727,63 @@ struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, return leader; } -int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack) +static int evlist__parse_control_fifo(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close) +{ + char *s, *p; + int ret = 0, fd; + + if (strncmp(str, "fifo:", 5)) + return -EINVAL; + + str += 5; + if (!*str || *str == ',') + return -EINVAL; + + s = strdup(str); + if (!s) + return -ENOMEM; + + p = strchr(s, ','); + if (p) + *p = '\0'; + + /* + * O_RDWR avoids POLLHUPs which is necessary to allow the other + * end of a FIFO to be repeatedly opened and closed. + */ + fd = open(s, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + pr_err("Failed to open '%s'\n", s); + ret = -errno; + goto out_free; + } + *ctl_fd = fd; + *ctl_fd_close = true; + + if (p && *++p) { + /* O_RDWR | O_NONBLOCK means the other end need not be open */ + fd = open(p, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + pr_err("Failed to open '%s'\n", p); + ret = -errno; + goto out_free; + } + *ctl_fd_ack = fd; + } + +out_free: + free(s); + return ret; +} + +int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close) { char *comma = NULL, *endptr = NULL; + *ctl_fd_close = false; + if (strncmp(str, "fd:", 3)) - return -EINVAL; + return evlist__parse_control_fifo(str, ctl_fd, ctl_fd_ack, ctl_fd_close); *ctl_fd = strtoul(&str[3], &endptr, 0); if (endptr == &str[3]) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a5a5a07d5c55..a5678eb5ee60 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -373,7 +373,7 @@ enum evlist_ctl_cmd { EVLIST_CTL_CMD_ACK }; -int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack); +int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close); 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); diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h index 03678ff25539..266760ac9143 100644 --- a/tools/perf/util/record.h +++ b/tools/perf/util/record.h @@ -73,6 +73,7 @@ struct record_opts { unsigned int nr_threads_synthesize; int ctl_fd; int ctl_fd_ack; + bool ctl_fd_close; }; extern const char * const *record_usage; diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index aa3bed48511b..9911fc6adbfd 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -136,6 +136,7 @@ struct perf_stat_config { struct rblist metric_events; int ctl_fd; int ctl_fd_ack; + bool ctl_fd_close; }; void perf_stat__set_big_num(int set); |