diff options
author | Jiri Olsa <jolsa@kernel.org> | 2021-02-08 21:08:48 +0100 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2021-02-09 16:23:10 -0300 |
commit | ed36b7042fc8c0fb0de473139150c8e845c366cb (patch) | |
tree | 0d513f3a44e8765f9742b202caf74c3c79dc5ebe /tools/perf/builtin-daemon.c | |
parent | 5631d100f98390f82383eb271b9f503400514b44 (diff) |
perf daemon: Add server socket support
Add support to create a server socket that listens for client commands
and processes them.
This patch adds only the core support, all commands using this
functionality are coming in the following patches.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Budankov <abudankov@huawei.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: https://lore.kernel.org/r/20210208200908.1019149-5-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-daemon.c')
-rw-r--r-- | tools/perf/builtin-daemon.c | 117 |
1 files changed, 116 insertions, 1 deletions
diff --git a/tools/perf/builtin-daemon.c b/tools/perf/builtin-daemon.c index ce0373f453d6..495e4ff120ed 100644 --- a/tools/perf/builtin-daemon.c +++ b/tools/perf/builtin-daemon.c @@ -1,12 +1,19 @@ // SPDX-License-Identifier: GPL-2.0 +#include <internal/lib.h> #include <subcmd/parse-options.h> +#include <api/fd/array.h> #include <linux/limits.h> +#include <linux/string.h> #include <string.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <poll.h> #include "builtin.h" #include "perf.h" #include "debug.h" @@ -37,6 +44,92 @@ static void sig_handler(int sig __maybe_unused) done = true; } +static int setup_server_socket(struct daemon *daemon) +{ + struct sockaddr_un addr; + char path[PATH_MAX]; + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + + if (fd < 0) { + fprintf(stderr, "socket: %s\n", strerror(errno)); + return -1; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + perror("failed: fcntl FD_CLOEXEC"); + close(fd); + return -1; + } + + scnprintf(path, sizeof(path), "%s/control", daemon->base); + + if (strlen(path) + 1 >= sizeof(addr.sun_path)) { + pr_err("failed: control path too long '%s'\n", path); + close(fd); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + + strlcpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + unlink(path); + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("failed: bind"); + close(fd); + return -1; + } + + if (listen(fd, 1) == -1) { + perror("failed: listen"); + close(fd); + return -1; + } + + return fd; +} + +union cmd { + int cmd; +}; + +static int handle_server_socket(struct daemon *daemon __maybe_unused, int sock_fd) +{ + int ret = -1, fd; + FILE *out = NULL; + union cmd cmd; + + fd = accept(sock_fd, NULL, NULL); + if (fd < 0) { + perror("failed: accept"); + return -1; + } + + if (sizeof(cmd) != readn(fd, &cmd, sizeof(cmd))) { + perror("failed: read"); + goto out; + } + + out = fdopen(fd, "w"); + if (!out) { + perror("failed: fdopen"); + goto out; + } + + switch (cmd.cmd) { + default: + break; + } + + fclose(out); +out: + /* If out is defined, then fd is closed via fclose. */ + if (!out) + close(fd); + return ret; +} + static void daemon__exit(struct daemon *daemon) { free(daemon->config_real); @@ -77,6 +170,9 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[], OPT_PARENT(parent_options), OPT_END() }; + int sock_fd = -1; + int sock_pos; + struct fdarray fda; int err = 0; argc = parse_options(argc, argv, start_options, daemon_usage, 0); @@ -93,15 +189,34 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[], pr_info("daemon started (pid %d)\n", getpid()); + fdarray__init(&fda, 1); + + sock_fd = setup_server_socket(daemon); + if (sock_fd < 0) + goto out; + + sock_pos = fdarray__add(&fda, sock_fd, POLLIN|POLLERR|POLLHUP, 0); + if (sock_pos < 0) + goto out; + signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); while (!done && !err) { - sleep(1); + if (fdarray__poll(&fda, -1)) { + if (fda.entries[sock_pos].revents & POLLIN) + err = handle_server_socket(daemon, sock_fd); + } } +out: + fdarray__exit(&fda); + daemon__exit(daemon); + if (sock_fd != -1) + close(sock_fd); + pr_info("daemon exited\n"); fclose(daemon->out); return err; |