Commit ec886bf5 authored by Alexey Budankov's avatar Alexey Budankov Committed by Arnaldo Carvalho de Melo

perf evlist: Implement control command handling functions

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: default avatarAlexey Budankov <alexey.budankov@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@redhat.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/62518ceb-1cc9-2aba-593b-55408d07c1bf@linux.intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 8ab705b5
......@@ -1726,3 +1726,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;
}
......@@ -360,4 +360,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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment