Add lttng_waiter utils
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index 916a2b76993edc96111365760077c4a5951cfeeb..9b6f70cd08134acfa45afa1d970735d3d2ee6a4c 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/wait.h>
 #include <urcu/uatomic.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include <common/common.h>
 #include <common/compat/socket.h>
 #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"
 
 #define CONSUMERD_FILE "lttng-consumerd"
 
+static const char *help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng-sessiond.8.h>
+#else
+NULL
+#endif
+;
+
 const char *progname;
-static const char *tracing_group_name = DEFAULT_TRACING_GROUP;
+const char *tracing_group_name = DEFAULT_TRACING_GROUP;
 static int tracing_group_name_override;
 static char *opt_pidfile;
 static int opt_sig_parent;
@@ -102,6 +114,7 @@ static struct consumer_data kconsumer_data = {
        .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,
@@ -113,6 +126,7 @@ static struct consumer_data ustconsumer64_data = {
        .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,
@@ -124,6 +138,7 @@ static struct consumer_data ustconsumer32_data = {
        .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,
@@ -189,7 +204,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
@@ -210,6 +224,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
@@ -304,17 +319,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)
@@ -421,47 +445,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.
  *
@@ -494,11 +477,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.
  */
@@ -561,6 +539,24 @@ 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");
+               }
+       }
 }
 
 /*
@@ -604,8 +600,7 @@ static void wait_consumer(struct consumer_data *consumer_data)
        ret = waitpid(consumer_data->pid, &status, 0);
        if (ret == -1) {
                PERROR("consumerd waitpid pid: %d", consumer_data->pid)
-       }
-       if (!WIFEXITED(status)) {
+       } else  if (!WIFEXITED(status)) {
                ERR("consumerd termination with error: %d",
                                WEXITSTATUS(ret));
        }
@@ -800,12 +795,6 @@ static void sessiond_cleanup_options(void)
        free(kmod_extra_probes_list);
 
        run_as_destroy_worker();
-
-       /* <fun> */
-       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);
-       /* </fun> */
 }
 
 /*
@@ -1270,6 +1259,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");
 
@@ -1379,40 +1369,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;
@@ -1433,6 +1426,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) {
@@ -1576,6 +1590,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();
@@ -1902,6 +1920,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)) {
@@ -2135,6 +2155,7 @@ error_testpoint:
                ERR("Health error occurred in %s", __func__);
        }
        health_unregister(health_sessiond);
+       rcu_unregister_thread();
        return NULL;
 }
 
@@ -2242,10 +2263,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 (app_socket_timeout >= 0) {
+                                               (void) lttcomm_setsockopt_rcv_timeout(sock,
+                                                               app_socket_timeout * 1000);
+                                               (void) lttcomm_setsockopt_snd_timeout(sock,
+                                                               app_socket_timeout * 1000);
+                                       }
 
                                        /*
                                         * Set the CLOEXEC flag. Return code is useless because
@@ -2371,7 +2394,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 */
@@ -2401,8 +2429,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");
@@ -2414,7 +2442,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
@@ -3039,7 +3067,10 @@ 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_METADATA_REGENERATE:
+       case LTTNG_REGENERATE_METADATA:
+       case LTTNG_REGENERATE_STATEDUMP:
+       case LTTNG_REGISTER_TRIGGER:
+       case LTTNG_UNREGISTER_TRIGGER:
                need_domain = 0;
                break;
        default:
@@ -3081,6 +3112,7 @@ 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 */
@@ -3096,12 +3128,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:
@@ -3485,8 +3518,11 @@ error_add_context:
        }
        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:
@@ -3938,12 +3974,6 @@ error_add_context:
                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;
@@ -4149,9 +4179,26 @@ error_add_context:
                                cmd_ctx->lsm->u.set_shm_path.shm_path);
                break;
        }
-       case LTTNG_METADATA_REGENERATE:
+       case LTTNG_REGENERATE_METADATA:
        {
-               ret = cmd_metadata_regenerate(cmd_ctx->session);
+               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:
@@ -4320,7 +4367,6 @@ restart:
                        if (ret) {
                                PERROR("close");
                        }
-                       new_sock = -1;
                        continue;
                }
 
@@ -4349,7 +4395,6 @@ restart:
                if (ret) {
                        PERROR("close");
                }
-               new_sock = -1;
        }
 
 exit:
@@ -4367,7 +4412,7 @@ error:
        }
 
        lttng_poll_clean(&events);
-
+       stop_threads();
        rcu_unregister_thread();
        return NULL;
 }
@@ -4719,9 +4764,9 @@ static int set_option(int opt, const char *arg, const char *optname)
                        tracing_group_name_override = 1;
                }
        } else if (string_match(optname, "help") || opt == 'h') {
-               ret = utils_show_man_page(8, "lttng-sessiond");
+               ret = utils_show_help(8, "lttng-sessiond", help_msg);
                if (ret) {
-                       ERR("Cannot view man page lttng-sessiond(8)");
+                       ERR("Cannot show --help for `lttng-sessiond`");
                        perror("exec");
                }
                exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
@@ -5405,9 +5450,6 @@ error:
 static void sighandler(int sig)
 {
        switch (sig) {
-       case SIGPIPE:
-               DBG("SIGPIPE caught");
-               return;
        case SIGINT:
                DBG("SIGINT caught");
                stop_threads();
@@ -5439,9 +5481,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;
@@ -5452,12 +5495,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;
        }
@@ -5469,14 +5513,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;
 
@@ -5571,6 +5615,10 @@ int main(int argc, char **argv)
        int ret = 0, retval = 0;
        void *status;
        const char *home_path, *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();
 
@@ -5645,29 +5693,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;
        }
@@ -5750,6 +5777,19 @@ int main(int argc, char **argv)
                                kconsumer_data.err_unix_sock_path);
                DBG2("Kernel consumer cmd path: %s",
                                kconsumer_data.cmd_unix_sock_path);
+               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;
+               }
+               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;
+               }
        } else {
                home_path = utils_get_home_dir();
                if (home_path == NULL) {
@@ -5854,6 +5894,18 @@ int main(int argc, char **argv)
                        ustconsumer32_data.err_unix_sock_path);
        DBG2("UST consumer 32 bits cmd path: %s",
                        ustconsumer32_data.cmd_unix_sock_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;
+       }
+       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;
+       }
 
        /* 64 bits consumerd path setup */
        ret = snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX,
@@ -5875,6 +5927,18 @@ int main(int argc, char **argv)
                        ustconsumer64_data.err_unix_sock_path);
        DBG2("UST consumer 64 bits cmd path: %s",
                        ustconsumer64_data.cmd_unix_sock_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;
+       }
+       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;
+       }
 
        /*
         * See if daemon already exist.
@@ -6034,8 +6098,8 @@ int main(int argc, char **argv)
        }
        load_info->path = opt_load_session_path;
 
-       /* 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;
@@ -6044,86 +6108,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(&notification_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(&reg_apps_thread, NULL,
+       ret = pthread_create(&reg_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) {
                /* 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;
        }
 
@@ -6200,62 +6296,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:
-       /* Ensure all prior call_rcu are done. */
-       rcu_barrier();
-
        sessiond_cleanup_options();
 
 exit_set_signal_handler:
-
        if (!retval) {
                exit(EXIT_SUCCESS);
        } else {
This page took 0.034581 seconds and 4 git commands to generate.