X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=10802aa7b2cc66d87d0946ee53623b05b47a1c0f;hp=b5cfe307df0f09e1a1eec61de85795bee1de29ea;hb=e6142f2e647e83238b1e399b1264e8adb05409f9;hpb=fb45065e7ccafc636e6eec7ab2a463c49e603ebb diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index b5cfe307d..10802aa7b 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #define _LGPL_SOURCE #include #include @@ -38,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -49,7 +48,7 @@ #include #include #include -#include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -72,23 +71,24 @@ #include "agent-thread.h" #include "save.h" #include "load-session-thread.h" +#include "notification-thread.h" +#include "notification-thread-commands.h" #include "syscall.h" #include "agent.h" +#include "ht-cleanup.h" +#include "sessiond-config.h" -#define CONSUMERD_FILE "lttng-consumerd" +static const char *help_msg = +#ifdef LTTNG_EMBED_HELP +#include +#else +NULL +#endif +; const char *progname; -static const char *tracing_group_name = DEFAULT_TRACING_GROUP; -static int tracing_group_name_override; -static char *opt_pidfile; -static int opt_sig_parent; -static int opt_verbose_consumer; -static int opt_daemon, opt_background; -static int opt_no_kernel; -static char *opt_load_session_path; static pid_t ppid; /* Parent PID for --sig-parent option */ static pid_t child_ppid; /* Internal parent PID use with daemonize. */ -static char *rundir; static int lockfile_fd = -1; /* Set to 1 when a SIGUSR1 signal is received. */ @@ -100,10 +100,9 @@ static int recv_child_signal; */ static struct consumer_data kconsumer_data = { .type = LTTNG_CONSUMER_KERNEL, - .err_unix_sock_path = DEFAULT_KCONSUMERD_ERR_SOCK_PATH, - .cmd_unix_sock_path = DEFAULT_KCONSUMERD_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -111,10 +110,9 @@ static struct consumer_data kconsumer_data = { }; static struct consumer_data ustconsumer64_data = { .type = LTTNG_CONSUMER64_UST, - .err_unix_sock_path = DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, - .cmd_unix_sock_path = DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -122,10 +120,9 @@ static struct consumer_data ustconsumer64_data = { }; static struct consumer_data ustconsumer32_data = { .type = LTTNG_CONSUMER32_UST, - .err_unix_sock_path = DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, - .cmd_unix_sock_path = DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, .err_sock = -1, .cmd_sock = -1, + .channel_monitor_pipe = -1, .pid_mutex = PTHREAD_MUTEX_INITIALIZER, .lock = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, @@ -165,21 +162,14 @@ static const struct option long_options[] = { { NULL, 0, 0, 0 } }; +struct sessiond_config config; + /* Command line options to ignore from configuration file */ static const char *config_ignore_options[] = { "help", "version", "config" }; /* Shared between threads */ static int dispatch_thread_exit; -/* Global application Unix socket path */ -static char apps_unix_sock_path[PATH_MAX]; -/* Global client Unix socket path */ -static char client_unix_sock_path[PATH_MAX]; -/* global wait shm path for UST */ -static char wait_shm_path[PATH_MAX]; -/* Global health check unix path */ -static char health_unix_sock_path[PATH_MAX]; - /* Sockets and FDs */ static int client_sock = -1; static int apps_sock = -1; @@ -191,7 +181,6 @@ static int kernel_poll_pipe[2] = { -1, -1 }; * for all threads when receiving an event on the pipe. */ static int thread_quit_pipe[2] = { -1, -1 }; -static int ht_cleanup_quit_pipe[2] = { -1, -1 }; /* * This pipe is used to inform the thread managing application communication @@ -212,6 +201,7 @@ static pthread_t health_thread; static pthread_t ht_cleanup_thread; static pthread_t agent_reg_thread; static pthread_t load_session_thread; +static pthread_t notification_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -239,15 +229,6 @@ static struct ltt_session_list *session_list_ptr; int ust_consumerd64_fd = -1; int ust_consumerd32_fd = -1; -static const char *consumerd32_bin = CONFIG_CONSUMERD32_BIN; -static const char *consumerd64_bin = CONFIG_CONSUMERD64_BIN; -static const char *consumerd32_libdir = CONFIG_CONSUMERD32_LIBDIR; -static const char *consumerd64_libdir = CONFIG_CONSUMERD64_LIBDIR; -static int consumerd32_bin_override; -static int consumerd64_bin_override; -static int consumerd32_libdir_override; -static int consumerd64_libdir_override; - static const char *module_proc_lttng = "/proc/lttng"; /* @@ -284,20 +265,12 @@ enum consumerd_state { static enum consumerd_state ust_consumerd_state; static enum consumerd_state kernel_consumerd_state; -/* - * Socket timeout for receiving and sending in seconds. - */ -static int app_socket_timeout; - /* Set in main() with the current page size. */ long page_size; /* Application health monitoring */ struct health_app *health_sessiond; -/* Agent TCP port for registration. Used by the agent thread. */ -unsigned int agent_tcp_port = DEFAULT_AGENT_TCP_PORT; - /* Am I root or not. */ int is_root; /* Set to 1 if the daemon is running as root */ @@ -306,17 +279,26 @@ const char * const config_section_name = "sessiond"; /* Load session thread information to operate. */ struct load_session_thread_data *load_info; +/* Notification thread handle. */ +struct notification_thread_handle *notification_thread_handle; + /* Global hash tables */ struct lttng_ht *agent_apps_ht_by_sock = NULL; /* - * Whether sessiond is ready for commands/health check requests. + * Whether sessiond is ready for commands/notification channel/health check + * requests. * NR_LTTNG_SESSIOND_READY must match the number of calls to * sessiond_notify_ready(). */ -#define NR_LTTNG_SESSIOND_READY 3 +#define NR_LTTNG_SESSIOND_READY 4 int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY; +int sessiond_check_thread_quit_pipe(int fd, uint32_t events) +{ + return (fd == thread_quit_pipe[0] && (events & LPOLLIN)) ? 1 : 0; +} + /* Notify parents that we are ready for cmd and health check */ LTTNG_HIDDEN void sessiond_notify_ready(void) @@ -327,7 +309,7 @@ void sessiond_notify_ready(void) * for client side. This ppid is the one from the * external process that spawned us. */ - if (opt_sig_parent) { + if (config.sig_parent) { kill(ppid, SIGUSR1); } @@ -335,61 +317,12 @@ void sessiond_notify_ready(void) * Notify the parent of the fork() process that we are * ready. */ - if (opt_daemon || opt_background) { + if (config.daemonize || config.background) { kill(child_ppid, SIGUSR1); } } } -static -void setup_consumerd_path(void) -{ - const char *bin, *libdir; - - /* - * Allow INSTALL_BIN_PATH to be used as a target path for the - * native architecture size consumer if CONFIG_CONSUMER*_PATH - * has not been defined. - */ -#if (CAA_BITS_PER_LONG == 32) - if (!consumerd32_bin[0]) { - consumerd32_bin = INSTALL_BIN_PATH "/" CONSUMERD_FILE; - } - if (!consumerd32_libdir[0]) { - consumerd32_libdir = INSTALL_LIB_PATH; - } -#elif (CAA_BITS_PER_LONG == 64) - if (!consumerd64_bin[0]) { - consumerd64_bin = INSTALL_BIN_PATH "/" CONSUMERD_FILE; - } - if (!consumerd64_libdir[0]) { - consumerd64_libdir = INSTALL_LIB_PATH; - } -#else -#error "Unknown bitness" -#endif - - /* - * runtime env. var. overrides the build default. - */ - bin = lttng_secure_getenv("LTTNG_CONSUMERD32_BIN"); - if (bin) { - consumerd32_bin = bin; - } - bin = lttng_secure_getenv("LTTNG_CONSUMERD64_BIN"); - if (bin) { - consumerd64_bin = bin; - } - libdir = lttng_secure_getenv("LTTNG_CONSUMERD32_LIBDIR"); - if (libdir) { - consumerd32_libdir = libdir; - } - libdir = lttng_secure_getenv("LTTNG_CONSUMERD64_LIBDIR"); - if (libdir) { - consumerd64_libdir = libdir; - } -} - static int __sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size, int *a_pipe) @@ -423,47 +356,6 @@ int sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size) return __sessiond_set_thread_pollset(events, size, thread_quit_pipe); } -/* - * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. - */ -int sessiond_set_ht_cleanup_thread_pollset(struct lttng_poll_event *events, - size_t size) -{ - return __sessiond_set_thread_pollset(events, size, - ht_cleanup_quit_pipe); -} - -static -int __sessiond_check_thread_quit_pipe(int fd, uint32_t events, int a_pipe) -{ - if (fd == a_pipe && (events & LPOLLIN)) { - return 1; - } - return 0; -} - -/* - * Check if the thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_thread_quit_pipe(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - thread_quit_pipe[0]); -} - -/* - * Check if the ht_cleanup thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_ht_cleanup_quit(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - ht_cleanup_quit_pipe[0]); -} - /* * Init thread quit pipe. * @@ -496,11 +388,6 @@ static int init_thread_quit_pipe(void) return __init_thread_quit_pipe(thread_quit_pipe); } -static int init_ht_cleanup_quit_pipe(void) -{ - return __init_thread_quit_pipe(ht_cleanup_quit_pipe); -} - /* * Stop all threads by closing the thread quit pipe. */ @@ -563,27 +450,51 @@ static void close_consumer_sockets(void) PERROR("UST consumerd64 cmd_sock close"); } } + if (kconsumer_data.channel_monitor_pipe >= 0) { + ret = close(kconsumer_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("kernel consumer channel monitor pipe close"); + } + } + if (ustconsumer32_data.channel_monitor_pipe >= 0) { + ret = close(ustconsumer32_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("UST consumerd32 channel monitor pipe close"); + } + } + if (ustconsumer64_data.channel_monitor_pipe >= 0) { + ret = close(ustconsumer64_data.channel_monitor_pipe); + if (ret < 0) { + PERROR("UST consumerd64 channel monitor pipe close"); + } + } } /* - * Generate the full lock file path using the rundir. + * Wait on consumer process termination. * - * Return the snprintf() return value thus a negative value is an error. + * Need to be called with the consumer data lock held or from a context + * ensuring no concurrent access to data (e.g: cleanup). */ -static int generate_lock_file_path(char *path, size_t len) +static void wait_consumer(struct consumer_data *consumer_data) { - int ret; + pid_t ret; + int status; - assert(path); - assert(rundir); - - /* Build lockfile path from rundir. */ - ret = snprintf(path, len, "%s/" DEFAULT_LTTNG_SESSIOND_LOCKFILE, rundir); - if (ret < 0) { - PERROR("snprintf lockfile path"); + if (consumer_data->pid <= 0) { + return; } - return ret; + DBG("Waiting for complete teardown of consumerd (PID: %d)", + consumer_data->pid); + ret = waitpid(consumer_data->pid, &status, 0); + if (ret == -1) { + PERROR("consumerd waitpid pid: %d", consumer_data->pid) + } else if (!WIFEXITED(status)) { + ERR("consumerd termination with error: %d", + WEXITSTATUS(ret)); + } + consumer_data->pid = 0; } /* @@ -593,7 +504,6 @@ static void sessiond_cleanup(void) { int ret; struct ltt_session *sess, *stmp; - char path[PATH_MAX]; DBG("Cleanup sessiond"); @@ -604,68 +514,46 @@ static void sessiond_cleanup(void) utils_close_pipe(thread_quit_pipe); /* - * If opt_pidfile is undefined, the default file will be wiped when - * removing the rundir. + * If config.pid_file_path.value is undefined, the default file will be + * wiped when removing the rundir. */ - if (opt_pidfile) { - ret = remove(opt_pidfile); + if (config.pid_file_path.value) { + ret = remove(config.pid_file_path.value); if (ret < 0) { - PERROR("remove pidfile %s", opt_pidfile); + PERROR("remove pidfile %s", config.pid_file_path.value); } } - DBG("Removing sessiond and consumerd content of directory %s", rundir); + DBG("Removing sessiond and consumerd content of directory %s", + config.rundir.value); /* sessiond */ - snprintf(path, PATH_MAX, - "%s/%s", - rundir, DEFAULT_LTTNG_SESSIOND_PIDFILE); - DBG("Removing %s", path); - (void) unlink(path); + DBG("Removing %s", config.pid_file_path.value); + (void) unlink(config.pid_file_path.value); - snprintf(path, PATH_MAX, "%s/%s", rundir, - DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE); - DBG("Removing %s", path); - (void) unlink(path); + DBG("Removing %s", config.agent_port_file_path.value); + (void) unlink(config.agent_port_file_path.value); /* kconsumerd */ - snprintf(path, PATH_MAX, - DEFAULT_KCONSUMERD_ERR_SOCK_PATH, - rundir); - DBG("Removing %s", path); - (void) unlink(path); - - snprintf(path, PATH_MAX, - DEFAULT_KCONSUMERD_PATH, - rundir); - DBG("Removing directory %s", path); - (void) rmdir(path); + DBG("Removing %s", kconsumer_data.err_unix_sock_path); + (void) unlink(kconsumer_data.err_unix_sock_path); + + DBG("Removing directory %s", config.kconsumerd_path.value); + (void) rmdir(config.kconsumerd_path.value); /* ust consumerd 32 */ - snprintf(path, PATH_MAX, - DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, - rundir); - DBG("Removing %s", path); - (void) unlink(path); - - snprintf(path, PATH_MAX, - DEFAULT_USTCONSUMERD32_PATH, - rundir); - DBG("Removing directory %s", path); - (void) rmdir(path); + DBG("Removing %s", config.consumerd32_err_unix_sock_path.value); + (void) unlink(config.consumerd32_err_unix_sock_path.value); + + DBG("Removing directory %s", config.consumerd32_path.value); + (void) rmdir(config.consumerd32_path.value); /* ust consumerd 64 */ - snprintf(path, PATH_MAX, - DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, - rundir); - DBG("Removing %s", path); - (void) unlink(path); - - snprintf(path, PATH_MAX, - DEFAULT_USTCONSUMERD64_PATH, - rundir); - DBG("Removing directory %s", path); - (void) rmdir(path); + DBG("Removing %s", config.consumerd64_err_unix_sock_path.value); + (void) unlink(config.consumerd64_err_unix_sock_path.value); + + DBG("Removing directory %s", config.consumerd64_path.value); + (void) rmdir(config.consumerd64_path.value); DBG("Cleaning up all sessions"); @@ -680,6 +568,10 @@ static void sessiond_cleanup(void) } } + wait_consumer(&kconsumer_data); + wait_consumer(&ustconsumer64_data); + wait_consumer(&ustconsumer32_data); + DBG("Cleaning up all agent apps"); agent_app_ht_clean(); @@ -687,7 +579,7 @@ static void sessiond_cleanup(void) ust_app_clean_list(); buffer_reg_destroy_registries(); - if (is_root && !opt_no_kernel) { + if (is_root && !config.no_kernel) { DBG2("Closing kernel fd"); if (kernel_tracer_fd >= 0) { ret = close(kernel_tracer_fd); @@ -712,19 +604,13 @@ static void sessiond_cleanup(void) * release the file system lock. */ if (lockfile_fd >= 0) { - char lockfile_path[PATH_MAX]; - - ret = generate_lock_file_path(lockfile_path, - sizeof(lockfile_path)); - if (ret > 0) { - ret = remove(lockfile_path); - if (ret < 0) { - PERROR("remove lock file"); - } - ret = close(lockfile_fd); - if (ret < 0) { - PERROR("close lock file"); - } + ret = remove(config.lock_file_path.value); + if (ret < 0) { + PERROR("remove lock file"); + } + ret = close(lockfile_fd); + if (ret < 0) { + PERROR("close lock file"); } } @@ -733,8 +619,6 @@ static void sessiond_cleanup(void) * using it, for instance lttng-relayd, which can start in * parallel with this teardown. */ - - free(rundir); } /* @@ -744,36 +628,9 @@ static void sessiond_cleanup_options(void) { DBG("Cleaning up options"); - /* - * If the override option is set, the pointer points to a *non* const - * thus freeing it even though the variable type is set to const. - */ - if (tracing_group_name_override) { - free((void *) tracing_group_name); - } - if (consumerd32_bin_override) { - free((void *) consumerd32_bin); - } - if (consumerd64_bin_override) { - free((void *) consumerd64_bin); - } - if (consumerd32_libdir_override) { - free((void *) consumerd32_libdir); - } - if (consumerd64_libdir_override) { - free((void *) consumerd64_libdir); - } - - free(opt_pidfile); - free(opt_load_session_path); - free(kmod_probes_list); - free(kmod_extra_probes_list); + sessiond_config_fini(&config); - /* */ - DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" - "Matthew, BEET driven development works!%c[%dm", - 27, 1, 31, 27, 0, 27, 1, 33, 27, 0); - /* */ + run_as_destroy_worker(); } /* @@ -819,7 +676,7 @@ static int notify_ust_apps(int active) DBG("Notifying applications of session daemon state: %d", active); /* See shm.c for this call implying mmap, shm and futex calls */ - wait_shm_mmap = shm_ust_get_mmap(wait_shm_path, is_root); + wait_shm_mmap = shm_ust_get_mmap(config.wait_shm_path.value, is_root); if (wait_shm_mmap == NULL) { goto error; } @@ -839,34 +696,57 @@ error: * right amount of memory and copying the original information from the lsm * structure. * - * Return total size of the buffer pointed by buf. + * Return 0 on success, negative value on error. */ -static int setup_lttng_msg(struct command_ctx *cmd_ctx, size_t size) +static int setup_lttng_msg(struct command_ctx *cmd_ctx, + const void *payload_buf, size_t payload_len, + const void *cmd_header_buf, size_t cmd_header_len) { - int ret, buf_size; + int ret = 0; + const size_t header_len = sizeof(struct lttcomm_lttng_msg); + const size_t cmd_header_offset = header_len; + const size_t payload_offset = cmd_header_offset + cmd_header_len; + const size_t total_msg_size = header_len + cmd_header_len + payload_len; - buf_size = size; + cmd_ctx->llm = zmalloc(total_msg_size); - cmd_ctx->llm = zmalloc(sizeof(struct lttcomm_lttng_msg) + buf_size); if (cmd_ctx->llm == NULL) { PERROR("zmalloc"); ret = -ENOMEM; - goto error; + goto end; } /* Copy common data */ cmd_ctx->llm->cmd_type = cmd_ctx->lsm->cmd_type; cmd_ctx->llm->pid = cmd_ctx->lsm->domain.attr.pid; + cmd_ctx->llm->cmd_header_size = cmd_header_len; + cmd_ctx->llm->data_size = payload_len; + cmd_ctx->lttng_msg_size = total_msg_size; - cmd_ctx->llm->data_size = size; - cmd_ctx->lttng_msg_size = sizeof(struct lttcomm_lttng_msg) + buf_size; + /* Copy command header */ + if (cmd_header_len) { + memcpy(((uint8_t *) cmd_ctx->llm) + cmd_header_offset, cmd_header_buf, + cmd_header_len); + } - return buf_size; + /* Copy payload */ + if (payload_len) { + memcpy(((uint8_t *) cmd_ctx->llm) + payload_offset, payload_buf, + payload_len); + } -error: +end: return ret; } +/* + * Version of setup_lttng_msg() without command header. + */ +static int setup_lttng_msg_no_cmd_header(struct command_ctx *cmd_ctx, + void *payload_buf, size_t payload_len) +{ + return setup_lttng_msg(cmd_ctx, payload_buf, payload_len, NULL, 0); +} /* * Update the kernel poll set of all channel fd available over all tracing * session. Add the wakeup pipe at the end of the set. @@ -1133,31 +1013,33 @@ static void *thread_manage_kernel(void *data) } /* Check for data on kernel pipe */ - if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) { - (void) lttng_read(kernel_poll_pipe[0], - &tmp, 1); - /* - * Ret value is useless here, if this pipe gets any actions an - * update is required anyway. - */ - update_poll_flag = 1; - continue; - } else { - /* - * New CPU detected by the kernel. Adding kernel stream to - * kernel session and updating the kernel consumer - */ - if (revents & LPOLLIN) { + if (revents & LPOLLIN) { + if (pollfd == kernel_poll_pipe[0]) { + (void) lttng_read(kernel_poll_pipe[0], + &tmp, 1); + /* + * Ret value is useless here, if this pipe gets any actions an + * update is required anyway. + */ + update_poll_flag = 1; + continue; + } else { + /* + * New CPU detected by the kernel. Adding kernel stream to + * kernel session and updating the kernel consumer + */ ret = update_kernel_stream(&kconsumer_data, pollfd); if (ret < 0) { continue; } break; - /* - * TODO: We might want to handle the LPOLLERR | LPOLLHUP - * and unregister kernel stream at this point. - */ } + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + update_poll_flag = 1; + continue; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1213,6 +1095,7 @@ static void *thread_manage_consumer(void *data) enum lttcomm_return_code code; struct lttng_poll_event events; struct consumer_data *consumer_data = data; + struct consumer_socket *cmd_socket_wrapper = NULL; DBG("[thread] Manage consumer started"); @@ -1287,9 +1170,14 @@ restart: /* Event on the registration socket */ if (pollfd == consumer_data->err_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("consumer err socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1317,40 +1205,43 @@ restart: } health_code_update(); - if (code == LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { - /* Connect both socket, command and metadata. */ - consumer_data->cmd_sock = - lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); - consumer_data->metadata_fd = - lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); - if (consumer_data->cmd_sock < 0 - || consumer_data->metadata_fd < 0) { - PERROR("consumer connect cmd socket"); - /* On error, signal condition and quit. */ - signal_consumer_condition(consumer_data, -1); - goto error; - } - consumer_data->metadata_sock.fd_ptr = &consumer_data->metadata_fd; - /* Create metadata socket lock. */ - consumer_data->metadata_sock.lock = zmalloc(sizeof(pthread_mutex_t)); - if (consumer_data->metadata_sock.lock == NULL) { - PERROR("zmalloc pthread mutex"); - ret = -1; - goto error; - } - pthread_mutex_init(consumer_data->metadata_sock.lock, NULL); - - signal_consumer_condition(consumer_data, 1); - DBG("Consumer command socket ready (fd: %d", consumer_data->cmd_sock); - DBG("Consumer metadata socket ready (fd: %d)", - consumer_data->metadata_fd); - } else { + if (code != LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { ERR("consumer error when waiting for SOCK_READY : %s", lttcomm_get_readable_code(-code)); goto error; } - /* Remove the consumerd error sock since we've established a connexion */ + /* Connect both command and metadata sockets. */ + consumer_data->cmd_sock = + lttcomm_connect_unix_sock( + consumer_data->cmd_unix_sock_path); + consumer_data->metadata_fd = + lttcomm_connect_unix_sock( + consumer_data->cmd_unix_sock_path); + if (consumer_data->cmd_sock < 0 || consumer_data->metadata_fd < 0) { + PERROR("consumer connect cmd socket"); + /* On error, signal condition and quit. */ + signal_consumer_condition(consumer_data, -1); + goto error; + } + + consumer_data->metadata_sock.fd_ptr = &consumer_data->metadata_fd; + + /* Create metadata socket lock. */ + consumer_data->metadata_sock.lock = zmalloc(sizeof(pthread_mutex_t)); + if (consumer_data->metadata_sock.lock == NULL) { + PERROR("zmalloc pthread mutex"); + goto error; + } + pthread_mutex_init(consumer_data->metadata_sock.lock, NULL); + + DBG("Consumer command socket ready (fd: %d", consumer_data->cmd_sock); + DBG("Consumer metadata socket ready (fd: %d)", + consumer_data->metadata_fd); + + /* + * Remove the consumerd error sock since we've established a connection. + */ ret = lttng_poll_del(&events, consumer_data->err_sock); if (ret < 0) { goto error; @@ -1371,6 +1262,27 @@ restart: health_code_update(); + /* + * Transfer the write-end of the channel monitoring pipe to the + * by issuing a SET_CHANNEL_MONITOR_PIPE command. + */ + cmd_socket_wrapper = consumer_allocate_socket(&consumer_data->cmd_sock); + if (!cmd_socket_wrapper) { + goto error; + } + + ret = consumer_send_channel_monitor_pipe(cmd_socket_wrapper, + consumer_data->channel_monitor_pipe); + if (ret) { + goto error; + } + /* Discard the socket wrapper as it is no longer needed. */ + consumer_destroy_socket(cmd_socket_wrapper); + cmd_socket_wrapper = NULL; + + /* The thread is completely initialized, signal that it is ready. */ + signal_consumer_condition(consumer_data, 1); + /* Infinite blocking call, waiting for transmission */ restart_poll: while (1) { @@ -1419,7 +1331,8 @@ restart_poll: if (pollfd == sock) { /* Event on the consumerd socket */ - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) + && !(revents & LPOLLIN)) { ERR("consumer err socket second poll error"); goto error; } @@ -1437,6 +1350,11 @@ restart_poll: goto exit; } else if (pollfd == consumer_data->metadata_fd) { + if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) + && !(revents & LPOLLIN)) { + ERR("consumer err metadata socket second poll error"); + goto error; + } /* UST metadata requests */ ret = ust_consumer_metadata_request( &consumer_data->metadata_sock); @@ -1500,7 +1418,6 @@ error: unlink(consumer_data->err_unix_sock_path); unlink(consumer_data->cmd_unix_sock_path); - consumer_data->pid = 0; pthread_mutex_unlock(&consumer_data->lock); /* Cleanup metadata socket mutex. */ @@ -1509,6 +1426,10 @@ error: free(consumer_data->metadata_sock.lock); } lttng_poll_clean(&events); + + if (cmd_socket_wrapper) { + consumer_destroy_socket(cmd_socket_wrapper); + } error_poll: if (err) { health_error(); @@ -1605,10 +1526,7 @@ static void *thread_manage_apps(void *data) /* Inspect the apps cmd pipe */ if (pollfd == apps_cmd_pipe[0]) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Apps command pipe error"); - goto error; - } else if (revents & LPOLLIN) { + if (revents & LPOLLIN) { int sock; /* Empty pipe */ @@ -1621,9 +1539,8 @@ static void *thread_manage_apps(void *data) health_code_update(); /* - * We only monitor the error events of the socket. This - * thread does not handle any incoming data from UST - * (POLLIN). + * Since this is a command socket (write then read), + * we only monitor the error events of the socket. */ ret = lttng_poll_add(&events, sock, LPOLLERR | LPOLLHUP | LPOLLRDHUP); @@ -1632,6 +1549,12 @@ static void *thread_manage_apps(void *data) } DBG("Apps with sock %d added to poll set", sock); + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + ERR("Apps command pipe error"); + goto error; + } else { + ERR("Unknown poll events %u for sock %d", revents, pollfd); + goto error; } } else { /* @@ -1647,6 +1570,9 @@ static void *thread_manage_apps(void *data) /* Socket closed on remote end. */ ust_app_unregister(pollfd); + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } @@ -1787,7 +1713,16 @@ static void sanitize_wait_queue(struct ust_reg_wait_queue *wait_queue) wait_queue->count--; ust_app_destroy(wait_node->app); free(wait_node); + /* + * Silence warning of use-after-free in + * cds_list_for_each_entry_safe which uses + * __typeof__(*wait_node). + */ + wait_node = NULL; break; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1821,6 +1756,8 @@ static void *thread_dispatch_ust_registration(void *data) .count = 0, }; + rcu_register_thread(); + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH); if (testpoint(sessiond_thread_app_reg_dispatch)) { @@ -1833,12 +1770,16 @@ static void *thread_dispatch_ust_registration(void *data) DBG("[thread] Dispatch UST command started"); - while (!CMM_LOAD_SHARED(dispatch_thread_exit)) { + for (;;) { health_code_update(); /* Atomically prepare the queue futex */ futex_nto1_prepare(&ust_cmd_queue.futex); + if (CMM_LOAD_SHARED(dispatch_thread_exit)) { + break; + } + do { struct ust_app *app = NULL; ust_cmd = NULL; @@ -2054,6 +1995,7 @@ error_testpoint: ERR("Health error occurred in %s", __func__); } health_unregister(health_sessiond); + rcu_unregister_thread(); return NULL; } @@ -2148,10 +2090,7 @@ static void *thread_registration_apps(void *data) /* Event on the registration socket */ if (pollfd == apps_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Register apps socket poll error"); - goto error; - } else if (revents & LPOLLIN) { + if (revents & LPOLLIN) { sock = lttcomm_accept_unix_sock(apps_sock); if (sock < 0) { goto error; @@ -2164,10 +2103,12 @@ static void *thread_registration_apps(void *data) * lttcomm_setsockopt_snd_timeout expect msec as * parameter. */ - (void) lttcomm_setsockopt_rcv_timeout(sock, - app_socket_timeout * 1000); - (void) lttcomm_setsockopt_snd_timeout(sock, - app_socket_timeout * 1000); + if (config.app_socket_timeout >= 0) { + (void) lttcomm_setsockopt_rcv_timeout(sock, + config.app_socket_timeout * 1000); + (void) lttcomm_setsockopt_snd_timeout(sock, + config.app_socket_timeout * 1000); + } /* * Set the CLOEXEC flag. Return code is useless because @@ -2238,6 +2179,12 @@ static void *thread_registration_apps(void *data) * barrier with the exchange in cds_wfcq_enqueue. */ futex_nto1_wake(&ust_cmd_queue.futex); + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + ERR("Register apps socket poll error"); + goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -2261,7 +2208,7 @@ error: } lttng_fd_put(LTTNG_FD_APPS, 1); } - unlink(apps_unix_sock_path); + unlink(config.apps_unix_sock_path.value); error_poll_add: lttng_poll_clean(&events); @@ -2287,7 +2234,12 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) int ret, clock_ret; struct timespec timeout; - /* Make sure we set the readiness flag to 0 because we are NOT ready */ + /* + * Make sure we set the readiness flag to 0 because we are NOT ready. + * This access to consumer_thread_is_ready does not need to be + * protected by consumer_data.cond_mutex (yet) since the consumer + * management thread has not been started at this point. + */ consumer_data->consumer_thread_is_ready = 0; /* Setup pthread condition */ @@ -2317,8 +2269,8 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) goto error; } - ret = pthread_create(&consumer_data->thread, NULL, thread_manage_consumer, - consumer_data); + ret = pthread_create(&consumer_data->thread, default_pthread_attr(), + thread_manage_consumer, consumer_data); if (ret) { errno = ret; PERROR("pthread_create consumer"); @@ -2330,7 +2282,7 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) pthread_mutex_lock(&consumer_data->cond_mutex); /* Get time for sem_timedwait absolute timeout */ - clock_ret = clock_gettime(CLOCK_MONOTONIC, &timeout); + clock_ret = lttng_clock_gettime(CLOCK_MONOTONIC, &timeout); /* * Set the timeout for the condition timed wait even if the clock gettime * call fails since we might loop on that call and we want to avoid to @@ -2445,7 +2397,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) /* * Exec consumerd. */ - if (opt_verbose_consumer) { + if (config.verbose_consumer) { verbosity = "--verbose"; } else if (lttng_opt_quiet) { verbosity = "--quiet"; @@ -2461,36 +2413,36 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) * fallback on the 32-bit one, */ DBG3("Looking for a kernel consumer at these locations:"); - DBG3(" 1) %s", consumerd64_bin); - DBG3(" 2) %s/%s", INSTALL_BIN_PATH, CONSUMERD_FILE); - DBG3(" 3) %s", consumerd32_bin); - if (stat(consumerd64_bin, &st) == 0) { + DBG3(" 1) %s", config.consumerd64_bin_path.value); + DBG3(" 2) %s/%s", INSTALL_BIN_PATH, DEFAULT_CONSUMERD_FILE); + DBG3(" 3) %s", config.consumerd32_bin_path.value); + if (stat(config.consumerd64_bin_path.value, &st) == 0) { DBG3("Found location #1"); - consumer_to_use = consumerd64_bin; - } else if (stat(INSTALL_BIN_PATH "/" CONSUMERD_FILE, &st) == 0) { + consumer_to_use = config.consumerd64_bin_path.value; + } else if (stat(INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE, &st) == 0) { DBG3("Found location #2"); - consumer_to_use = INSTALL_BIN_PATH "/" CONSUMERD_FILE; - } else if (stat(consumerd32_bin, &st) == 0) { + consumer_to_use = INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE; + } else if (stat(config.consumerd32_bin_path.value, &st) == 0) { DBG3("Found location #3"); - consumer_to_use = consumerd32_bin; + consumer_to_use = config.consumerd32_bin_path.value; } else { DBG("Could not find any valid consumerd executable"); ret = -EINVAL; - break; + goto error; } DBG("Using kernel consumer at: %s", consumer_to_use); - ret = execl(consumer_to_use, + (void) execl(consumer_to_use, "lttng-consumerd", verbosity, "-k", "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path, "--consumerd-err-sock", consumer_data->err_unix_sock_path, - "--group", tracing_group_name, + "--group", config.tracing_group_name.value, NULL); break; case LTTNG_CONSUMER64_UST: { char *tmpnew = NULL; - if (consumerd64_libdir[0] != '\0') { + if (config.consumerd64_lib_dir.value[0] != '\0') { char *tmp; size_t tmplen; @@ -2499,14 +2451,14 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) tmp = ""; } tmplen = strlen("LD_LIBRARY_PATH=") - + strlen(consumerd64_libdir) + 1 /* : */ + strlen(tmp); + + strlen(config.consumerd64_lib_dir.value) + 1 /* : */ + strlen(tmp); tmpnew = zmalloc(tmplen + 1 /* \0 */); if (!tmpnew) { ret = -ENOMEM; goto error; } strcpy(tmpnew, "LD_LIBRARY_PATH="); - strcat(tmpnew, consumerd64_libdir); + strcat(tmpnew, config.consumerd64_lib_dir.value); if (tmp[0] != '\0') { strcat(tmpnew, ":"); strcat(tmpnew, tmp); @@ -2518,13 +2470,13 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) goto error; } } - DBG("Using 64-bit UST consumer at: %s", consumerd64_bin); - ret = execl(consumerd64_bin, "lttng-consumerd", verbosity, "-u", + DBG("Using 64-bit UST consumer at: %s", config.consumerd64_bin_path.value); + (void) execl(config.consumerd64_bin_path.value, "lttng-consumerd", verbosity, "-u", "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path, "--consumerd-err-sock", consumer_data->err_unix_sock_path, - "--group", tracing_group_name, + "--group", config.tracing_group_name.value, NULL); - if (consumerd64_libdir[0] != '\0') { + if (config.consumerd64_lib_dir.value[0] != '\0') { free(tmpnew); } break; @@ -2533,7 +2485,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) { char *tmpnew = NULL; - if (consumerd32_libdir[0] != '\0') { + if (config.consumerd32_lib_dir.value[0] != '\0') { char *tmp; size_t tmplen; @@ -2542,14 +2494,14 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) tmp = ""; } tmplen = strlen("LD_LIBRARY_PATH=") - + strlen(consumerd32_libdir) + 1 /* : */ + strlen(tmp); + + strlen(config.consumerd32_lib_dir.value) + 1 /* : */ + strlen(tmp); tmpnew = zmalloc(tmplen + 1 /* \0 */); if (!tmpnew) { ret = -ENOMEM; goto error; } strcpy(tmpnew, "LD_LIBRARY_PATH="); - strcat(tmpnew, consumerd32_libdir); + strcat(tmpnew, config.consumerd32_lib_dir.value); if (tmp[0] != '\0') { strcat(tmpnew, ":"); strcat(tmpnew, tmp); @@ -2561,13 +2513,13 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) goto error; } } - DBG("Using 32-bit UST consumer at: %s", consumerd32_bin); - ret = execl(consumerd32_bin, "lttng-consumerd", verbosity, "-u", + DBG("Using 32-bit UST consumer at: %s", config.consumerd32_bin_path.value); + (void) execl(config.consumerd32_bin_path.value, "lttng-consumerd", verbosity, "-u", "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path, "--consumerd-err-sock", consumer_data->err_unix_sock_path, - "--group", tracing_group_name, + "--group", config.tracing_group_name.value, NULL); - if (consumerd32_libdir[0] != '\0') { + if (config.consumerd32_lib_dir.value[0] != '\0') { free(tmpnew); } break; @@ -2666,7 +2618,6 @@ static int init_kernel_tracer(void) kernel_tracer_fd = open(module_proc_lttng, O_RDWR); if (kernel_tracer_fd < 0) { DBG("Failed to open %s", module_proc_lttng); - ret = -1; goto error_open; } @@ -2681,6 +2632,18 @@ static int init_kernel_tracer(void) goto error_modules; } + ret = kernel_supports_ring_buffer_snapshot_sample_positions( + kernel_tracer_fd); + if (ret < 0) { + goto error_modules; + } + + if (ret < 1) { + WARN("Kernel tracer does not support buffer monitoring. " + "The monitoring timer of channels in the kernel domain " + "will be set to 0 (disabled)."); + } + DBG("Kernel tracer fd %d", kernel_tracer_fd); return 0; @@ -2935,6 +2898,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); + assert(!rcu_read_ongoing()); + *sock_error = 0; switch (cmd_ctx->lsm->cmd_type) { @@ -2953,13 +2918,17 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_SNAPSHOT_RECORD: case LTTNG_SAVE_SESSION: case LTTNG_SET_SESSION_SHM_PATH: + case LTTNG_REGENERATE_METADATA: + case LTTNG_REGENERATE_STATEDUMP: + case LTTNG_REGISTER_TRIGGER: + case LTTNG_UNREGISTER_TRIGGER: need_domain = 0; break; default: need_domain = 1; } - if (opt_no_kernel && need_domain + if (config.no_kernel && need_domain && cmd_ctx->lsm->domain.type == LTTNG_DOMAIN_KERNEL) { if (!is_root) { ret = LTTNG_ERR_NEED_ROOT_SESSIOND; @@ -2994,10 +2963,11 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_EVENTS: case LTTNG_LIST_SYSCALLS: case LTTNG_LIST_TRACKER_PIDS: + case LTTNG_DATA_PENDING: break; default: /* Setup lttng message with no payload */ - ret = setup_lttng_msg(cmd_ctx, 0); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, NULL, 0); if (ret < 0) { /* This label does not try to unlock the session */ goto init_setup_error; @@ -3009,12 +2979,13 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_CREATE_SESSION: case LTTNG_CREATE_SESSION_SNAPSHOT: case LTTNG_CREATE_SESSION_LIVE: - case LTTNG_CALIBRATE: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: case LTTNG_LIST_SYSCALLS: case LTTNG_LIST_TRACEPOINT_FIELDS: case LTTNG_SAVE_SESSION: + case LTTNG_REGISTER_TRIGGER: + case LTTNG_UNREGISTER_TRIGGER: need_tracing_session = 0; break; default: @@ -3163,7 +3134,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, /* Start the UST consumer daemons */ /* 64-bit */ pthread_mutex_lock(&ustconsumer64_data.pid_mutex); - if (consumerd64_bin[0] != '\0' && + if (config.consumerd64_bin_path.value && ustconsumer64_data.pid == 0 && cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) { pthread_mutex_unlock(&ustconsumer64_data.pid_mutex); @@ -3192,7 +3163,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, /* 32-bit */ pthread_mutex_lock(&ustconsumer32_data.pid_mutex); - if (consumerd32_bin[0] != '\0' && + if (config.consumerd32_bin_path.value && ustconsumer32_data.pid == 0 && cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) { pthread_mutex_unlock(&ustconsumer32_data.pid_mutex); @@ -3230,6 +3201,8 @@ skip_domain: if (cmd_ctx->lsm->cmd_type == LTTNG_START_TRACE || cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) { switch (cmd_ctx->lsm->domain.type) { + case LTTNG_DOMAIN_NONE: + break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_PYTHON: @@ -3245,6 +3218,9 @@ skip_domain: goto error; } break; + default: + ret = LTTNG_ERR_UNKNOWN_DOMAIN; + goto error; } } @@ -3280,9 +3256,74 @@ skip_domain: switch (cmd_ctx->lsm->cmd_type) { case LTTNG_ADD_CONTEXT: { - ret = cmd_add_context(cmd_ctx->session, cmd_ctx->lsm->domain.type, + /* + * An LTTNG_ADD_CONTEXT command might have a supplementary + * payload if the context being added is an application context. + */ + if (cmd_ctx->lsm->u.context.ctx.ctx == + LTTNG_EVENT_CONTEXT_APP_CONTEXT) { + char *provider_name = NULL, *context_name = NULL; + size_t provider_name_len = + cmd_ctx->lsm->u.context.provider_name_len; + size_t context_name_len = + cmd_ctx->lsm->u.context.context_name_len; + + if (provider_name_len == 0 || context_name_len == 0) { + /* + * Application provider and context names MUST + * be provided. + */ + ret = -LTTNG_ERR_INVALID; + goto error; + } + + provider_name = zmalloc(provider_name_len + 1); + if (!provider_name) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = + provider_name; + + context_name = zmalloc(context_name_len + 1); + if (!context_name) { + ret = -LTTNG_ERR_NOMEM; + goto error_add_context; + } + cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = + context_name; + + ret = lttcomm_recv_unix_sock(sock, provider_name, + provider_name_len); + if (ret < 0) { + goto error_add_context; + } + + ret = lttcomm_recv_unix_sock(sock, context_name, + context_name_len); + if (ret < 0) { + goto error_add_context; + } + } + + /* + * cmd_add_context assumes ownership of the provider and context + * names. + */ + ret = cmd_add_context(cmd_ctx->session, + cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.context.channel_name, - &cmd_ctx->lsm->u.context.ctx, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.context.ctx, + kernel_poll_pipe[1]); + + cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = NULL; + cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = NULL; +error_add_context: + free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name); + free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name); + if (ret < 0) { + goto error; + } break; } case LTTNG_DISABLE_CHANNEL: @@ -3328,8 +3369,11 @@ skip_domain: } case LTTNG_ENABLE_CHANNEL: { + cmd_ctx->lsm->u.channel.chan.attr.extended.ptr = + (struct lttng_channel_extended *) &cmd_ctx->lsm->u.channel.extended; ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain, - &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.channel.chan, + kernel_poll_pipe[1]); break; } case LTTNG_TRACK_PID: @@ -3474,18 +3518,14 @@ skip_domain: * Setup lttng message with payload size set to the event list size in * bytes and then copy list into the llm payload. */ - ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event) * nb_events); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, + sizeof(struct lttng_event) * nb_events); + free(events); + if (ret < 0) { - free(events); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, events, - sizeof(struct lttng_event) * nb_events); - - free(events); - ret = LTTNG_OK; break; } @@ -3508,19 +3548,14 @@ skip_domain: * Setup lttng message with payload size set to the event list size in * bytes and then copy list into the llm payload. */ - ret = setup_lttng_msg(cmd_ctx, + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, fields, sizeof(struct lttng_event_field) * nb_fields); + free(fields); + if (ret < 0) { - free(fields); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, fields, - sizeof(struct lttng_event_field) * nb_fields); - - free(fields); - ret = LTTNG_OK; break; } @@ -3540,18 +3575,14 @@ skip_domain: * Setup lttng message with payload size set to the event list size in * bytes and then copy list into the llm payload. */ - ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event) * nb_events); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, + sizeof(struct lttng_event) * nb_events); + free(events); + if (ret < 0) { - free(events); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, events, - sizeof(struct lttng_event) * nb_events); - - free(events); - ret = LTTNG_OK; break; } @@ -3572,18 +3603,14 @@ skip_domain: * Setup lttng message with payload size set to the event list size in * bytes and then copy list into the llm payload. */ - ret = setup_lttng_msg(cmd_ctx, sizeof(int32_t) * nr_pids); - if (ret < 0) { - free(pids); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, pids, + sizeof(int32_t) * nr_pids); + free(pids); + + if (ret < 0) { goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, pids, - sizeof(int) * nr_pids); - - free(pids); - ret = LTTNG_OK; break; } @@ -3697,46 +3724,38 @@ skip_domain: goto error; } - ret = setup_lttng_msg(cmd_ctx, nb_dom * sizeof(struct lttng_domain)); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, domains, + nb_dom * sizeof(struct lttng_domain)); + free(domains); + if (ret < 0) { - free(domains); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, domains, - nb_dom * sizeof(struct lttng_domain)); - - free(domains); - ret = LTTNG_OK; break; } case LTTNG_LIST_CHANNELS: { - int nb_chan; + ssize_t payload_size; struct lttng_channel *channels = NULL; - nb_chan = cmd_list_channels(cmd_ctx->lsm->domain.type, + payload_size = cmd_list_channels(cmd_ctx->lsm->domain.type, cmd_ctx->session, &channels); - if (nb_chan < 0) { + if (payload_size < 0) { /* Return value is a negative lttng_error_code. */ - ret = -nb_chan; + ret = -payload_size; goto error; } - ret = setup_lttng_msg(cmd_ctx, nb_chan * sizeof(struct lttng_channel)); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels, + payload_size); + free(channels); + if (ret < 0) { - free(channels); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, channels, - nb_chan * sizeof(struct lttng_channel)); - - free(channels); - ret = LTTNG_OK; break; } @@ -3744,61 +3763,68 @@ skip_domain: { ssize_t nb_event; struct lttng_event *events = NULL; + struct lttcomm_event_command_header cmd_header; + size_t total_size; + + memset(&cmd_header, 0, sizeof(cmd_header)); + /* Extended infos are included at the end of events */ + nb_event = cmd_list_events(cmd_ctx->lsm->domain.type, + cmd_ctx->session, cmd_ctx->lsm->u.list.channel_name, + &events, &total_size); - nb_event = cmd_list_events(cmd_ctx->lsm->domain.type, cmd_ctx->session, - cmd_ctx->lsm->u.list.channel_name, &events); if (nb_event < 0) { /* Return value is a negative lttng_error_code. */ ret = -nb_event; goto error; } - ret = setup_lttng_msg(cmd_ctx, nb_event * sizeof(struct lttng_event)); + cmd_header.nb_events = nb_event; + ret = setup_lttng_msg(cmd_ctx, events, total_size, + &cmd_header, sizeof(cmd_header)); + free(events); + if (ret < 0) { - free(events); goto setup_error; } - /* Copy event list into message payload */ - memcpy(cmd_ctx->llm->payload, events, - nb_event * sizeof(struct lttng_event)); - - free(events); - ret = LTTNG_OK; break; } case LTTNG_LIST_SESSIONS: { unsigned int nr_sessions; + void *sessions_payload; + size_t payload_len; session_lock_list(); nr_sessions = lttng_sessions_count( LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); + payload_len = sizeof(struct lttng_session) * nr_sessions; + sessions_payload = zmalloc(payload_len); - ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_session) * nr_sessions); - if (ret < 0) { + if (!sessions_payload) { session_unlock_list(); + ret = -ENOMEM; goto setup_error; } - /* Filled the session array */ - cmd_list_lttng_sessions((struct lttng_session *)(cmd_ctx->llm->payload), + cmd_list_lttng_sessions(sessions_payload, LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - session_unlock_list(); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, sessions_payload, + payload_len); + free(sessions_payload); + + if (ret < 0) { + goto setup_error; + } + ret = LTTNG_OK; break; } - case LTTNG_CALIBRATE: - { - ret = cmd_calibrate(cmd_ctx->lsm->domain.type, - &cmd_ctx->lsm->u.calibrate); - break; - } case LTTNG_REGISTER_CONSUMER: { struct consumer_data *cdata; @@ -3819,14 +3845,10 @@ skip_domain: case LTTNG_DATA_PENDING: { int pending_ret; - - /* 1 byte to return whether or not data is pending */ - ret = setup_lttng_msg(cmd_ctx, 1); - if (ret < 0) { - goto setup_error; - } + uint8_t pending_ret_byte; pending_ret = cmd_data_pending(cmd_ctx->session); + /* * FIXME * @@ -3837,7 +3859,10 @@ skip_domain: * "unknown" error. */ if (pending_ret == 0 || pending_ret == 1) { - ret = LTTNG_OK; + /* + * ret will be set to LTTNG_OK at the end of + * this function. + */ } else if (pending_ret < 0) { ret = LTTNG_ERR_UNK; goto setup_error; @@ -3846,7 +3871,17 @@ skip_domain: goto setup_error; } - *cmd_ctx->llm->payload = (uint8_t) pending_ret; + pending_ret_byte = (uint8_t) pending_ret; + + /* 1 byte to return whether or not data is pending */ + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, + &pending_ret_byte, 1); + + if (ret < 0) { + goto setup_error; + } + + ret = LTTNG_OK; break; } case LTTNG_SNAPSHOT_ADD_OUTPUT: @@ -3859,13 +3894,13 @@ skip_domain: goto error; } - ret = setup_lttng_msg(cmd_ctx, sizeof(reply)); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &reply, + sizeof(reply)); if (ret < 0) { goto setup_error; } /* Copy output list into message payload */ - memcpy(cmd_ctx->llm->payload, &reply, sizeof(reply)); ret = LTTNG_OK; break; } @@ -3886,20 +3921,15 @@ skip_domain: goto error; } - ret = setup_lttng_msg(cmd_ctx, + assert((nb_output > 0 && outputs) || nb_output == 0); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, outputs, nb_output * sizeof(struct lttng_snapshot_output)); + free(outputs); + if (ret < 0) { - free(outputs); goto setup_error; } - if (outputs) { - /* Copy output list into message payload */ - memcpy(cmd_ctx->llm->payload, outputs, - nb_output * sizeof(struct lttng_snapshot_output)); - free(outputs); - } - ret = LTTNG_OK; break; } @@ -4000,6 +4030,28 @@ skip_domain: cmd_ctx->lsm->u.set_shm_path.shm_path); break; } + case LTTNG_REGENERATE_METADATA: + { + ret = cmd_regenerate_metadata(cmd_ctx->session); + break; + } + case LTTNG_REGENERATE_STATEDUMP: + { + ret = cmd_regenerate_statedump(cmd_ctx->session); + break; + } + case LTTNG_REGISTER_TRIGGER: + { + ret = cmd_register_trigger(cmd_ctx, sock, + notification_thread_handle); + break; + } + case LTTNG_UNREGISTER_TRIGGER: + { + ret = cmd_unregister_trigger(cmd_ctx, sock, + notification_thread_handle); + break; + } default: ret = LTTNG_ERR_UND; break; @@ -4008,7 +4060,7 @@ skip_domain: error: if (cmd_ctx->llm == NULL) { DBG("Missing llm structure. Allocating one."); - if (setup_lttng_msg(cmd_ctx, 0) < 0) { + if (setup_lttng_msg_no_cmd_header(cmd_ctx, NULL, 0) < 0) { goto setup_error; } } @@ -4022,6 +4074,7 @@ setup_error: session_unlock_list(); } init_setup_error: + assert(!rcu_read_ongoing()); return ret; } @@ -4044,30 +4097,27 @@ static void *thread_manage_health(void *data) lttng_poll_init(&events); /* Create unix socket */ - sock = lttcomm_create_unix_sock(health_unix_sock_path); + sock = lttcomm_create_unix_sock(config.health_unix_sock_path.value); if (sock < 0) { ERR("Unable to create health check Unix socket"); - ret = -1; goto error; } if (is_root) { /* lttng health client socket path permissions */ - ret = chown(health_unix_sock_path, 0, - utils_get_group_id(tracing_group_name)); + ret = chown(config.health_unix_sock_path.value, 0, + utils_get_group_id(config.tracing_group_name.value)); if (ret < 0) { - ERR("Unable to set group on %s", health_unix_sock_path); + ERR("Unable to set group on %s", config.health_unix_sock_path.value); PERROR("chown"); - ret = -1; goto error; } - ret = chmod(health_unix_sock_path, + ret = chmod(config.health_unix_sock_path.value, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret < 0) { - ERR("Unable to set permissions on %s", health_unix_sock_path); + ERR("Unable to set permissions on %s", config.health_unix_sock_path.value); PERROR("chmod"); - ret = -1; goto error; } } @@ -4137,9 +4187,14 @@ restart: /* Event on the registration socket */ if (pollfd == sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("Health socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -4163,7 +4218,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; continue; } @@ -4192,7 +4246,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; } exit: @@ -4201,7 +4254,7 @@ error: ERR("Health error occurred in %s", __func__); } DBG("Health check thread dying"); - unlink(health_unix_sock_path); + unlink(config.health_unix_sock_path.value); if (sock >= 0) { ret = close(sock); if (ret) { @@ -4210,7 +4263,7 @@ error: } lttng_poll_clean(&events); - + stop_threads(); rcu_unregister_thread(); return NULL; } @@ -4314,9 +4367,14 @@ static void *thread_manage_clients(void *data) /* Event on the registration socket */ if (pollfd == client_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("Client socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -4448,7 +4506,7 @@ error: error_listen: error_create_poll: - unlink(client_unix_sock_path); + unlink(config.client_unix_sock_path.value); if (client_sock >= 0) { ret = close(client_sock); if (ret) { @@ -4491,43 +4549,6 @@ error_create_poll: return NULL; } - -/* - * usage function on stderr - */ -static void usage(void) -{ - fprintf(stderr, "Usage: %s OPTIONS\n\nOptions:\n", progname); - fprintf(stderr, " -h, --help Display this usage.\n"); - fprintf(stderr, " -c, --client-sock PATH Specify path for the client unix socket\n"); - fprintf(stderr, " -a, --apps-sock PATH Specify path for apps unix socket\n"); - fprintf(stderr, " --kconsumerd-err-sock PATH Specify path for the kernel consumer error socket\n"); - fprintf(stderr, " --kconsumerd-cmd-sock PATH Specify path for the kernel consumer command socket\n"); - fprintf(stderr, " --ustconsumerd32-err-sock PATH Specify path for the 32-bit UST consumer error socket\n"); - fprintf(stderr, " --ustconsumerd64-err-sock PATH Specify path for the 64-bit UST consumer error socket\n"); - fprintf(stderr, " --ustconsumerd32-cmd-sock PATH Specify path for the 32-bit UST consumer command socket\n"); - fprintf(stderr, " --ustconsumerd64-cmd-sock PATH Specify path for the 64-bit UST consumer command socket\n"); - fprintf(stderr, " --consumerd32-path PATH Specify path for the 32-bit UST consumer daemon binary\n"); - fprintf(stderr, " --consumerd32-libdir PATH Specify path for the 32-bit UST consumer daemon libraries\n"); - fprintf(stderr, " --consumerd64-path PATH Specify path for the 64-bit UST consumer daemon binary\n"); - fprintf(stderr, " --consumerd64-libdir PATH Specify path for the 64-bit UST consumer daemon libraries\n"); - fprintf(stderr, " -d, --daemonize Start as a daemon.\n"); - fprintf(stderr, " -b, --background Start as a daemon, keeping console open.\n"); - fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n"); - fprintf(stderr, " -V, --version Show version number.\n"); - fprintf(stderr, " -S, --sig-parent Send SIGUSR1 to parent pid to notify readiness.\n"); - fprintf(stderr, " -q, --quiet No output at all.\n"); - fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); - fprintf(stderr, " -p, --pidfile FILE Write a pid to FILE name overriding the default value.\n"); - fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n"); - fprintf(stderr, " --no-kernel Disable kernel tracer\n"); - fprintf(stderr, " --agent-tcp-port Agent registration TCP port\n"); - fprintf(stderr, " -f --config PATH Load daemon configuration file\n"); - fprintf(stderr, " -l --load PATH Load session configuration\n"); - fprintf(stderr, " --kmod-probes Specify kernel module probes to load\n"); - fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n"); -} - static int string_match(const char *str1, const char *str2) { return (str1 && str2) && !strcmp(str1, str2); @@ -4543,210 +4564,278 @@ static int set_option(int opt, const char *arg, const char *optname) { int ret = 0; - if (arg && arg[0] == '\0') { - /* - * This only happens if the value is read from daemon config - * file. This means the option requires an argument and the - * configuration file contains a line such as: - * my_option = - */ - ret = -EINVAL; - goto end; - } - if (string_match(optname, "client-sock") || opt == 'c') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-c, --client-sock"); } else { - snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.client_unix_sock_path, + strdup(arg)); + if (!config.client_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "apps-sock") || opt == 'a') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-a, --apps-sock"); } else { - snprintf(apps_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.apps_unix_sock_path, + strdup(arg)); + if (!config.apps_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "daemonize") || opt == 'd') { - opt_daemon = 1; + config.daemonize = true; } else if (string_match(optname, "background") || opt == 'b') { - opt_background = 1; + config.background = true; } else if (string_match(optname, "group") || opt == 'g') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-g, --group"); } else { - /* - * If the override option is set, the pointer points to a - * *non* const thus freeing it even though the variable type is - * set to const. - */ - if (tracing_group_name_override) { - free((void *) tracing_group_name); - } - tracing_group_name = strdup(arg); - if (!tracing_group_name) { - PERROR("strdup"); + config_string_set(&config.tracing_group_name, + strdup(arg)); + if (!config.tracing_group_name.value) { ret = -ENOMEM; + PERROR("strdup"); } - tracing_group_name_override = 1; } } else if (string_match(optname, "help") || opt == 'h') { - usage(); - exit(EXIT_SUCCESS); + ret = utils_show_help(8, "lttng-sessiond", help_msg); + if (ret) { + ERR("Cannot show --help for `lttng-sessiond`"); + perror("exec"); + } + exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else if (string_match(optname, "version") || opt == 'V') { fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); } else if (string_match(optname, "sig-parent") || opt == 'S') { - opt_sig_parent = 1; + config.sig_parent = true; } else if (string_match(optname, "kconsumerd-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-err-sock"); } else { - snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.kconsumerd_err_unix_sock_path, + strdup(arg)); + if (!config.kconsumerd_err_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "kconsumerd-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-cmd-sock"); } else { - snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.kconsumerd_cmd_unix_sock_path, + strdup(arg)); + if (!config.kconsumerd_cmd_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "ustconsumerd64-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-err-sock"); } else { - snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.consumerd64_err_unix_sock_path, + strdup(arg)); + if (!config.consumerd64_err_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "ustconsumerd64-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-cmd-sock"); } else { - snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.consumerd64_cmd_unix_sock_path, + strdup(arg)); + if (!config.consumerd64_cmd_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "ustconsumerd32-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-err-sock"); } else { - snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.consumerd32_err_unix_sock_path, + strdup(arg)); + if (!config.consumerd32_err_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "ustconsumerd32-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-cmd-sock"); } else { - snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + config_string_set(&config.consumerd32_cmd_unix_sock_path, + strdup(arg)); + if (!config.consumerd32_cmd_unix_sock_path.value) { + ret = -ENOMEM; + PERROR("strdup"); + } } } else if (string_match(optname, "no-kernel")) { - opt_no_kernel = 1; + config.no_kernel = true; } else if (string_match(optname, "quiet") || opt == 'q') { - lttng_opt_quiet = 1; + lttng_opt_quiet = true; } else if (string_match(optname, "verbose") || opt == 'v') { /* Verbose level can increase using multiple -v */ if (arg) { /* Value obtained from config file */ - lttng_opt_verbose = config_parse_value(arg); + config.verbose = config_parse_value(arg); } else { /* -v used on command line */ - lttng_opt_verbose++; + config.verbose++; } /* Clamp value to [0, 3] */ - lttng_opt_verbose = lttng_opt_verbose < 0 ? 0 : - (lttng_opt_verbose <= 3 ? lttng_opt_verbose : 3); + config.verbose = config.verbose < 0 ? 0 : + (config.verbose <= 3 ? config.verbose : 3); } else if (string_match(optname, "verbose-consumer")) { if (arg) { - opt_verbose_consumer = config_parse_value(arg); + config.verbose_consumer = config_parse_value(arg); } else { - opt_verbose_consumer += 1; + config.verbose_consumer++; } } else if (string_match(optname, "consumerd32-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-path"); } else { - if (consumerd32_bin_override) { - free((void *) consumerd32_bin); - } - consumerd32_bin = strdup(arg); - if (!consumerd32_bin) { + config_string_set(&config.consumerd32_bin_path, + strdup(arg)); + if (!config.consumerd32_bin_path.value) { PERROR("strdup"); ret = -ENOMEM; } - consumerd32_bin_override = 1; } } else if (string_match(optname, "consumerd32-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-libdir"); } else { - if (consumerd32_libdir_override) { - free((void *) consumerd32_libdir); - } - consumerd32_libdir = strdup(arg); - if (!consumerd32_libdir) { + config_string_set(&config.consumerd32_lib_dir, + strdup(arg)); + if (!config.consumerd32_lib_dir.value) { PERROR("strdup"); ret = -ENOMEM; } - consumerd32_libdir_override = 1; } } else if (string_match(optname, "consumerd64-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-path"); } else { - if (consumerd64_bin_override) { - free((void *) consumerd64_bin); - } - consumerd64_bin = strdup(arg); - if (!consumerd64_bin) { + config_string_set(&config.consumerd64_bin_path, + strdup(arg)); + if (!config.consumerd64_bin_path.value) { PERROR("strdup"); ret = -ENOMEM; } - consumerd64_bin_override = 1; } } else if (string_match(optname, "consumerd64-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-libdir"); } else { - if (consumerd64_libdir_override) { - free((void *) consumerd64_libdir); - } - consumerd64_libdir = strdup(arg); - if (!consumerd64_libdir) { + config_string_set(&config.consumerd64_lib_dir, + strdup(arg)); + if (!config.consumerd64_lib_dir.value) { PERROR("strdup"); ret = -ENOMEM; } - consumerd64_libdir_override = 1; } } else if (string_match(optname, "pidfile") || opt == 'p') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-p, --pidfile"); } else { - free(opt_pidfile); - opt_pidfile = strdup(arg); - if (!opt_pidfile) { + config_string_set(&config.pid_file_path, strdup(arg)); + if (!config.pid_file_path.value) { PERROR("strdup"); ret = -ENOMEM; } } } else if (string_match(optname, "agent-tcp-port")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--agent-tcp-port"); } else { unsigned long v; - if (!arg) { - ret = -EINVAL; - goto end; - } errno = 0; v = strtoul(arg, NULL, 0); if (errno != 0 || !isdigit(arg[0])) { @@ -4757,41 +4846,51 @@ static int set_option(int opt, const char *arg, const char *optname) ERR("Port overflow in --agent-tcp-port parameter: %s", arg); return -1; } - agent_tcp_port = (uint32_t) v; - DBG3("Agent TCP port set to non default: %u", agent_tcp_port); + config.agent_tcp_port = (uint32_t) v; + DBG3("Agent TCP port set to non default: %u", config.agent_tcp_port); } } else if (string_match(optname, "load") || opt == 'l') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-l, --load"); } else { - free(opt_load_session_path); - opt_load_session_path = strdup(arg); - if (!opt_load_session_path) { + config_string_set(&config.load_session_path, strdup(arg)); + if (!config.load_session_path.value) { PERROR("strdup"); ret = -ENOMEM; } } } else if (string_match(optname, "kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kmod-probes"); } else { - free(kmod_probes_list); - kmod_probes_list = strdup(arg); - if (!kmod_probes_list) { + config_string_set(&config.kmod_probes_list, strdup(arg)); + if (!config.kmod_probes_list.value) { PERROR("strdup"); ret = -ENOMEM; } } } else if (string_match(optname, "extra-kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--extra-kmod-probes"); } else { - free(kmod_extra_probes_list); - kmod_extra_probes_list = strdup(arg); - if (!kmod_extra_probes_list) { + config_string_set(&config.kmod_extra_probes_list, + strdup(arg)); + if (!config.kmod_extra_probes_list.value) { PERROR("strdup"); ret = -ENOMEM; } @@ -4827,7 +4926,7 @@ end: /* * config_entry_handler_cb used to handle options read from a config file. - * See config_entry_handler_cb comment in common/config/config.h for the + * See config_entry_handler_cb comment in common/config/session-config.h for the * return value conventions. */ static int config_entry_handler(const struct config_entry *entry, void *unused) @@ -4975,9 +5074,9 @@ static int init_daemon_socket(void) old_umask = umask(0); /* Create client tool unix socket */ - client_sock = lttcomm_create_unix_sock(client_unix_sock_path); + client_sock = lttcomm_create_unix_sock(config.client_unix_sock_path.value); if (client_sock < 0) { - ERR("Create unix sock failed: %s", client_unix_sock_path); + ERR("Create unix sock failed: %s", config.client_unix_sock_path.value); ret = -1; goto end; } @@ -4991,17 +5090,17 @@ static int init_daemon_socket(void) } /* File permission MUST be 660 */ - ret = chmod(client_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + ret = chmod(config.client_unix_sock_path.value, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret < 0) { - ERR("Set file permissions failed: %s", client_unix_sock_path); + ERR("Set file permissions failed: %s", config.client_unix_sock_path.value); PERROR("chmod"); goto end; } /* Create the application unix socket */ - apps_sock = lttcomm_create_unix_sock(apps_unix_sock_path); + apps_sock = lttcomm_create_unix_sock(config.apps_unix_sock_path.value); if (apps_sock < 0) { - ERR("Create unix sock failed: %s", apps_unix_sock_path); + ERR("Create unix sock failed: %s", config.apps_unix_sock_path.value); ret = -1; goto end; } @@ -5015,10 +5114,10 @@ static int init_daemon_socket(void) } /* File permission MUST be 666 */ - ret = chmod(apps_unix_sock_path, + ret = chmod(config.apps_unix_sock_path.value, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (ret < 0) { - ERR("Set file permissions failed: %s", apps_unix_sock_path); + ERR("Set file permissions failed: %s", config.apps_unix_sock_path.value); PERROR("chmod"); goto end; } @@ -5056,7 +5155,7 @@ static int set_permissions(char *rundir) int ret; gid_t gid; - gid = utils_get_group_id(tracing_group_name); + gid = utils_get_group_id(config.tracing_group_name.value); /* Set lttng run dir */ ret = chown(rundir, 0, gid); @@ -5077,9 +5176,9 @@ static int set_permissions(char *rundir) } /* lttng client socket path */ - ret = chown(client_unix_sock_path, 0, gid); + ret = chown(config.client_unix_sock_path.value, 0, gid); if (ret < 0) { - ERR("Unable to set group on %s", client_unix_sock_path); + ERR("Unable to set group on %s", config.client_unix_sock_path.value); PERROR("chown"); } @@ -5112,16 +5211,16 @@ static int set_permissions(char *rundir) /* * Create the lttng run directory needed for all global sockets and pipe. */ -static int create_lttng_rundir(const char *rundir) +static int create_lttng_rundir(void) { int ret; - DBG3("Creating LTTng run directory: %s", rundir); + DBG3("Creating LTTng run directory: %s", config.rundir.value); - ret = mkdir(rundir, S_IRWXU); + ret = mkdir(config.rundir.value, S_IRWXU); if (ret < 0) { if (errno != EEXIST) { - ERR("Unable to create %s", rundir); + ERR("Unable to create %s", config.rundir.value); goto error; } else { ret = 0; @@ -5133,44 +5232,41 @@ error: } /* - * Setup sockets and directory needed by the kconsumerd communication with the + * Setup sockets and directory needed by the consumerds' communication with the * session daemon. */ -static int set_consumer_sockets(struct consumer_data *consumer_data, - const char *rundir) +static int set_consumer_sockets(struct consumer_data *consumer_data) { int ret; - char path[PATH_MAX]; + char *path = NULL; switch (consumer_data->type) { case LTTNG_CONSUMER_KERNEL: - snprintf(path, PATH_MAX, DEFAULT_KCONSUMERD_PATH, rundir); + path = config.kconsumerd_path.value; break; case LTTNG_CONSUMER64_UST: - snprintf(path, PATH_MAX, DEFAULT_USTCONSUMERD64_PATH, rundir); + path = config.consumerd64_path.value; break; case LTTNG_CONSUMER32_UST: - snprintf(path, PATH_MAX, DEFAULT_USTCONSUMERD32_PATH, rundir); + path = config.consumerd32_path.value; break; default: ERR("Consumer type unknown"); ret = -EINVAL; goto error; } + assert(path); DBG2("Creating consumer directory: %s", path); ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP); - if (ret < 0) { - if (errno != EEXIST) { - PERROR("mkdir"); - ERR("Failed to create %s", path); - goto error; - } - ret = -1; + if (ret < 0 && errno != EEXIST) { + PERROR("mkdir"); + ERR("Failed to create %s", path); + goto error; } if (is_root) { - ret = chown(path, 0, utils_get_group_id(tracing_group_name)); + ret = chown(path, 0, utils_get_group_id(config.tracing_group_name.value)); if (ret < 0) { ERR("Unable to set group on %s", path); PERROR("chown"); @@ -5178,7 +5274,7 @@ static int set_consumer_sockets(struct consumer_data *consumer_data, } } - /* Create the kconsumerd error unix socket */ + /* Create the consumerd error unix socket */ consumer_data->err_sock = lttcomm_create_unix_sock(consumer_data->err_unix_sock_path); if (consumer_data->err_sock < 0) { @@ -5219,9 +5315,6 @@ error: static void sighandler(int sig) { switch (sig) { - case SIGPIPE: - DBG("SIGPIPE caught"); - return; case SIGINT: DBG("SIGINT caught"); stop_threads(); @@ -5253,9 +5346,10 @@ static int set_signal_handler(void) return ret; } - sa.sa_handler = sighandler; sa.sa_mask = sigset; sa.sa_flags = 0; + + sa.sa_handler = sighandler; if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; @@ -5266,12 +5360,13 @@ static int set_signal_handler(void) return ret; } - if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } - if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + sa.sa_handler = SIG_IGN; + if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } @@ -5283,14 +5378,14 @@ static int set_signal_handler(void) /* * Set open files limit to unlimited. This daemon can open a large number of - * file descriptors in order to consumer multiple kernel traces. + * file descriptors in order to consume multiple kernel traces. */ static void set_ulimit(void) { int ret; struct rlimit lim; - /* The kernel does not allowed an infinite limit for open files */ + /* The kernel does not allow an infinite limit for open files */ lim.rlim_cur = 65535; lim.rlim_max = 65535; @@ -5300,34 +5395,9 @@ static void set_ulimit(void) } } -/* - * Write pidfile using the rundir and opt_pidfile. - */ static int write_pidfile(void) { - int ret; - char pidfile_path[PATH_MAX]; - - assert(rundir); - - if (opt_pidfile) { - strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path)); - } else { - /* Build pidfile path from rundir and opt_pidfile. */ - ret = snprintf(pidfile_path, sizeof(pidfile_path), "%s/" - DEFAULT_LTTNG_SESSIOND_PIDFILE, rundir); - if (ret < 0) { - PERROR("snprintf pidfile path"); - goto error; - } - } - - /* - * Create pid file in rundir. - */ - ret = utils_create_pid_file(getpid(), pidfile_path); -error: - return ret; + return utils_create_pid_file(getpid(), config.pid_file_path.value); } /* @@ -5335,17 +5405,7 @@ error: */ static int create_lockfile(void) { - int ret; - char lockfile_path[PATH_MAX]; - - ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path)); - if (ret < 0) { - goto error; - } - - ret = utils_create_lock_file(lockfile_path); -error: - return ret; + return utils_create_lock_file(config.lock_file_path.value); } /* @@ -5353,24 +5413,36 @@ error: */ static int write_agent_port(void) { - int ret; - char path[PATH_MAX]; + return utils_create_pid_file(config.agent_tcp_port, + config.agent_port_file_path.value); +} + +static int set_clock_plugin_env(void) +{ + int ret = 0; + char *env_value = NULL; - assert(rundir); + if (!config.lttng_ust_clock_plugin.value) { + goto end; + } - ret = snprintf(path, sizeof(path), "%s/" - DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE, rundir); + ret = asprintf(&env_value, "LTTNG_UST_CLOCK_PLUGIN=%s", + config.lttng_ust_clock_plugin.value); if (ret < 0) { - PERROR("snprintf agent port path"); - goto error; + PERROR("asprintf"); + goto end; } - /* - * Create TCP agent port file in rundir. - */ - ret = utils_create_pid_file(agent_tcp_port, path); + ret = putenv(env_value); + if (ret) { + free(env_value); + PERROR("putenv of LTTNG_UST_CLOCK_PLUGIN"); + goto end; + } -error: + DBG("Updated LTTNG_UST_CLOCK_PLUGIN environment variable to \"%s\"", + config.lttng_ust_clock_plugin.value); +end: return ret; } @@ -5381,7 +5453,11 @@ int main(int argc, char **argv) { int ret = 0, retval = 0; void *status; - const char *home_path, *env_app_timeout; + const char *env_app_timeout; + struct lttng_pipe *ust32_channel_monitor_pipe = NULL, + *ust64_channel_monitor_pipe = NULL, + *kernel_channel_monitor_pipe = NULL; + bool notification_thread_running = false; init_kernel_workarounds(); @@ -5392,8 +5468,6 @@ int main(int argc, char **argv) goto exit_set_signal_handler; } - setup_consumerd_path(); - page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) { PERROR("sysconf _SC_PAGESIZE"); @@ -5401,6 +5475,12 @@ int main(int argc, char **argv) WARN("Fallback page size to %ld", page_size); } + ret = sessiond_config_init(&config); + if (ret) { + retval = -1; + goto exit_set_signal_handler; + } + /* * Parse arguments and load the daemon configuration file. * @@ -5415,12 +5495,45 @@ int main(int argc, char **argv) goto exit_options; } + /* Init config from environment variables. */ + sessiond_config_apply_env_config(&config); + + /* + * Resolve all paths received as arguments, configuration option, or + * through environment variable as absolute paths. This is necessary + * since daemonizing causes the sessiond's current working directory + * to '/'. + */ + ret = sessiond_config_resolve_paths(&config); + if (ret) { + goto exit_options; + } + + /* Apply config. */ + lttng_opt_verbose = config.verbose; + lttng_opt_quiet = config.quiet; + kconsumer_data.err_unix_sock_path = + config.kconsumerd_err_unix_sock_path.value; + kconsumer_data.cmd_unix_sock_path = + config.kconsumerd_cmd_unix_sock_path.value; + ustconsumer32_data.err_unix_sock_path = + config.consumerd32_err_unix_sock_path.value; + ustconsumer32_data.cmd_unix_sock_path = + config.consumerd32_cmd_unix_sock_path.value; + ustconsumer64_data.err_unix_sock_path = + config.consumerd64_err_unix_sock_path.value; + ustconsumer64_data.cmd_unix_sock_path = + config.consumerd64_cmd_unix_sock_path.value; + set_clock_plugin_env(); + + sessiond_config_log(&config); + /* Daemonize */ - if (opt_daemon || opt_background) { + if (config.daemonize || config.background) { int i; ret = lttng_daemonize(&child_ppid, &recv_child_signal, - !opt_background); + !config.background); if (ret < 0) { retval = -1; goto exit_options; @@ -5436,6 +5549,10 @@ int main(int argc, char **argv) } } + if (run_as_create_worker(argv[0]) < 0) { + goto exit_create_run_as_worker_cleanup; + } + /* * Starting from here, we can create threads. This needs to be after * lttng_daemonize due to RCU. @@ -5452,29 +5569,8 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - if (init_ht_cleanup_quit_pipe()) { - retval = -1; - goto exit_ht_cleanup_quit_pipe; - } - - /* Setup the thread ht_cleanup communication pipe. */ - if (utils_create_pipe_cloexec(ht_cleanup_pipe)) { - retval = -1; - goto exit_ht_cleanup_pipe; - } - - /* Set up max poll set size */ - if (lttng_poll_set_max_size()) { - retval = -1; - goto exit_set_max_size; - } - /* Create thread to clean up RCU hash tables */ - ret = pthread_create(&ht_cleanup_thread, NULL, - thread_ht_cleanup, (void *) NULL); - if (ret) { - errno = ret; - PERROR("pthread_create ht_cleanup"); + if (init_ht_cleanup_thread(&ht_cleanup_thread)) { retval = -1; goto exit_ht_cleanup; } @@ -5489,141 +5585,25 @@ int main(int argc, char **argv) is_root = !getuid(); if (is_root) { - rundir = strdup(DEFAULT_LTTNG_RUNDIR); - if (!rundir) { - retval = -1; - goto exit_init_data; - } - /* Create global run dir with root access */ - if (create_lttng_rundir(rundir)) { + if (create_lttng_rundir()) { retval = -1; goto exit_init_data; } - if (strlen(apps_unix_sock_path) == 0) { - ret = snprintf(apps_unix_sock_path, PATH_MAX, - DEFAULT_GLOBAL_APPS_UNIX_SOCK); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - if (strlen(client_unix_sock_path) == 0) { - ret = snprintf(client_unix_sock_path, PATH_MAX, - DEFAULT_GLOBAL_CLIENT_UNIX_SOCK); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - /* Set global SHM for ust */ - if (strlen(wait_shm_path) == 0) { - ret = snprintf(wait_shm_path, PATH_MAX, - DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - if (strlen(health_unix_sock_path) == 0) { - ret = snprintf(health_unix_sock_path, - sizeof(health_unix_sock_path), - DEFAULT_GLOBAL_HEALTH_UNIX_SOCK); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - /* Setup kernel consumerd path */ - ret = snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, - DEFAULT_KCONSUMERD_ERR_SOCK_PATH, rundir); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - ret = snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, - DEFAULT_KCONSUMERD_CMD_SOCK_PATH, rundir); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - - DBG2("Kernel consumer err path: %s", - kconsumer_data.err_unix_sock_path); - DBG2("Kernel consumer cmd path: %s", - kconsumer_data.cmd_unix_sock_path); - } 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."); - retval = -1; - goto exit_init_data; - } - - /* - * Create rundir from home path. This will create something like - * $HOME/.lttng - */ - ret = asprintf(&rundir, DEFAULT_LTTNG_HOME_RUNDIR, home_path); - if (ret < 0) { + kernel_channel_monitor_pipe = lttng_pipe_open(0); + if (!kernel_channel_monitor_pipe) { + ERR("Failed to create kernel consumer channel monitor pipe"); retval = -1; goto exit_init_data; } - - if (create_lttng_rundir(rundir)) { + kconsumer_data.channel_monitor_pipe = + lttng_pipe_release_writefd( + kernel_channel_monitor_pipe); + if (kconsumer_data.channel_monitor_pipe < 0) { retval = -1; goto exit_init_data; } - - if (strlen(apps_unix_sock_path) == 0) { - ret = snprintf(apps_unix_sock_path, PATH_MAX, - DEFAULT_HOME_APPS_UNIX_SOCK, - home_path); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - /* Set the cli tool unix socket path */ - if (strlen(client_unix_sock_path) == 0) { - ret = snprintf(client_unix_sock_path, PATH_MAX, - DEFAULT_HOME_CLIENT_UNIX_SOCK, - home_path); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - /* Set global SHM for ust */ - if (strlen(wait_shm_path) == 0) { - ret = snprintf(wait_shm_path, PATH_MAX, - DEFAULT_HOME_APPS_WAIT_SHM_PATH, - getuid()); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } - - /* Set health check Unix path */ - if (strlen(health_unix_sock_path) == 0) { - ret = snprintf(health_unix_sock_path, - sizeof(health_unix_sock_path), - DEFAULT_HOME_HEALTH_UNIX_SOCK, - home_path); - if (ret < 0) { - retval = -1; - goto exit_init_data; - } - } } lockfile_fd = create_lockfile(); @@ -5636,53 +5616,32 @@ int main(int argc, char **argv) kernel_consumerd_state = CONSUMER_STOPPED; ust_consumerd_state = CONSUMER_STOPPED; - DBG("Client socket path %s", client_unix_sock_path); - DBG("Application socket path %s", apps_unix_sock_path); - DBG("Application wait path %s", wait_shm_path); - DBG("LTTng run directory path: %s", rundir); - - /* 32 bits consumerd path setup */ - ret = snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, rundir); - if (ret < 0) { - PERROR("snprintf 32-bit consumer error socket path"); + ust32_channel_monitor_pipe = lttng_pipe_open(0); + if (!ust32_channel_monitor_pipe) { + ERR("Failed to create 32-bit user space consumer channel monitor pipe"); retval = -1; goto exit_init_data; } - ret = snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, rundir); - if (ret < 0) { - PERROR("snprintf 32-bit consumer command socket path"); + ustconsumer32_data.channel_monitor_pipe = lttng_pipe_release_writefd( + ust32_channel_monitor_pipe); + if (ustconsumer32_data.channel_monitor_pipe < 0) { retval = -1; goto exit_init_data; } - DBG2("UST consumer 32 bits err path: %s", - ustconsumer32_data.err_unix_sock_path); - DBG2("UST consumer 32 bits cmd path: %s", - ustconsumer32_data.cmd_unix_sock_path); - - /* 64 bits consumerd path setup */ - ret = snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, rundir); - if (ret < 0) { - PERROR("snprintf 64-bit consumer error socket path"); + ust64_channel_monitor_pipe = lttng_pipe_open(0); + if (!ust64_channel_monitor_pipe) { + ERR("Failed to create 64-bit user space consumer channel monitor pipe"); retval = -1; goto exit_init_data; } - ret = snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, - DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, rundir); - if (ret < 0) { - PERROR("snprintf 64-bit consumer command socket path"); + ustconsumer64_data.channel_monitor_pipe = lttng_pipe_release_writefd( + ust64_channel_monitor_pipe); + if (ustconsumer64_data.channel_monitor_pipe < 0) { retval = -1; goto exit_init_data; } - DBG2("UST consumer 64 bits err path: %s", - ustconsumer64_data.err_unix_sock_path); - DBG2("UST consumer 64 bits cmd path: %s", - ustconsumer64_data.cmd_unix_sock_path); - /* * See if daemon already exist. */ @@ -5723,13 +5682,13 @@ int main(int argc, char **argv) * kernel tracer. */ if (is_root) { - if (set_consumer_sockets(&kconsumer_data, rundir)) { + if (set_consumer_sockets(&kconsumer_data)) { retval = -1; goto exit_init_data; } /* Setup kernel tracer */ - if (!opt_no_kernel) { + if (!config.no_kernel) { init_kernel_tracer(); if (kernel_tracer_fd >= 0) { ret = syscall_init_table(); @@ -5747,12 +5706,12 @@ int main(int argc, char **argv) /* init lttng_fd tracking must be done after set_ulimit. */ lttng_fd_init(); - if (set_consumer_sockets(&ustconsumer64_data, rundir)) { + if (set_consumer_sockets(&ustconsumer64_data)) { retval = -1; goto exit_init_data; } - if (set_consumer_sockets(&ustconsumer32_data, rundir)) { + if (set_consumer_sockets(&ustconsumer32_data)) { retval = -1; goto exit_init_data; } @@ -5764,18 +5723,18 @@ int main(int argc, char **argv) } /* Set credentials to socket */ - if (is_root && set_permissions(rundir)) { + if (is_root && set_permissions(config.rundir.value)) { retval = -1; goto exit_init_data; } /* Get parent pid if -S, --sig-parent is specified. */ - if (opt_sig_parent) { + if (config.sig_parent) { ppid = getppid(); } /* Setup the kernel pipe for waking up the kernel thread */ - if (is_root && !opt_no_kernel) { + if (is_root && !config.no_kernel) { if (utils_create_pipe_cloexec(kernel_poll_pipe)) { retval = -1; goto exit_init_data; @@ -5812,9 +5771,9 @@ int main(int argc, char **argv) /* Check for the application socket timeout env variable. */ env_app_timeout = getenv(DEFAULT_APP_SOCKET_TIMEOUT_ENV); if (env_app_timeout) { - app_socket_timeout = atoi(env_app_timeout); + config.app_socket_timeout = atoi(env_app_timeout); } else { - app_socket_timeout = DEFAULT_APP_SOCKET_RW_TIMEOUT; + config.app_socket_timeout = DEFAULT_APP_SOCKET_RW_TIMEOUT; } ret = write_pidfile(); @@ -5839,10 +5798,10 @@ int main(int argc, char **argv) retval = -1; goto exit_init_data; } - load_info->path = opt_load_session_path; + load_info->path = config.load_session_path.value; - /* Create health-check thread */ - ret = pthread_create(&health_thread, NULL, + /* Create health-check thread. */ + ret = pthread_create(&health_thread, default_pthread_attr(), thread_manage_health, (void *) NULL); if (ret) { errno = ret; @@ -5851,86 +5810,118 @@ int main(int argc, char **argv) goto exit_health; } + /* notification_thread_data acquires the pipes' read side. */ + notification_thread_handle = notification_thread_handle_create( + ust32_channel_monitor_pipe, + ust64_channel_monitor_pipe, + kernel_channel_monitor_pipe); + if (!notification_thread_handle) { + retval = -1; + ERR("Failed to create notification thread shared data"); + stop_threads(); + goto exit_notification; + } + + /* Create notification thread. */ + ret = pthread_create(¬ification_thread, default_pthread_attr(), + thread_notification, notification_thread_handle); + if (ret) { + errno = ret; + PERROR("pthread_create notification"); + retval = -1; + stop_threads(); + goto exit_notification; + } + notification_thread_running = true; + /* Create thread to manage the client socket */ - ret = pthread_create(&client_thread, NULL, + ret = pthread_create(&client_thread, default_pthread_attr(), thread_manage_clients, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create clients"); retval = -1; + stop_threads(); goto exit_client; } /* Create thread to dispatch registration */ - ret = pthread_create(&dispatch_thread, NULL, + ret = pthread_create(&dispatch_thread, default_pthread_attr(), thread_dispatch_ust_registration, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create dispatch"); retval = -1; + stop_threads(); goto exit_dispatch; } /* Create thread to manage application registration. */ - ret = pthread_create(®_apps_thread, NULL, + ret = pthread_create(®_apps_thread, default_pthread_attr(), thread_registration_apps, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create registration"); retval = -1; + stop_threads(); goto exit_reg_apps; } /* Create thread to manage application socket */ - ret = pthread_create(&apps_thread, NULL, + ret = pthread_create(&apps_thread, default_pthread_attr(), thread_manage_apps, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create apps"); retval = -1; + stop_threads(); goto exit_apps; } /* Create thread to manage application notify socket */ - ret = pthread_create(&apps_notify_thread, NULL, + ret = pthread_create(&apps_notify_thread, default_pthread_attr(), ust_thread_manage_notify, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create notify"); retval = -1; + stop_threads(); goto exit_apps_notify; } /* Create agent registration thread. */ - ret = pthread_create(&agent_reg_thread, NULL, + ret = pthread_create(&agent_reg_thread, default_pthread_attr(), agent_thread_manage_registration, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create agent"); retval = -1; + stop_threads(); goto exit_agent_reg; } /* Don't start this thread if kernel tracing is not requested nor root */ - if (is_root && !opt_no_kernel) { + if (is_root && !config.no_kernel) { /* Create kernel thread to manage kernel event */ - ret = pthread_create(&kernel_thread, NULL, + ret = pthread_create(&kernel_thread, default_pthread_attr(), thread_manage_kernel, (void *) NULL); if (ret) { errno = ret; PERROR("pthread_create kernel"); retval = -1; + stop_threads(); goto exit_kernel; } } /* Create session loading thread. */ - ret = pthread_create(&load_session_thread, NULL, thread_load_session, - load_info); + ret = pthread_create(&load_session_thread, default_pthread_attr(), + thread_load_session, load_info); if (ret) { errno = ret; PERROR("pthread_create load_session_thread"); retval = -1; + stop_threads(); goto exit_load_session; } @@ -5947,7 +5938,7 @@ int main(int argc, char **argv) } exit_load_session: - if (is_root && !opt_no_kernel) { + if (is_root && !config.no_kernel) { ret = pthread_join(kernel_thread, &status); if (ret) { errno = ret; @@ -6007,60 +5998,77 @@ exit_dispatch: PERROR("pthread_join"); retval = -1; } -exit_client: +exit_client: +exit_notification: ret = pthread_join(health_thread, &status); if (ret) { errno = ret; PERROR("pthread_join health thread"); retval = -1; } -exit_health: +exit_health: 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(); /* * sessiond_cleanup() is called when no other thread is running, except * the ht_cleanup thread, which is needed to destroy the hash tables. */ rcu_thread_online(); sessiond_cleanup(); - rcu_thread_offline(); - rcu_unregister_thread(); - ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]); - if (ret < 0) { - ERR("write error on ht_cleanup quit pipe"); - retval = -1; + /* + * Ensure all prior call_rcu are done. call_rcu callbacks may push + * hash tables to the ht_cleanup thread. Therefore, we ensure that + * the queue is empty before shutting down the clean-up thread. + */ + rcu_barrier(); + + /* + * The teardown of the notification system is performed after the + * session daemon's teardown in order to allow it to be notified + * of the active session and channels at the moment of the teardown. + */ + if (notification_thread_handle) { + if (notification_thread_running) { + notification_thread_command_quit( + notification_thread_handle); + ret = pthread_join(notification_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join notification thread"); + retval = -1; + } + } + notification_thread_handle_destroy(notification_thread_handle); } - ret = pthread_join(ht_cleanup_thread, &status); + rcu_thread_offline(); + rcu_unregister_thread(); + + ret = fini_ht_cleanup_thread(&ht_cleanup_thread); if (ret) { - errno = ret; - PERROR("pthread_join ht cleanup thread"); retval = -1; } + lttng_pipe_destroy(ust32_channel_monitor_pipe); + lttng_pipe_destroy(ust64_channel_monitor_pipe); + lttng_pipe_destroy(kernel_channel_monitor_pipe); exit_ht_cleanup: -exit_set_max_size: - - utils_close_pipe(ht_cleanup_pipe); -exit_ht_cleanup_pipe: - - /* - * Close the ht_cleanup quit pipe. - */ - utils_close_pipe(ht_cleanup_quit_pipe); -exit_ht_cleanup_quit_pipe: health_app_destroy(health_sessiond); exit_health_sessiond_cleanup: +exit_create_run_as_worker_cleanup: exit_options: sessiond_cleanup_options(); exit_set_signal_handler: - /* Ensure all prior call_rcu are done. */ - rcu_barrier(); - if (!retval) { exit(EXIT_SUCCESS); } else {