From: Simon Marchi Date: Fri, 3 Sep 2021 21:31:29 +0000 (-0400) Subject: bin: compile lttng-consumerd as a C++ X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=657d1bf105996bf8f6e13af697fb1112afa61b28;p=lttng-tools.git bin: compile lttng-consumerd as a C++ Same as the previous commits, but change lttng-consumerd to be a C++ program. Function lttng_consumer_get_type is dlsym-ed by tests/regression/tools/notification/consumer_testpoints.c, so we have two choices: make the dlsym use the mangled name or make the function have a C linkage name. The latter is better, because the mangled name is implementation-defined, and therefore more fragile. Change-Id: I1986e38c193a935721e52c89426c89fd434ccd6b Signed-off-by: Simon Marchi Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-consumerd/Makefile.am b/src/bin/lttng-consumerd/Makefile.am index 112e360d0..37fc6d524 100644 --- a/src/bin/lttng-consumerd/Makefile.am +++ b/src/bin/lttng-consumerd/Makefile.am @@ -2,10 +2,11 @@ lttnglibexec_PROGRAMS = lttng-consumerd -lttng_consumerd_SOURCES = lttng-consumerd.c \ +lttng_consumerd_SOURCES = \ + lttng-consumerd.cpp \ lttng-consumerd.h \ - health-consumerd.h \ - health-consumerd.c + health-consumerd.cpp \ + health-consumerd.h lttng_consumerd_LDADD = \ $(top_builddir)/src/common/consumer/libconsumer.la \ diff --git a/src/bin/lttng-consumerd/health-consumerd.c b/src/bin/lttng-consumerd/health-consumerd.c deleted file mode 100644 index 90b4b1e12..000000000 --- a/src/bin/lttng-consumerd/health-consumerd.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2013 Mathieu Desnoyers - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -#define _LGPL_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "lttng-consumerd.h" -#include "health-consumerd.h" - -/* Global health check unix path */ -static char health_unix_sock_path[PATH_MAX]; - -int health_quit_pipe[2]; - -/* - * Check if the thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -static -int check_health_quit_pipe(int fd, uint32_t events) -{ - if (fd == health_quit_pipe[0] && (events & LPOLLIN)) { - return 1; - } - - return 0; -} - -/* - * Send data on a unix socket using the liblttsessiondcomm API. - * - * Return lttcomm error code. - */ -static int send_unix_sock(int sock, void *buf, size_t len) -{ - /* Check valid length */ - if (len == 0) { - return -1; - } - - return lttcomm_send_unix_sock(sock, buf, len); -} - -static -int setup_health_path(void) -{ - int is_root, ret = 0; - enum lttng_consumer_type type; - const char *home_path; - - type = lttng_consumer_get_type(); - is_root = !getuid(); - - if (is_root) { - if (strlen(health_unix_sock_path) != 0) { - goto end; - } - switch (type) { - case LTTNG_CONSUMER_KERNEL: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_GLOBAL_KCONSUMER_HEALTH_UNIX_SOCK); - break; - case LTTNG_CONSUMER64_UST: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_GLOBAL_USTCONSUMER64_HEALTH_UNIX_SOCK); - break; - case LTTNG_CONSUMER32_UST: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK); - break; - default: - ret = -EINVAL; - goto end; - } - } else { - home_path = utils_get_home_dir(); - if (home_path == NULL) { - /* TODO: Add --socket PATH option */ - ERR("Can't get HOME directory for sockets creation."); - ret = -EPERM; - goto end; - } - - /* Set health check Unix path */ - if (strlen(health_unix_sock_path) != 0) { - goto end; - } - switch (type) { - case LTTNG_CONSUMER_KERNEL: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_HOME_KCONSUMER_HEALTH_UNIX_SOCK, home_path); - break; - case LTTNG_CONSUMER64_UST: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_HOME_USTCONSUMER64_HEALTH_UNIX_SOCK, home_path); - break; - case LTTNG_CONSUMER32_UST: - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_HOME_USTCONSUMER32_HEALTH_UNIX_SOCK, home_path); - break; - default: - ret = -EINVAL; - goto end; - } - } -end: - return ret; -} - -/* - * Thread managing health check socket. - */ -void *thread_manage_health(void *data) -{ - int sock = -1, new_sock = -1, ret, i, pollfd, err = -1; - uint32_t revents, nb_fd; - struct lttng_poll_event events; - struct health_comm_msg msg; - struct health_comm_reply reply; - int is_root; - - DBG("[thread] Manage health check started"); - - setup_health_path(); - - rcu_register_thread(); - - /* We might hit an error path before this is created. */ - lttng_poll_init(&events); - - /* Create unix socket */ - sock = lttcomm_create_unix_sock(health_unix_sock_path); - if (sock < 0) { - ERR("Unable to create health check Unix socket"); - err = -1; - goto error; - } - - is_root = !getuid(); - if (is_root) { - /* lttng health client socket path permissions */ - gid_t gid; - - ret = utils_get_group_id(tracing_group_name, true, &gid); - if (ret) { - /* Default to root group. */ - gid = 0; - } - - ret = chown(health_unix_sock_path, 0, gid); - if (ret < 0) { - ERR("Unable to set group on %s", health_unix_sock_path); - PERROR("chown"); - err = -1; - goto error; - } - - ret = chmod(health_unix_sock_path, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (ret < 0) { - ERR("Unable to set permissions on %s", health_unix_sock_path); - PERROR("chmod"); - err = -1; - goto error; - } - } - - /* - * Set the CLOEXEC flag. Return code is useless because either way, the - * show must go on. - */ - (void) utils_set_fd_cloexec(sock); - - ret = lttcomm_listen_unix_sock(sock); - if (ret < 0) { - goto error; - } - - /* Size is set to 1 for the consumer_channel pipe */ - ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC); - if (ret < 0) { - ERR("Poll set creation failed"); - goto error; - } - - ret = lttng_poll_add(&events, health_quit_pipe[0], LPOLLIN); - if (ret < 0) { - goto error; - } - - /* Add the application registration socket */ - ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI); - if (ret < 0) { - goto error; - } - - /* Perform prior memory accesses before decrementing ready */ - cmm_smp_mb__before_uatomic_dec(); - uatomic_dec(<tng_consumer_ready); - - while (1) { - DBG("Health check ready"); - - /* Inifinite blocking call, waiting for transmission */ -restart: - ret = lttng_poll_wait(&events, -1); - if (ret < 0) { - /* - * Restart interrupted system call. - */ - if (errno == EINTR) { - goto restart; - } - goto error; - } - - nb_fd = ret; - - for (i = 0; i < nb_fd; i++) { - /* Fetch once the poll data */ - revents = LTTNG_POLL_GETEV(&events, i); - pollfd = LTTNG_POLL_GETFD(&events, i); - - /* Thread quit pipe has been closed. Killing thread. */ - ret = check_health_quit_pipe(pollfd, revents); - if (ret) { - err = 0; - goto exit; - } - - /* Event on the registration socket */ - if (pollfd == sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) - && !(revents & LPOLLIN)) { - ERR("Health socket poll error"); - goto error; - } - } - } - - new_sock = lttcomm_accept_unix_sock(sock); - if (new_sock < 0) { - goto error; - } - - /* - * Set the CLOEXEC flag. Return code is useless because either way, the - * show must go on. - */ - (void) utils_set_fd_cloexec(new_sock); - - DBG("Receiving data from client for health..."); - ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg)); - if (ret <= 0) { - DBG("Nothing recv() from client... continuing"); - ret = close(new_sock); - if (ret) { - PERROR("close"); - } - new_sock = -1; - continue; - } - - rcu_thread_online(); - - LTTNG_ASSERT(msg.cmd == HEALTH_CMD_CHECK); - - memset(&reply, 0, sizeof(reply)); - for (i = 0; i < NR_HEALTH_CONSUMERD_TYPES; i++) { - /* - * health_check_state return 0 if thread is in - * error. - */ - if (!health_check_state(health_consumerd, i)) { - reply.ret_code |= 1ULL << i; - } - } - - DBG("Health check return value %" PRIx64, reply.ret_code); - - ret = send_unix_sock(new_sock, (void *) &reply, sizeof(reply)); - if (ret < 0) { - ERR("Failed to send health data back to client"); - } - - /* End of transmission */ - ret = close(new_sock); - if (ret) { - PERROR("close"); - } - new_sock = -1; - } - -exit: -error: - if (err) { - ERR("Health error occurred in %s", __func__); - } - DBG("Health check thread dying"); - unlink(health_unix_sock_path); - if (sock >= 0) { - ret = close(sock); - if (ret) { - PERROR("close"); - } - } - - lttng_poll_clean(&events); - - rcu_unregister_thread(); - return NULL; -} diff --git a/src/bin/lttng-consumerd/health-consumerd.cpp b/src/bin/lttng-consumerd/health-consumerd.cpp new file mode 100644 index 000000000..90b4b1e12 --- /dev/null +++ b/src/bin/lttng-consumerd/health-consumerd.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2013 Mathieu Desnoyers + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "lttng-consumerd.h" +#include "health-consumerd.h" + +/* Global health check unix path */ +static char health_unix_sock_path[PATH_MAX]; + +int health_quit_pipe[2]; + +/* + * Check if the thread quit pipe was triggered. + * + * Return 1 if it was triggered else 0; + */ +static +int check_health_quit_pipe(int fd, uint32_t events) +{ + if (fd == health_quit_pipe[0] && (events & LPOLLIN)) { + return 1; + } + + return 0; +} + +/* + * Send data on a unix socket using the liblttsessiondcomm API. + * + * Return lttcomm error code. + */ +static int send_unix_sock(int sock, void *buf, size_t len) +{ + /* Check valid length */ + if (len == 0) { + return -1; + } + + return lttcomm_send_unix_sock(sock, buf, len); +} + +static +int setup_health_path(void) +{ + int is_root, ret = 0; + enum lttng_consumer_type type; + const char *home_path; + + type = lttng_consumer_get_type(); + is_root = !getuid(); + + if (is_root) { + if (strlen(health_unix_sock_path) != 0) { + goto end; + } + switch (type) { + case LTTNG_CONSUMER_KERNEL: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_GLOBAL_KCONSUMER_HEALTH_UNIX_SOCK); + break; + case LTTNG_CONSUMER64_UST: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_GLOBAL_USTCONSUMER64_HEALTH_UNIX_SOCK); + break; + case LTTNG_CONSUMER32_UST: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK); + break; + default: + ret = -EINVAL; + goto end; + } + } else { + home_path = utils_get_home_dir(); + if (home_path == NULL) { + /* TODO: Add --socket PATH option */ + ERR("Can't get HOME directory for sockets creation."); + ret = -EPERM; + goto end; + } + + /* Set health check Unix path */ + if (strlen(health_unix_sock_path) != 0) { + goto end; + } + switch (type) { + case LTTNG_CONSUMER_KERNEL: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_HOME_KCONSUMER_HEALTH_UNIX_SOCK, home_path); + break; + case LTTNG_CONSUMER64_UST: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_HOME_USTCONSUMER64_HEALTH_UNIX_SOCK, home_path); + break; + case LTTNG_CONSUMER32_UST: + snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + DEFAULT_HOME_USTCONSUMER32_HEALTH_UNIX_SOCK, home_path); + break; + default: + ret = -EINVAL; + goto end; + } + } +end: + return ret; +} + +/* + * Thread managing health check socket. + */ +void *thread_manage_health(void *data) +{ + int sock = -1, new_sock = -1, ret, i, pollfd, err = -1; + uint32_t revents, nb_fd; + struct lttng_poll_event events; + struct health_comm_msg msg; + struct health_comm_reply reply; + int is_root; + + DBG("[thread] Manage health check started"); + + setup_health_path(); + + rcu_register_thread(); + + /* We might hit an error path before this is created. */ + lttng_poll_init(&events); + + /* Create unix socket */ + sock = lttcomm_create_unix_sock(health_unix_sock_path); + if (sock < 0) { + ERR("Unable to create health check Unix socket"); + err = -1; + goto error; + } + + is_root = !getuid(); + if (is_root) { + /* lttng health client socket path permissions */ + gid_t gid; + + ret = utils_get_group_id(tracing_group_name, true, &gid); + if (ret) { + /* Default to root group. */ + gid = 0; + } + + ret = chown(health_unix_sock_path, 0, gid); + if (ret < 0) { + ERR("Unable to set group on %s", health_unix_sock_path); + PERROR("chown"); + err = -1; + goto error; + } + + ret = chmod(health_unix_sock_path, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (ret < 0) { + ERR("Unable to set permissions on %s", health_unix_sock_path); + PERROR("chmod"); + err = -1; + goto error; + } + } + + /* + * Set the CLOEXEC flag. Return code is useless because either way, the + * show must go on. + */ + (void) utils_set_fd_cloexec(sock); + + ret = lttcomm_listen_unix_sock(sock); + if (ret < 0) { + goto error; + } + + /* Size is set to 1 for the consumer_channel pipe */ + ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC); + if (ret < 0) { + ERR("Poll set creation failed"); + goto error; + } + + ret = lttng_poll_add(&events, health_quit_pipe[0], LPOLLIN); + if (ret < 0) { + goto error; + } + + /* Add the application registration socket */ + ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI); + if (ret < 0) { + goto error; + } + + /* Perform prior memory accesses before decrementing ready */ + cmm_smp_mb__before_uatomic_dec(); + uatomic_dec(<tng_consumer_ready); + + while (1) { + DBG("Health check ready"); + + /* Inifinite blocking call, waiting for transmission */ +restart: + ret = lttng_poll_wait(&events, -1); + if (ret < 0) { + /* + * Restart interrupted system call. + */ + if (errno == EINTR) { + goto restart; + } + goto error; + } + + nb_fd = ret; + + for (i = 0; i < nb_fd; i++) { + /* Fetch once the poll data */ + revents = LTTNG_POLL_GETEV(&events, i); + pollfd = LTTNG_POLL_GETFD(&events, i); + + /* Thread quit pipe has been closed. Killing thread. */ + ret = check_health_quit_pipe(pollfd, revents); + if (ret) { + err = 0; + goto exit; + } + + /* Event on the registration socket */ + if (pollfd == sock) { + if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) + && !(revents & LPOLLIN)) { + ERR("Health socket poll error"); + goto error; + } + } + } + + new_sock = lttcomm_accept_unix_sock(sock); + if (new_sock < 0) { + goto error; + } + + /* + * Set the CLOEXEC flag. Return code is useless because either way, the + * show must go on. + */ + (void) utils_set_fd_cloexec(new_sock); + + DBG("Receiving data from client for health..."); + ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg)); + if (ret <= 0) { + DBG("Nothing recv() from client... continuing"); + ret = close(new_sock); + if (ret) { + PERROR("close"); + } + new_sock = -1; + continue; + } + + rcu_thread_online(); + + LTTNG_ASSERT(msg.cmd == HEALTH_CMD_CHECK); + + memset(&reply, 0, sizeof(reply)); + for (i = 0; i < NR_HEALTH_CONSUMERD_TYPES; i++) { + /* + * health_check_state return 0 if thread is in + * error. + */ + if (!health_check_state(health_consumerd, i)) { + reply.ret_code |= 1ULL << i; + } + } + + DBG("Health check return value %" PRIx64, reply.ret_code); + + ret = send_unix_sock(new_sock, (void *) &reply, sizeof(reply)); + if (ret < 0) { + ERR("Failed to send health data back to client"); + } + + /* End of transmission */ + ret = close(new_sock); + if (ret) { + PERROR("close"); + } + new_sock = -1; + } + +exit: +error: + if (err) { + ERR("Health error occurred in %s", __func__); + } + DBG("Health check thread dying"); + unlink(health_unix_sock_path); + if (sock >= 0) { + ret = close(sock); + if (ret) { + PERROR("close"); + } + } + + lttng_poll_clean(&events); + + rcu_unregister_thread(); + return NULL; +} diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c deleted file mode 100644 index dbcda885e..000000000 --- a/src/bin/lttng-consumerd/lttng-consumerd.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (C) 2011 Julien Desfossez - * Copyright (C) 2011 Mathieu Desnoyers - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -#define _LGPL_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lttng-consumerd.h" -#include "health-consumerd.h" - -/* threads (channel handling, poll, metadata, sessiond) */ - -static pthread_t channel_thread, data_thread, metadata_thread, - sessiond_thread, metadata_timer_thread, health_thread; -static bool metadata_timer_thread_online; - -/* to count the number of times the user pressed ctrl+c */ -static int sigintcount = 0; - -/* Argument variables */ -int lttng_opt_quiet; /* not static in error.h */ -int lttng_opt_verbose; /* not static in error.h */ -int lttng_opt_mi; /* not static in error.h */ - -static int opt_daemon; -static const char *progname; -static char command_sock_path[PATH_MAX]; /* Global command socket path */ -static char error_sock_path[PATH_MAX]; /* Global error path */ -static enum lttng_consumer_type opt_type = LTTNG_CONSUMER_KERNEL; - -/* the liblttngconsumerd context */ -static struct lttng_consumer_local_data *ctx; - -/* Consumerd health monitoring */ -struct health_app *health_consumerd; - -const char *tracing_group_name = DEFAULT_TRACING_GROUP; - -int lttng_consumer_ready = NR_LTTNG_CONSUMER_READY; - -enum lttng_consumer_type lttng_consumer_get_type(void) -{ - if (!ctx) { - return LTTNG_CONSUMER_UNKNOWN; - } - return ctx->type; -} - -/* - * Signal handler for the daemon - */ -static void sighandler(int sig, siginfo_t *siginfo, void *arg) -{ - if (sig == SIGINT && sigintcount++ == 0) { - DBG("ignoring first SIGINT"); - return; - } - - if (sig == SIGBUS) { - int write_ret; - const char msg[] = "Received SIGBUS, aborting program.\n"; - - lttng_consumer_sigbus_handle(siginfo->si_addr); - /* - * If ustctl did not catch this signal (triggering a - * siglongjmp), abort the program. Otherwise, the execution - * will resume from the ust-ctl call which caused this error. - * - * The return value is ignored since the program aborts anyhow. - */ - write_ret = write(STDERR_FILENO, msg, sizeof(msg)); - (void) write_ret; - abort(); - } - - if (ctx) { - lttng_consumer_should_exit(ctx); - } -} - -/* - * Setup signal handler for : - * SIGINT, SIGTERM, SIGPIPE, SIGBUS - */ -static int set_signal_handler(void) -{ - int ret = 0; - struct sigaction sa; - sigset_t sigset; - - if ((ret = sigemptyset(&sigset)) < 0) { - PERROR("sigemptyset"); - return ret; - } - - sa.sa_mask = sigset; - sa.sa_flags = SA_SIGINFO; - - sa.sa_sigaction = sighandler; - if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { - PERROR("sigaction"); - return ret; - } - - if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) { - PERROR("sigaction"); - return ret; - } - - if ((ret = sigaction(SIGBUS, &sa, NULL)) < 0) { - PERROR("sigaction"); - return ret; - } - - sa.sa_flags = 0; - sa.sa_handler = SIG_IGN; - if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { - PERROR("sigaction"); - return ret; - } - - return ret; -} - -/* - * Usage function on stream file. - */ -static void usage(FILE *fp) -{ - fprintf(fp, "Usage: %s OPTIONS\n\nOptions:\n", progname); - fprintf(fp, " -h, --help " - "Display this usage.\n"); - fprintf(fp, " -c, --consumerd-cmd-sock PATH " - "Specify path for the command socket\n"); - fprintf(fp, " -e, --consumerd-err-sock PATH " - "Specify path for the error socket\n"); - fprintf(fp, " -d, --daemonize " - "Start as a daemon.\n"); - fprintf(fp, " -q, --quiet " - "No output at all.\n"); - fprintf(fp, " -v, --verbose " - "Verbose mode. Activate DBG() macro.\n"); - fprintf(fp, " -V, --version " - "Show version number.\n"); - fprintf(fp, " -g, --group NAME " - "Specify the tracing group name. (default: tracing)\n"); - fprintf(fp, " -k, --kernel " - "Consumer kernel buffers (default).\n"); - fprintf(fp, " -u, --ust " - "Consumer UST buffers.%s\n", -#ifdef HAVE_LIBLTTNG_UST_CTL - "" -#else - " (support not compiled in)" -#endif - ); -} - -/* - * daemon argument parsing - */ -static int parse_args(int argc, char **argv) -{ - int c, ret = 0; - - static struct option long_options[] = { - { "consumerd-cmd-sock", 1, 0, 'c' }, - { "consumerd-err-sock", 1, 0, 'e' }, - { "daemonize", 0, 0, 'd' }, - { "group", 1, 0, 'g' }, - { "help", 0, 0, 'h' }, - { "quiet", 0, 0, 'q' }, - { "verbose", 0, 0, 'v' }, - { "version", 0, 0, 'V' }, - { "kernel", 0, 0, 'k' }, -#ifdef HAVE_LIBLTTNG_UST_CTL - { "ust", 0, 0, 'u' }, -#endif - { NULL, 0, 0, 0 } - }; - - while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "dhqvVku" "c:e:g:", - long_options, &option_index); - if (c == -1) { - break; - } - - switch (c) { - case 0: - fprintf(stderr, "option %s", - long_options[option_index].name); - if (optarg) { - fprintf(stderr, " with arg %s\n", optarg); - ret = -1; - goto end; - } - break; - case 'c': - if (lttng_is_setuid_setgid()) { - WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", - "-c, --consumerd-cmd-sock"); - } else { - snprintf(command_sock_path, PATH_MAX, "%s", optarg); - } - break; - case 'e': - if (lttng_is_setuid_setgid()) { - WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", - "-e, --consumerd-err-sock"); - } else { - snprintf(error_sock_path, PATH_MAX, "%s", optarg); - } - break; - case 'd': - opt_daemon = 1; - break; - case 'g': - if (lttng_is_setuid_setgid()) { - WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", - "-g, --group"); - } else { - tracing_group_name = optarg; - } - break; - case 'h': - usage(stdout); - exit(EXIT_SUCCESS); - case 'q': - lttng_opt_quiet = 1; - break; - case 'v': - lttng_opt_verbose = 3; - break; - case 'V': - fprintf(stdout, "%s\n", VERSION); - exit(EXIT_SUCCESS); - case 'k': - opt_type = LTTNG_CONSUMER_KERNEL; - break; -#ifdef HAVE_LIBLTTNG_UST_CTL - case 'u': -# if (CAA_BITS_PER_LONG == 64) - opt_type = LTTNG_CONSUMER64_UST; -# elif (CAA_BITS_PER_LONG == 32) - opt_type = LTTNG_CONSUMER32_UST; -# else -# error "Unknown bitness" -# endif - break; -#endif - default: - usage(stderr); - ret = -1; - goto end; - } - } -end: - return ret; -} - -/* - * Set open files limit to unlimited. This daemon can open a large number of - * file descriptors in order to consumer multiple kernel traces. - */ -static void set_ulimit(void) -{ - int ret; - struct rlimit lim; - - /* The kernel does not allowed an infinite limit for open files */ - lim.rlim_cur = 65535; - lim.rlim_max = 65535; - - ret = setrlimit(RLIMIT_NOFILE, &lim); - if (ret < 0) { - PERROR("failed to set open files limit"); - } -} - -/* - * main - */ -int main(int argc, char **argv) -{ - int ret = 0, retval = 0; - void *status; - struct lttng_consumer_local_data *tmp_ctx; - - rcu_register_thread(); - - if (run_as_create_worker(argv[0], NULL, NULL) < 0) { - goto exit_set_signal_handler; - } - - if (set_signal_handler()) { - retval = -1; - goto exit_set_signal_handler; - } - - /* Parse arguments */ - progname = argv[0]; - if (parse_args(argc, argv)) { - retval = -1; - goto exit_options; - } - - /* Daemonize */ - if (opt_daemon) { - int i; - - /* - * fork - * child: setsid, close FD 0, 1, 2, chdir / - * parent: exit (if fork is successful) - */ - ret = daemon(0, 0); - if (ret < 0) { - PERROR("daemon"); - retval = -1; - goto exit_options; - } - /* - * We are in the child. Make sure all other file - * descriptors are closed, in case we are called with - * more opened file descriptors than the standard ones. - */ - for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { - (void) close(i); - } - } - - /* - * Starting from here, we can create threads. This needs to be after - * lttng_daemonize due to RCU. - */ - - health_consumerd = health_app_create(NR_HEALTH_CONSUMERD_TYPES); - if (!health_consumerd) { - retval = -1; - goto exit_health_consumerd_cleanup; - } - - if (*command_sock_path == '\0') { - switch (opt_type) { - case LTTNG_CONSUMER_KERNEL: - ret = snprintf(command_sock_path, PATH_MAX, - DEFAULT_KCONSUMERD_CMD_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - case LTTNG_CONSUMER64_UST: - ret = snprintf(command_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - case LTTNG_CONSUMER32_UST: - ret = snprintf(command_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - default: - ERR("Unknown consumerd type"); - retval = -1; - goto exit_init_data; - } - } - - /* Init */ - if (lttng_consumer_init()) { - retval = -1; - goto exit_init_data; - } - - /* Initialize communication library */ - lttcomm_init(); - /* Initialize TCP timeout values */ - lttcomm_inet_init(); - - if (!getuid()) { - /* Set limit for open files */ - set_ulimit(); - } - - /* create the consumer instance with and assign the callbacks */ - ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer, - NULL, lttng_consumer_on_recv_stream, NULL); - if (!ctx) { - retval = -1; - goto exit_init_data; - } - - lttng_consumer_set_command_sock_path(ctx, command_sock_path); - if (*error_sock_path == '\0') { - switch (opt_type) { - case LTTNG_CONSUMER_KERNEL: - ret = snprintf(error_sock_path, PATH_MAX, - DEFAULT_KCONSUMERD_ERR_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - case LTTNG_CONSUMER64_UST: - ret = snprintf(error_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - case LTTNG_CONSUMER32_UST: - ret = snprintf(error_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, - DEFAULT_LTTNG_RUNDIR); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - break; - default: - ERR("Unknown consumerd type"); - retval = -1; - goto exit_init_data; - } - } - - /* Connect to the socket created by lttng-sessiond to report errors */ - DBG("Connecting to error socket %s", error_sock_path); - ret = lttcomm_connect_unix_sock(error_sock_path); - /* - * Not a fatal error, but all communication with lttng-sessiond will - * fail. - */ - if (ret < 0) { - WARN("Cannot connect to error socket (is lttng-sessiond started?)"); - } - lttng_consumer_set_error_sock(ctx, ret); - - /* - * Block RT signals used for UST periodical metadata flush and the live - * timer in main, and create a dedicated thread to handle these signals. - */ - if (consumer_signal_init()) { - retval = -1; - goto exit_init_data; - } - - ctx->type = opt_type; - - if (utils_create_pipe(health_quit_pipe)) { - retval = -1; - goto exit_health_pipe; - } - - /* Create thread to manage the client socket */ - ret = pthread_create(&health_thread, default_pthread_attr(), - thread_manage_health, (void *) NULL); - if (ret) { - errno = ret; - PERROR("pthread_create health"); - retval = -1; - goto exit_health_thread; - } - - /* - * Wait for health thread to be initialized before letting the - * sessiond thread reply to the sessiond that we are ready. - */ - while (uatomic_read(<tng_consumer_ready)) { - usleep(100000); - } - cmm_smp_mb(); /* Read ready before following operations */ - - /* - * Create the thread to manage the UST metadata periodic timer and - * live timer. - */ - ret = pthread_create(&metadata_timer_thread, NULL, - consumer_timer_thread, (void *) ctx); - if (ret) { - errno = ret; - PERROR("pthread_create"); - retval = -1; - goto exit_metadata_timer_thread; - } - metadata_timer_thread_online = true; - - /* Create thread to manage channels */ - ret = pthread_create(&channel_thread, default_pthread_attr(), - consumer_thread_channel_poll, - (void *) ctx); - if (ret) { - errno = ret; - PERROR("pthread_create"); - retval = -1; - goto exit_channel_thread; - } - - /* Create thread to manage the polling/writing of trace metadata */ - ret = pthread_create(&metadata_thread, default_pthread_attr(), - consumer_thread_metadata_poll, - (void *) ctx); - if (ret) { - errno = ret; - PERROR("pthread_create"); - retval = -1; - goto exit_metadata_thread; - } - - /* Create thread to manage the polling/writing of trace data */ - ret = pthread_create(&data_thread, default_pthread_attr(), - consumer_thread_data_poll, (void *) ctx); - if (ret) { - errno = ret; - PERROR("pthread_create"); - retval = -1; - goto exit_data_thread; - } - - /* Create the thread to manage the reception of fds */ - ret = pthread_create(&sessiond_thread, default_pthread_attr(), - consumer_thread_sessiond_poll, - (void *) ctx); - if (ret) { - errno = ret; - PERROR("pthread_create"); - retval = -1; - goto exit_sessiond_thread; - } - - - /* - * This is where we start awaiting program completion (e.g. through - * signal that asks threads to teardown. - */ - - ret = pthread_join(sessiond_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join sessiond_thread"); - retval = -1; - } -exit_sessiond_thread: - - ret = pthread_join(data_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join data_thread"); - retval = -1; - } -exit_data_thread: - - ret = pthread_join(metadata_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join metadata_thread"); - retval = -1; - } -exit_metadata_thread: - - ret = pthread_join(channel_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join channel_thread"); - retval = -1; - } -exit_channel_thread: - -exit_metadata_timer_thread: - - ret = pthread_join(health_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join health_thread"); - retval = -1; - } -exit_health_thread: - - utils_close_pipe(health_quit_pipe); -exit_health_pipe: - -exit_init_data: - /* - * Wait for all pending call_rcu work to complete before tearing - * down data structures. call_rcu worker may be trying to - * perform lookups in those structures. - */ - rcu_barrier(); - lttng_consumer_cleanup(); - /* - * Tearing down the metadata timer thread in a - * non-fully-symmetric fashion compared to its creation in case - * lttng_consumer_cleanup() ends up tearing down timers (which - * requires the timer thread to be alive). - */ - if (metadata_timer_thread_online) { - /* - * Ensure the metadata timer thread exits only after all other - * threads are gone, because it is required to perform timer - * teardown synchronization. - */ - kill(getpid(), LTTNG_CONSUMER_SIG_EXIT); - ret = pthread_join(metadata_timer_thread, &status); - if (ret) { - errno = ret; - PERROR("pthread_join metadata_timer_thread"); - retval = -1; - } - ret = consumer_timer_thread_get_channel_monitor_pipe(); - if (ret >= 0) { - ret = close(ret); - if (ret) { - PERROR("close channel monitor pipe"); - } - } - metadata_timer_thread_online = false; - } - tmp_ctx = ctx; - ctx = NULL; - cmm_barrier(); /* Clear ctx for signal handler. */ - lttng_consumer_destroy(tmp_ctx); - - if (health_consumerd) { - health_app_destroy(health_consumerd); - } - /* Ensure all prior call_rcu are done. */ - rcu_barrier(); - - run_as_destroy_worker(); - -exit_health_consumerd_cleanup: -exit_options: -exit_set_signal_handler: - - rcu_unregister_thread(); - - if (!retval) { - exit(EXIT_SUCCESS); - } else { - exit(EXIT_FAILURE); - } -} diff --git a/src/bin/lttng-consumerd/lttng-consumerd.cpp b/src/bin/lttng-consumerd/lttng-consumerd.cpp new file mode 100644 index 000000000..dbcda885e --- /dev/null +++ b/src/bin/lttng-consumerd/lttng-consumerd.cpp @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2011 Julien Desfossez + * Copyright (C) 2011 Mathieu Desnoyers + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lttng-consumerd.h" +#include "health-consumerd.h" + +/* threads (channel handling, poll, metadata, sessiond) */ + +static pthread_t channel_thread, data_thread, metadata_thread, + sessiond_thread, metadata_timer_thread, health_thread; +static bool metadata_timer_thread_online; + +/* to count the number of times the user pressed ctrl+c */ +static int sigintcount = 0; + +/* Argument variables */ +int lttng_opt_quiet; /* not static in error.h */ +int lttng_opt_verbose; /* not static in error.h */ +int lttng_opt_mi; /* not static in error.h */ + +static int opt_daemon; +static const char *progname; +static char command_sock_path[PATH_MAX]; /* Global command socket path */ +static char error_sock_path[PATH_MAX]; /* Global error path */ +static enum lttng_consumer_type opt_type = LTTNG_CONSUMER_KERNEL; + +/* the liblttngconsumerd context */ +static struct lttng_consumer_local_data *ctx; + +/* Consumerd health monitoring */ +struct health_app *health_consumerd; + +const char *tracing_group_name = DEFAULT_TRACING_GROUP; + +int lttng_consumer_ready = NR_LTTNG_CONSUMER_READY; + +enum lttng_consumer_type lttng_consumer_get_type(void) +{ + if (!ctx) { + return LTTNG_CONSUMER_UNKNOWN; + } + return ctx->type; +} + +/* + * Signal handler for the daemon + */ +static void sighandler(int sig, siginfo_t *siginfo, void *arg) +{ + if (sig == SIGINT && sigintcount++ == 0) { + DBG("ignoring first SIGINT"); + return; + } + + if (sig == SIGBUS) { + int write_ret; + const char msg[] = "Received SIGBUS, aborting program.\n"; + + lttng_consumer_sigbus_handle(siginfo->si_addr); + /* + * If ustctl did not catch this signal (triggering a + * siglongjmp), abort the program. Otherwise, the execution + * will resume from the ust-ctl call which caused this error. + * + * The return value is ignored since the program aborts anyhow. + */ + write_ret = write(STDERR_FILENO, msg, sizeof(msg)); + (void) write_ret; + abort(); + } + + if (ctx) { + lttng_consumer_should_exit(ctx); + } +} + +/* + * Setup signal handler for : + * SIGINT, SIGTERM, SIGPIPE, SIGBUS + */ +static int set_signal_handler(void) +{ + int ret = 0; + struct sigaction sa; + sigset_t sigset; + + if ((ret = sigemptyset(&sigset)) < 0) { + PERROR("sigemptyset"); + return ret; + } + + sa.sa_mask = sigset; + sa.sa_flags = SA_SIGINFO; + + sa.sa_sigaction = sighandler; + if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + if ((ret = sigaction(SIGBUS, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + return ret; +} + +/* + * Usage function on stream file. + */ +static void usage(FILE *fp) +{ + fprintf(fp, "Usage: %s OPTIONS\n\nOptions:\n", progname); + fprintf(fp, " -h, --help " + "Display this usage.\n"); + fprintf(fp, " -c, --consumerd-cmd-sock PATH " + "Specify path for the command socket\n"); + fprintf(fp, " -e, --consumerd-err-sock PATH " + "Specify path for the error socket\n"); + fprintf(fp, " -d, --daemonize " + "Start as a daemon.\n"); + fprintf(fp, " -q, --quiet " + "No output at all.\n"); + fprintf(fp, " -v, --verbose " + "Verbose mode. Activate DBG() macro.\n"); + fprintf(fp, " -V, --version " + "Show version number.\n"); + fprintf(fp, " -g, --group NAME " + "Specify the tracing group name. (default: tracing)\n"); + fprintf(fp, " -k, --kernel " + "Consumer kernel buffers (default).\n"); + fprintf(fp, " -u, --ust " + "Consumer UST buffers.%s\n", +#ifdef HAVE_LIBLTTNG_UST_CTL + "" +#else + " (support not compiled in)" +#endif + ); +} + +/* + * daemon argument parsing + */ +static int parse_args(int argc, char **argv) +{ + int c, ret = 0; + + static struct option long_options[] = { + { "consumerd-cmd-sock", 1, 0, 'c' }, + { "consumerd-err-sock", 1, 0, 'e' }, + { "daemonize", 0, 0, 'd' }, + { "group", 1, 0, 'g' }, + { "help", 0, 0, 'h' }, + { "quiet", 0, 0, 'q' }, + { "verbose", 0, 0, 'v' }, + { "version", 0, 0, 'V' }, + { "kernel", 0, 0, 'k' }, +#ifdef HAVE_LIBLTTNG_UST_CTL + { "ust", 0, 0, 'u' }, +#endif + { NULL, 0, 0, 0 } + }; + + while (1) { + int option_index = 0; + c = getopt_long(argc, argv, "dhqvVku" "c:e:g:", + long_options, &option_index); + if (c == -1) { + break; + } + + switch (c) { + case 0: + fprintf(stderr, "option %s", + long_options[option_index].name); + if (optarg) { + fprintf(stderr, " with arg %s\n", optarg); + ret = -1; + goto end; + } + break; + case 'c': + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-c, --consumerd-cmd-sock"); + } else { + snprintf(command_sock_path, PATH_MAX, "%s", optarg); + } + break; + case 'e': + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-e, --consumerd-err-sock"); + } else { + snprintf(error_sock_path, PATH_MAX, "%s", optarg); + } + break; + case 'd': + opt_daemon = 1; + break; + case 'g': + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-g, --group"); + } else { + tracing_group_name = optarg; + } + break; + case 'h': + usage(stdout); + exit(EXIT_SUCCESS); + case 'q': + lttng_opt_quiet = 1; + break; + case 'v': + lttng_opt_verbose = 3; + break; + case 'V': + fprintf(stdout, "%s\n", VERSION); + exit(EXIT_SUCCESS); + case 'k': + opt_type = LTTNG_CONSUMER_KERNEL; + break; +#ifdef HAVE_LIBLTTNG_UST_CTL + case 'u': +# if (CAA_BITS_PER_LONG == 64) + opt_type = LTTNG_CONSUMER64_UST; +# elif (CAA_BITS_PER_LONG == 32) + opt_type = LTTNG_CONSUMER32_UST; +# else +# error "Unknown bitness" +# endif + break; +#endif + default: + usage(stderr); + ret = -1; + goto end; + } + } +end: + return ret; +} + +/* + * Set open files limit to unlimited. This daemon can open a large number of + * file descriptors in order to consumer multiple kernel traces. + */ +static void set_ulimit(void) +{ + int ret; + struct rlimit lim; + + /* The kernel does not allowed an infinite limit for open files */ + lim.rlim_cur = 65535; + lim.rlim_max = 65535; + + ret = setrlimit(RLIMIT_NOFILE, &lim); + if (ret < 0) { + PERROR("failed to set open files limit"); + } +} + +/* + * main + */ +int main(int argc, char **argv) +{ + int ret = 0, retval = 0; + void *status; + struct lttng_consumer_local_data *tmp_ctx; + + rcu_register_thread(); + + if (run_as_create_worker(argv[0], NULL, NULL) < 0) { + goto exit_set_signal_handler; + } + + if (set_signal_handler()) { + retval = -1; + goto exit_set_signal_handler; + } + + /* Parse arguments */ + progname = argv[0]; + if (parse_args(argc, argv)) { + retval = -1; + goto exit_options; + } + + /* Daemonize */ + if (opt_daemon) { + int i; + + /* + * fork + * child: setsid, close FD 0, 1, 2, chdir / + * parent: exit (if fork is successful) + */ + ret = daemon(0, 0); + if (ret < 0) { + PERROR("daemon"); + retval = -1; + goto exit_options; + } + /* + * We are in the child. Make sure all other file + * descriptors are closed, in case we are called with + * more opened file descriptors than the standard ones. + */ + for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { + (void) close(i); + } + } + + /* + * Starting from here, we can create threads. This needs to be after + * lttng_daemonize due to RCU. + */ + + health_consumerd = health_app_create(NR_HEALTH_CONSUMERD_TYPES); + if (!health_consumerd) { + retval = -1; + goto exit_health_consumerd_cleanup; + } + + if (*command_sock_path == '\0') { + switch (opt_type) { + case LTTNG_CONSUMER_KERNEL: + ret = snprintf(command_sock_path, PATH_MAX, + DEFAULT_KCONSUMERD_CMD_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + case LTTNG_CONSUMER64_UST: + ret = snprintf(command_sock_path, PATH_MAX, + DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + case LTTNG_CONSUMER32_UST: + ret = snprintf(command_sock_path, PATH_MAX, + DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + default: + ERR("Unknown consumerd type"); + retval = -1; + goto exit_init_data; + } + } + + /* Init */ + if (lttng_consumer_init()) { + retval = -1; + goto exit_init_data; + } + + /* Initialize communication library */ + lttcomm_init(); + /* Initialize TCP timeout values */ + lttcomm_inet_init(); + + if (!getuid()) { + /* Set limit for open files */ + set_ulimit(); + } + + /* create the consumer instance with and assign the callbacks */ + ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer, + NULL, lttng_consumer_on_recv_stream, NULL); + if (!ctx) { + retval = -1; + goto exit_init_data; + } + + lttng_consumer_set_command_sock_path(ctx, command_sock_path); + if (*error_sock_path == '\0') { + switch (opt_type) { + case LTTNG_CONSUMER_KERNEL: + ret = snprintf(error_sock_path, PATH_MAX, + DEFAULT_KCONSUMERD_ERR_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + case LTTNG_CONSUMER64_UST: + ret = snprintf(error_sock_path, PATH_MAX, + DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + case LTTNG_CONSUMER32_UST: + ret = snprintf(error_sock_path, PATH_MAX, + DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, + DEFAULT_LTTNG_RUNDIR); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + break; + default: + ERR("Unknown consumerd type"); + retval = -1; + goto exit_init_data; + } + } + + /* Connect to the socket created by lttng-sessiond to report errors */ + DBG("Connecting to error socket %s", error_sock_path); + ret = lttcomm_connect_unix_sock(error_sock_path); + /* + * Not a fatal error, but all communication with lttng-sessiond will + * fail. + */ + if (ret < 0) { + WARN("Cannot connect to error socket (is lttng-sessiond started?)"); + } + lttng_consumer_set_error_sock(ctx, ret); + + /* + * Block RT signals used for UST periodical metadata flush and the live + * timer in main, and create a dedicated thread to handle these signals. + */ + if (consumer_signal_init()) { + retval = -1; + goto exit_init_data; + } + + ctx->type = opt_type; + + if (utils_create_pipe(health_quit_pipe)) { + retval = -1; + goto exit_health_pipe; + } + + /* Create thread to manage the client socket */ + ret = pthread_create(&health_thread, default_pthread_attr(), + thread_manage_health, (void *) NULL); + if (ret) { + errno = ret; + PERROR("pthread_create health"); + retval = -1; + goto exit_health_thread; + } + + /* + * Wait for health thread to be initialized before letting the + * sessiond thread reply to the sessiond that we are ready. + */ + while (uatomic_read(<tng_consumer_ready)) { + usleep(100000); + } + cmm_smp_mb(); /* Read ready before following operations */ + + /* + * Create the thread to manage the UST metadata periodic timer and + * live timer. + */ + ret = pthread_create(&metadata_timer_thread, NULL, + consumer_timer_thread, (void *) ctx); + if (ret) { + errno = ret; + PERROR("pthread_create"); + retval = -1; + goto exit_metadata_timer_thread; + } + metadata_timer_thread_online = true; + + /* Create thread to manage channels */ + ret = pthread_create(&channel_thread, default_pthread_attr(), + consumer_thread_channel_poll, + (void *) ctx); + if (ret) { + errno = ret; + PERROR("pthread_create"); + retval = -1; + goto exit_channel_thread; + } + + /* Create thread to manage the polling/writing of trace metadata */ + ret = pthread_create(&metadata_thread, default_pthread_attr(), + consumer_thread_metadata_poll, + (void *) ctx); + if (ret) { + errno = ret; + PERROR("pthread_create"); + retval = -1; + goto exit_metadata_thread; + } + + /* Create thread to manage the polling/writing of trace data */ + ret = pthread_create(&data_thread, default_pthread_attr(), + consumer_thread_data_poll, (void *) ctx); + if (ret) { + errno = ret; + PERROR("pthread_create"); + retval = -1; + goto exit_data_thread; + } + + /* Create the thread to manage the reception of fds */ + ret = pthread_create(&sessiond_thread, default_pthread_attr(), + consumer_thread_sessiond_poll, + (void *) ctx); + if (ret) { + errno = ret; + PERROR("pthread_create"); + retval = -1; + goto exit_sessiond_thread; + } + + + /* + * This is where we start awaiting program completion (e.g. through + * signal that asks threads to teardown. + */ + + ret = pthread_join(sessiond_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join sessiond_thread"); + retval = -1; + } +exit_sessiond_thread: + + ret = pthread_join(data_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join data_thread"); + retval = -1; + } +exit_data_thread: + + ret = pthread_join(metadata_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join metadata_thread"); + retval = -1; + } +exit_metadata_thread: + + ret = pthread_join(channel_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join channel_thread"); + retval = -1; + } +exit_channel_thread: + +exit_metadata_timer_thread: + + ret = pthread_join(health_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join health_thread"); + retval = -1; + } +exit_health_thread: + + utils_close_pipe(health_quit_pipe); +exit_health_pipe: + +exit_init_data: + /* + * Wait for all pending call_rcu work to complete before tearing + * down data structures. call_rcu worker may be trying to + * perform lookups in those structures. + */ + rcu_barrier(); + lttng_consumer_cleanup(); + /* + * Tearing down the metadata timer thread in a + * non-fully-symmetric fashion compared to its creation in case + * lttng_consumer_cleanup() ends up tearing down timers (which + * requires the timer thread to be alive). + */ + if (metadata_timer_thread_online) { + /* + * Ensure the metadata timer thread exits only after all other + * threads are gone, because it is required to perform timer + * teardown synchronization. + */ + kill(getpid(), LTTNG_CONSUMER_SIG_EXIT); + ret = pthread_join(metadata_timer_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join metadata_timer_thread"); + retval = -1; + } + ret = consumer_timer_thread_get_channel_monitor_pipe(); + if (ret >= 0) { + ret = close(ret); + if (ret) { + PERROR("close channel monitor pipe"); + } + } + metadata_timer_thread_online = false; + } + tmp_ctx = ctx; + ctx = NULL; + cmm_barrier(); /* Clear ctx for signal handler. */ + lttng_consumer_destroy(tmp_ctx); + + if (health_consumerd) { + health_app_destroy(health_consumerd); + } + /* Ensure all prior call_rcu are done. */ + rcu_barrier(); + + run_as_destroy_worker(); + +exit_health_consumerd_cleanup: +exit_options: +exit_set_signal_handler: + + rcu_unregister_thread(); + + if (!retval) { + exit(EXIT_SUCCESS); + } else { + exit(EXIT_FAILURE); + } +} diff --git a/src/bin/lttng-consumerd/lttng-consumerd.h b/src/bin/lttng-consumerd/lttng-consumerd.h index 8e40c9fee..7621877d3 100644 --- a/src/bin/lttng-consumerd/lttng-consumerd.h +++ b/src/bin/lttng-consumerd/lttng-consumerd.h @@ -15,6 +15,10 @@ extern int lttng_consumer_ready; extern const char *tracing_group_name; -enum lttng_consumer_type lttng_consumer_get_type(void); +/* + * This function is dlsym-ed from a test, making it have a C linkage name + * makes it easier. + */ +extern "C" enum lttng_consumer_type lttng_consumer_get_type(); #endif /* _LTTNG_CONSUMERD_H */ diff --git a/src/common/consumer/consumer-timer.h b/src/common/consumer/consumer-timer.h index 85751442f..084eb017d 100644 --- a/src/common/consumer/consumer-timer.h +++ b/src/common/consumer/consumer-timer.h @@ -14,6 +14,10 @@ #include "consumer.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LTTNG_CONSUMER_SIG_SWITCH SIGRTMIN + 10 #define LTTNG_CONSUMER_SIG_TEARDOWN SIGRTMIN + 11 #define LTTNG_CONSUMER_SIG_LIVE SIGRTMIN + 12 @@ -53,4 +57,8 @@ int consumer_flush_ust_index(struct lttng_consumer_stream *stream); int consumer_timer_thread_get_channel_monitor_pipe(void); int consumer_timer_thread_set_channel_monitor_pipe(int fd); +#ifdef __cplusplus +} +#endif + #endif /* CONSUMER_TIMER_H */ diff --git a/src/common/consumer/consumer.h b/src/common/consumer/consumer.h index 0c83baa8c..6f2aae31b 100644 --- a/src/common/consumer/consumer.h +++ b/src/common/consumer/consumer.h @@ -29,6 +29,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct lttng_consumer_local_data; /* Commands for consumer */ @@ -1061,4 +1065,8 @@ enum lttcomm_return_code lttng_consumer_open_channel_packets( int consumer_metadata_wakeup_pipe(const struct lttng_consumer_channel *channel); void lttng_consumer_sigbus_handle(void *addr); +#ifdef __cplusplus +} +#endif + #endif /* LIB_CONSUMER_H */