Launch the notification thread using lttng_thread
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index 4968ee2a937194d2f344fa6a2b232656eec6acc9..4749f8621b62d1b0512304dcbac6677fd1e79124 100644 (file)
@@ -49,6 +49,9 @@
 #include <common/utils.h>
 #include <common/daemonize.h>
 #include <common/config/session-config.h>
+#include <common/dynamic-buffer.h>
+#include <lttng/userspace-probe-internal.h>
+#include <lttng/event-internal.h>
 
 #include "lttng-sessiond.h"
 #include "buffer-registry.h"
 #include "notification-thread.h"
 #include "notification-thread-commands.h"
 #include "rotation-thread.h"
-#include "syscall.h"
+#include "lttng-syscall.h"
 #include "agent.h"
 #include "ht-cleanup.h"
 #include "sessiond-config.h"
-#include "sessiond-timer.h"
+#include "timer.h"
+#include "thread.h"
 
 static const char *help_msg =
 #ifdef LTTNG_EMBED_HELP
@@ -89,8 +93,6 @@ NULL
 ;
 
 const char *progname;
-static pid_t ppid;          /* Parent PID for --sig-parent option */
-static pid_t child_ppid;    /* Internal parent PID use with daemonize. */
 static int lockfile_fd = -1;
 
 /* Set to 1 when a SIGUSR1 signal is received. */
@@ -108,7 +110,6 @@ static struct consumer_data kconsumer_data = {
        .err_sock = -1,
        .cmd_sock = -1,
        .channel_monitor_pipe = -1,
-       .channel_rotate_pipe = -1,
        .pid_mutex = PTHREAD_MUTEX_INITIALIZER,
        .lock = PTHREAD_MUTEX_INITIALIZER,
        .cond = PTHREAD_COND_INITIALIZER,
@@ -119,7 +120,6 @@ static struct consumer_data ustconsumer64_data = {
        .err_sock = -1,
        .cmd_sock = -1,
        .channel_monitor_pipe = -1,
-       .channel_rotate_pipe = -1,
        .pid_mutex = PTHREAD_MUTEX_INITIALIZER,
        .lock = PTHREAD_MUTEX_INITIALIZER,
        .cond = PTHREAD_COND_INITIALIZER,
@@ -130,7 +130,6 @@ static struct consumer_data ustconsumer32_data = {
        .err_sock = -1,
        .cmd_sock = -1,
        .channel_monitor_pipe = -1,
-       .channel_rotate_pipe = -1,
        .pid_mutex = PTHREAD_MUTEX_INITIALIZER,
        .lock = PTHREAD_MUTEX_INITIALIZER,
        .cond = PTHREAD_COND_INITIALIZER,
@@ -170,8 +169,6 @@ 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" };
 
@@ -181,14 +178,6 @@ static int dispatch_thread_exit;
 /* Sockets and FDs */
 static int client_sock = -1;
 static int apps_sock = -1;
-int kernel_tracer_fd = -1;
-static int kernel_poll_pipe[2] = { -1, -1 };
-
-/*
- * Quit pipe for all threads. This permits a single cancellation point
- * for all threads when receiving an event on the pipe.
- */
-static int thread_quit_pipe[2] = { -1, -1 };
 
 /*
  * This pipe is used to inform the thread managing application communication
@@ -196,8 +185,6 @@ static int thread_quit_pipe[2] = { -1, -1 };
  */
 static int apps_cmd_pipe[2] = { -1, -1 };
 
-int apps_cmd_notify_pipe[2] = { -1, -1 };
-
 /* Pthread, Mutexes and Semaphores */
 static pthread_t apps_thread;
 static pthread_t apps_notify_thread;
@@ -205,11 +192,8 @@ static pthread_t reg_apps_thread;
 static pthread_t client_thread;
 static pthread_t kernel_thread;
 static pthread_t dispatch_thread;
-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;
 static pthread_t rotation_thread;
 static pthread_t timer_thread;
 
@@ -224,21 +208,6 @@ static pthread_t timer_thread;
  */
 static struct ust_cmd_queue ust_cmd_queue;
 
-/*
- * Pointer initialized before thread creation.
- *
- * This points to the tracing session list containing the session count and a
- * mutex lock. The lock MUST be taken if you iterate over the list. The lock
- * MUST NOT be taken if you call a public function in session.c.
- *
- * The lock is nested inside the structure: session_list_ptr->lock. Please use
- * session_lock_list and session_unlock_list for lock acquisition.
- */
-static struct ltt_session_list *session_list_ptr;
-
-int ust_consumerd64_fd = -1;
-int ust_consumerd32_fd = -1;
-
 static const char *module_proc_lttng = "/proc/lttng";
 
 /*
@@ -275,131 +244,19 @@ enum consumerd_state {
 static enum consumerd_state ust_consumerd_state;
 static enum consumerd_state kernel_consumerd_state;
 
-/* Set in main() with the current page size. */
-long page_size;
-
-/* Application health monitoring */
-struct health_app *health_sessiond;
-
-/* Am I root or not. */
-int is_root;                   /* Set to 1 if the daemon is running as root */
-
-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;
-
-/* Rotation thread handle. */
-struct rotation_thread_handle *rotation_thread_handle;
-
-/* Global hash tables */
-struct lttng_ht *agent_apps_ht_by_sock = NULL;
-
-/*
- * 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                5
-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)
-{
-       if (uatomic_sub_return(&lttng_sessiond_ready, 1) == 0) {
-               /*
-                * Notify parent pid that we are ready to accept command
-                * for client side.  This ppid is the one from the
-                * external process that spawned us.
-                */
-               if (config.sig_parent) {
-                       kill(ppid, SIGUSR1);
-               }
-
-               /*
-                * Notify the parent of the fork() process that we are
-                * ready.
-                */
-               if (config.daemonize || config.background) {
-                       kill(child_ppid, SIGUSR1);
-               }
-       }
-}
-
-static
-int __sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size,
-               int *a_pipe)
-{
-       int ret;
-
-       assert(events);
-
-       ret = lttng_poll_create(events, size, LTTNG_CLOEXEC);
-       if (ret < 0) {
-               goto error;
-       }
-
-       /* Add quit pipe */
-       ret = lttng_poll_add(events, a_pipe[0], LPOLLIN | LPOLLERR);
-       if (ret < 0) {
-               goto error;
-       }
-
-       return 0;
-
-error:
-       return ret;
-}
-
-/*
- * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set.
- */
-int sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size)
-{
-       return __sessiond_set_thread_pollset(events, size, thread_quit_pipe);
-}
+static struct load_session_thread_data *load_info;
 
 /*
- * Init thread quit pipe.
- *
- * Return -1 on error or 0 if all pipes are created.
+ * Section name to look for in the daemon configuration file.
  */
-static int __init_thread_quit_pipe(int *a_pipe)
-{
-       int ret, i;
-
-       ret = pipe(a_pipe);
-       if (ret < 0) {
-               PERROR("thread quit pipe");
-               goto error;
-       }
-
-       for (i = 0; i < 2; i++) {
-               ret = fcntl(a_pipe[i], F_SETFD, FD_CLOEXEC);
-               if (ret < 0) {
-                       PERROR("fcntl");
-                       goto error;
-               }
-       }
+static const char * const config_section_name = "sessiond";
 
-error:
-       return ret;
-}
+/* Am I root or not. Set to 1 if the daemon is running as root */
+static int is_root;
 
-static int init_thread_quit_pipe(void)
-{
-       return __init_thread_quit_pipe(thread_quit_pipe);
-}
+/* Rotation thread handle. */
+static struct rotation_thread_handle *rotation_thread_handle;
 
 /*
  * Stop all threads by closing the thread quit pipe.
@@ -410,7 +267,7 @@ static void stop_threads(void)
 
        /* Stopping all threads */
        DBG("Terminating all threads");
-       ret = notify_thread_pipe(thread_quit_pipe[1]);
+       ret = sessiond_notify_quit_pipe();
        if (ret < 0) {
                ERR("write error on thread quit pipe");
        }
@@ -481,24 +338,6 @@ static void close_consumer_sockets(void)
                        PERROR("UST consumerd64 channel monitor pipe close");
                }
        }
-       if (kconsumer_data.channel_rotate_pipe >= 0) {
-               ret = close(kconsumer_data.channel_rotate_pipe);
-               if (ret < 0) {
-                       PERROR("kernel consumer channel rotate pipe close");
-               }
-       }
-       if (ustconsumer32_data.channel_rotate_pipe >= 0) {
-               ret = close(ustconsumer32_data.channel_rotate_pipe);
-               if (ret < 0) {
-                       PERROR("UST consumerd32 channel rotate pipe close");
-               }
-       }
-       if (ustconsumer64_data.channel_rotate_pipe >= 0) {
-               ret = close(ustconsumer64_data.channel_rotate_pipe);
-               if (ret < 0) {
-                       PERROR("UST consumerd64 channel rotate pipe close");
-               }
-       }
 }
 
 /*
@@ -534,7 +373,7 @@ static void wait_consumer(struct consumer_data *consumer_data)
 static void sessiond_cleanup(void)
 {
        int ret;
-       struct ltt_session *sess, *stmp;
+       struct ltt_session_list *session_list = session_get_list();
 
        DBG("Cleanup sessiond");
 
@@ -542,17 +381,11 @@ static void sessiond_cleanup(void)
         * Close the thread quit pipe. It has already done its job,
         * since we are now called.
         */
-       utils_close_pipe(thread_quit_pipe);
+       sessiond_close_quit_pipe();
 
-       /*
-        * If config.pid_file_path.value is undefined, the default file will be
-        * wiped when removing the rundir.
-        */
-       if (config.pid_file_path.value) {
-               ret = remove(config.pid_file_path.value);
-               if (ret < 0) {
-                       PERROR("remove pidfile %s", config.pid_file_path.value);
-               }
+       ret = remove(config.pid_file_path.value);
+       if (ret < 0) {
+               PERROR("remove pidfile %s", config.pid_file_path.value);
        }
 
        DBG("Removing sessiond and consumerd content of directory %s",
@@ -586,19 +419,7 @@ static void sessiond_cleanup(void)
        DBG("Removing directory %s", config.consumerd64_path.value);
        (void) rmdir(config.consumerd64_path.value);
 
-       DBG("Cleaning up all sessions");
-
-       /* Destroy session list mutex */
-       if (session_list_ptr != NULL) {
-               pthread_mutex_destroy(&session_list_ptr->lock);
-
-               /* Cleanup ALL session */
-               cds_list_for_each_entry_safe(sess, stmp,
-                               &session_list_ptr->head, list) {
-                       cmd_destroy_session(sess, kernel_poll_pipe[1],
-                                       notification_thread_handle);
-               }
-       }
+       pthread_mutex_destroy(&session_list->lock);
 
        wait_consumer(&kconsumer_data);
        wait_consumer(&ustconsumer64_data);
@@ -631,21 +452,6 @@ static void sessiond_cleanup(void)
                free(load_info);
        }
 
-       /*
-        * Cleanup lock file by deleting it and finaly closing it which will
-        * release the file system lock.
-        */
-       if (lockfile_fd >= 0) {
-               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");
-               }
-       }
-
        /*
         * We do NOT rmdir rundir because there are other processes
         * using it, for instance lttng-relayd, which can start in
@@ -786,16 +592,21 @@ static int setup_lttng_msg_no_cmd_header(struct command_ctx *cmd_ctx,
 static int update_kernel_poll(struct lttng_poll_event *events)
 {
        int ret;
-       struct ltt_session *session;
        struct ltt_kernel_channel *channel;
+       struct ltt_session *session;
+       const struct ltt_session_list *session_list = session_get_list();
 
        DBG("Updating kernel poll set");
 
        session_lock_list();
-       cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+       cds_list_for_each_entry(session, &session_list->head, list) {
+               if (!session_get(session)) {
+                       continue;
+               }
                session_lock(session);
                if (session->kernel_session == NULL) {
                        session_unlock(session);
+                       session_put(session);
                        continue;
                }
 
@@ -805,6 +616,7 @@ static int update_kernel_poll(struct lttng_poll_event *events)
                        ret = lttng_poll_add(events, channel->fd, LPOLLIN | LPOLLRDNORM);
                        if (ret < 0) {
                                session_unlock(session);
+                               session_put(session);
                                goto error;
                        }
                        DBG("Channel fd %d added to kernel set", channel->fd);
@@ -826,20 +638,25 @@ error:
  *
  * Useful for CPU hotplug feature.
  */
-static int update_kernel_stream(struct consumer_data *consumer_data, int fd)
+static int update_kernel_stream(int fd)
 {
        int ret = 0;
        struct ltt_session *session;
        struct ltt_kernel_session *ksess;
        struct ltt_kernel_channel *channel;
+       const struct ltt_session_list *session_list = session_get_list();
 
        DBG("Updating kernel streams for channel fd %d", fd);
 
        session_lock_list();
-       cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+       cds_list_for_each_entry(session, &session_list->head, list) {
+               if (!session_get(session)) {
+                       continue;
+               }
                session_lock(session);
                if (session->kernel_session == NULL) {
                        session_unlock(session);
+                       session_put(session);
                        continue;
                }
                ksess = session->kernel_session;
@@ -875,7 +692,7 @@ static int update_kernel_stream(struct consumer_data *consumer_data, int fd)
                        cds_lfht_for_each_entry(ksess->consumer->socks->ht,
                                        &iter.iter, socket, node.node) {
                                pthread_mutex_lock(socket->lock);
-                               ret = kernel_consumer_send_channel_stream(socket,
+                               ret = kernel_consumer_send_channel_streams(socket,
                                                channel, ksess,
                                                session->output_traces ? 1 : 0);
                                pthread_mutex_unlock(socket->lock);
@@ -887,12 +704,14 @@ static int update_kernel_stream(struct consumer_data *consumer_data, int fd)
                        rcu_read_unlock();
                }
                session_unlock(session);
+               session_put(session);
        }
        session_unlock_list();
        return ret;
 
 error:
        session_unlock(session);
+       session_put(session);
        session_unlock_list();
        return ret;
 }
@@ -904,6 +723,7 @@ error:
 static void update_ust_app(int app_sock)
 {
        struct ltt_session *sess, *stmp;
+       const struct ltt_session_list *session_list = session_get_list();
 
        /* Consumer is in an ERROR state. Stop any application update. */
        if (uatomic_read(&ust_consumerd_state) == CONSUMER_ERROR) {
@@ -912,9 +732,12 @@ static void update_ust_app(int app_sock)
        }
 
        /* For all tracing session(s) */
-       cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) {
+       cds_list_for_each_entry_safe(sess, stmp, &session_list->head, list) {
                struct ust_app *app;
 
+               if (!session_get(sess)) {
+                       continue;
+               }
                session_lock(sess);
                if (!sess->ust_session) {
                        goto unlock_session;
@@ -938,6 +761,7 @@ static void update_ust_app(int app_sock)
                rcu_read_unlock();
        unlock_session:
                session_unlock(sess);
+               session_put(sess);
        }
 }
 
@@ -1060,7 +884,7 @@ static void *thread_manage_kernel(void *data)
                                         * New CPU detected by the kernel. Adding kernel stream to
                                         * kernel session and updating the kernel consumer
                                         */
-                                       ret = update_kernel_stream(&kconsumer_data, pollfd);
+                                       ret = update_kernel_stream(pollfd);
                                        if (ret < 0) {
                                                continue;
                                        }
@@ -1296,8 +1120,7 @@ restart:
 
        /*
         * Transfer the write-end of the channel monitoring and rotate pipe
-        * to the consumer by issuing a SET_CHANNEL_MONITOR_PIPE and
-        * SET_CHANNEL_ROTATE_PIPE commands.
+        * to the consumer by issuing a SET_CHANNEL_MONITOR_PIPE command.
         */
        cmd_socket_wrapper = consumer_allocate_socket(&consumer_data->cmd_sock);
        if (!cmd_socket_wrapper) {
@@ -1311,12 +1134,6 @@ restart:
                goto error;
        }
 
-       ret = consumer_send_channel_rotate_pipe(cmd_socket_wrapper,
-                       consumer_data->channel_rotate_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;
@@ -2473,7 +2290,8 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data)
                        } else if (stat(INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE, &st) == 0) {
                                DBG3("Found location #2");
                                consumer_to_use = INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE;
-                       } else if (stat(config.consumerd32_bin_path.value, &st) == 0) {
+                       } else if (config.consumerd32_bin_path.value &&
+                                       stat(config.consumerd32_bin_path.value, &st) == 0) {
                                DBG3("Found location #3");
                                consumer_to_use = config.consumerd32_bin_path.value;
                        } else {
@@ -2889,21 +2707,132 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid)
 {
        unsigned int i = 0;
        struct ltt_session *session;
+       const struct ltt_session_list *session_list = session_get_list();
 
        DBG("Counting number of available session for UID %d GID %d",
                        uid, gid);
-       cds_list_for_each_entry(session, &session_list_ptr->head, list) {
-               /*
-                * Only list the sessions the user can control.
-                */
-               if (!session_access_ok(session, uid, gid)) {
+       cds_list_for_each_entry(session, &session_list->head, list) {
+               if (!session_get(session)) {
                        continue;
                }
-               i++;
+               session_lock(session);
+               /* Only count the sessions the user can control. */
+               if (session_access_ok(session, uid, gid) &&
+                               !session->destroyed) {
+                       i++;
+               }
+               session_unlock(session);
+               session_put(session);
        }
        return i;
 }
 
+static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock,
+               int *sock_error, struct lttng_event *event)
+{
+       int fd, ret;
+       struct lttng_userspace_probe_location *probe_location;
+       const struct lttng_userspace_probe_location_lookup_method *lookup = NULL;
+       struct lttng_dynamic_buffer probe_location_buffer;
+       struct lttng_buffer_view buffer_view;
+
+       /*
+        * Create a buffer to store the serialized version of the probe
+        * location.
+        */
+       lttng_dynamic_buffer_init(&probe_location_buffer);
+       ret = lttng_dynamic_buffer_set_size(&probe_location_buffer,
+                       cmd_ctx->lsm->u.enable.userspace_probe_location_len);
+       if (ret) {
+               ret = LTTNG_ERR_NOMEM;
+               goto error;
+       }
+
+       /*
+        * Receive the probe location.
+        */
+       ret = lttcomm_recv_unix_sock(sock, probe_location_buffer.data,
+                       probe_location_buffer.size);
+       if (ret <= 0) {
+               DBG("Nothing recv() from client var len data... continuing");
+               *sock_error = 1;
+               lttng_dynamic_buffer_reset(&probe_location_buffer);
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       buffer_view = lttng_buffer_view_from_dynamic_buffer(
+                       &probe_location_buffer, 0, probe_location_buffer.size);
+
+       /*
+        * Extract the probe location from the serialized version.
+        */
+       ret = lttng_userspace_probe_location_create_from_buffer(
+                               &buffer_view, &probe_location);
+       if (ret < 0) {
+               WARN("Failed to create a userspace probe location from the received buffer");
+               lttng_dynamic_buffer_reset( &probe_location_buffer);
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       /*
+        * Receive the file descriptor to the target binary from the client.
+        */
+       DBG("Receiving userspace probe target FD from client ...");
+       ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1);
+       if (ret <= 0) {
+               DBG("Nothing recv() from client userspace probe fd... continuing");
+               *sock_error = 1;
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       /*
+        * Set the file descriptor received from the client through the unix
+        * socket in the probe location.
+        */
+       lookup = lttng_userspace_probe_location_get_lookup_method(probe_location);
+       if (!lookup) {
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       /*
+        * From the kernel tracer's perspective, all userspace probe event types
+        * are all the same: a file and an offset.
+        */
+       switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) {
+       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+               ret = lttng_userspace_probe_location_function_set_binary_fd(
+                               probe_location, fd);
+               break;
+       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+               ret = lttng_userspace_probe_location_tracepoint_set_binary_fd(
+                               probe_location, fd);
+               break;
+       default:
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       if (ret) {
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       /* Attach the probe location to the event. */
+       ret = lttng_event_set_userspace_probe_location(event, probe_location);
+       if (ret) {
+               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+               goto error;
+       }
+
+       lttng_dynamic_buffer_reset(&probe_location_buffer);
+error:
+       return ret;
+}
+
 /*
  * Check if the current kernel tracer supports the session rotation feature.
  * Return 1 if it does, 0 otherwise.
@@ -2966,10 +2895,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_UNREGISTER_TRIGGER:
        case LTTNG_ROTATE_SESSION:
        case LTTNG_ROTATION_GET_INFO:
-       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
        case LTTNG_ROTATION_SET_SCHEDULE:
-       case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD:
-       case LTTNG_ROTATION_SCHEDULE_GET_SIZE:
+       case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
                need_domain = 0;
                break;
        default:
@@ -3014,8 +2941,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_DATA_PENDING:
        case LTTNG_ROTATE_SESSION:
        case LTTNG_ROTATION_GET_INFO:
-       case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD:
-       case LTTNG_ROTATION_SCHEDULE_GET_SIZE:
+       case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -3233,7 +3159,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                        }
 
                        /*
-                        * Setup socket for consumer 64 bit. No need for atomic access
+                        * Setup socket for consumer 32 bit. No need for atomic access
                         * since it was set above and can ONLY be set in this thread.
                         */
                        ret = consumer_create_socket(&ustconsumer32_data,
@@ -3283,7 +3209,8 @@ skip_domain:
        if (need_tracing_session) {
                if (!session_access_ok(cmd_ctx->session,
                                LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
-                               LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds))) {
+                               LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)) ||
+                               cmd_ctx->session->destroyed) {
                        ret = LTTNG_ERR_EPERM;
                        goto error;
                }
@@ -3444,6 +3371,7 @@ error_add_context:
        }
        case LTTNG_ENABLE_EVENT:
        {
+               struct lttng_event *ev = NULL;
                struct lttng_event_exclusion *exclusion = NULL;
                struct lttng_filter_bytecode *bytecode = NULL;
                char *filter_expression = NULL;
@@ -3495,7 +3423,7 @@ error_add_context:
                        ret = lttcomm_recv_unix_sock(sock, filter_expression,
                                expression_len);
                        if (ret <= 0) {
-                               DBG("Nothing recv() from client car len data... continuing");
+                               DBG("Nothing recv() from client var len data... continuing");
                                *sock_error = 1;
                                free(filter_expression);
                                free(exclusion);
@@ -3527,7 +3455,7 @@ error_add_context:
                        DBG("Receiving var len filter's bytecode from client ...");
                        ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len);
                        if (ret <= 0) {
-                               DBG("Nothing recv() from client car len data... continuing");
+                               DBG("Nothing recv() from client var len data... continuing");
                                *sock_error = 1;
                                free(filter_expression);
                                free(bytecode);
@@ -3545,11 +3473,36 @@ error_add_context:
                        }
                }
 
+               ev = lttng_event_copy(&cmd_ctx->lsm->u.enable.event);
+               if (!ev) {
+                       DBG("Failed to copy event: %s",
+                                       cmd_ctx->lsm->u.enable.event.name);
+                       free(filter_expression);
+                       free(bytecode);
+                       free(exclusion);
+                       ret = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+
+
+               if (cmd_ctx->lsm->u.enable.userspace_probe_location_len > 0) {
+                       /* Expect a userspace probe description. */
+                       ret = receive_userspace_probe(cmd_ctx, sock, sock_error, ev);
+                       if (ret) {
+                               free(filter_expression);
+                               free(bytecode);
+                               free(exclusion);
+                               lttng_event_destroy(ev);
+                               goto error;
+                       }
+               }
+
                ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                cmd_ctx->lsm->u.enable.channel_name,
-                               &cmd_ctx->lsm->u.enable.event,
+                               ev,
                                filter_expression, bytecode, exclusion,
                                kernel_poll_pipe[1]);
+               lttng_event_destroy(ev);
                break;
        }
        case LTTNG_LIST_TRACEPOINTS:
@@ -3772,11 +3725,8 @@ error_add_context:
        }
        case LTTNG_DESTROY_SESSION:
        {
-               ret = cmd_destroy_session(cmd_ctx->session, kernel_poll_pipe[1],
+               ret = cmd_destroy_session(cmd_ctx->session,
                                notification_thread_handle);
-
-               /* Set session to NULL so we do not unlock it after free. */
-               cmd_ctx->session = NULL;
                break;
        }
        case LTTNG_LIST_DOMAINS:
@@ -4170,39 +4120,26 @@ error_add_context:
                ret = LTTNG_OK;
                break;
        }
-       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
-       {
-               struct lttng_session_get_current_output_return output_return;
-
-               memset(&output_return, 0, sizeof(output_return));
-               ret = cmd_session_get_current_output(cmd_ctx->session,
-                               &output_return);
-               if (ret < 0) {
-                       ret = -ret;
-                       goto error;
-               }
-
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &output_return,
-                               sizeof(output_return));
-               if (ret < 0) {
-                       ret = -ret;
-                       goto error;
-               }
-
-               ret = LTTNG_OK;
-               break;
-       }
        case LTTNG_ROTATION_SET_SCHEDULE:
        {
+               bool set_schedule;
+               enum lttng_rotation_schedule_type schedule_type;
+               uint64_t value;
+
                if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) {
                        DBG("Kernel tracer version does not support session rotations");
                        ret = LTTNG_ERR_ROTATION_WRONG_VERSION;
                        goto error;
                }
 
+               set_schedule = cmd_ctx->lsm->u.rotation_set_schedule.set == 1;
+               schedule_type = (enum lttng_rotation_schedule_type) cmd_ctx->lsm->u.rotation_set_schedule.type;
+               value = cmd_ctx->lsm->u.rotation_set_schedule.value;
+
                ret = cmd_rotation_set_schedule(cmd_ctx->session,
-                               cmd_ctx->lsm->u.rotate_setup.timer_us,
-                               cmd_ctx->lsm->u.rotate_setup.size,
+                               set_schedule,
+                               schedule_type,
+                               value,
                                notification_thread_handle);
                if (ret != LTTNG_OK) {
                        goto error;
@@ -4210,42 +4147,17 @@ error_add_context:
 
                break;
        }
-       case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD:
-       {
-               struct lttng_rotation_schedule_get_timer_period *get_timer;
-
-               get_timer = zmalloc(sizeof(struct lttng_rotation_schedule_get_timer_period));
-               if (!get_timer) {
-                       ret = ENOMEM;
-                       goto error;
-               }
-               get_timer->rotate_timer = cmd_ctx->session->rotate_timer_period;
-
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_timer,
-                               sizeof(struct lttng_rotation_schedule_get_timer_period));
-               free(get_timer);
-               if (ret < 0) {
-                       ret = -ret;
-                       goto error;
-               }
-
-               ret = LTTNG_OK;
-               break;
-       }
-       case LTTNG_ROTATION_SCHEDULE_GET_SIZE:
+       case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
        {
-               struct lttng_rotation_schedule_get_size *get_size;
-
-               get_size = zmalloc(sizeof(struct lttng_rotation_schedule_get_size));
-               if (!get_size) {
-                       ret = ENOMEM;
-                       goto error;
-               }
-               get_size->rotate_size = cmd_ctx->session->rotate_size;
-
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_size,
-                               sizeof(struct lttng_rotation_schedule_get_size));
-               free(get_size);
+               struct lttng_session_list_schedules_return schedules = {
+                       .periodic.set = !!cmd_ctx->session->rotate_timer_period,
+                       .periodic.value = cmd_ctx->session->rotate_timer_period,
+                       .size.set = !!cmd_ctx->session->rotate_size,
+                       .size.value = cmd_ctx->session->rotate_size,
+               };
+
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &schedules,
+                               sizeof(schedules));
                if (ret < 0) {
                        ret = -ret;
                        goto error;
@@ -4271,6 +4183,7 @@ error:
 setup_error:
        if (cmd_ctx->session) {
                session_unlock(cmd_ctx->session);
+               session_put(cmd_ctx->session);
        }
        if (need_tracing_session) {
                session_unlock_list();
@@ -4281,218 +4194,28 @@ init_setup_error:
 }
 
 /*
- * Thread managing health check socket.
+ * This thread manage all clients request using the unix client socket for
+ * communication.
  */
-static void *thread_manage_health(void *data)
+static void *thread_manage_clients(void *data)
 {
-       int sock = -1, new_sock = -1, ret, i, pollfd, err = -1;
+       int sock = -1, ret, i, pollfd, err = -1;
+       int sock_error;
        uint32_t revents, nb_fd;
+       struct command_ctx *cmd_ctx = NULL;
        struct lttng_poll_event events;
-       struct health_comm_msg msg;
-       struct health_comm_reply reply;
 
-       DBG("[thread] Manage health check started");
+       DBG("[thread] Manage client started");
 
        rcu_register_thread();
 
-       /* We might hit an error path before this is created. */
-       lttng_poll_init(&events);
-
-       /* Create unix socket */
-       sock = lttcomm_create_unix_sock(config.health_unix_sock_path.value);
-       if (sock < 0) {
-               ERR("Unable to create health check Unix socket");
-               goto error;
-       }
+       health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CMD);
 
-       if (is_root) {
-               /* lttng health client socket path permissions */
-               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", config.health_unix_sock_path.value);
-                       PERROR("chown");
-                       goto error;
-               }
+       health_code_update();
 
-               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", config.health_unix_sock_path.value);
-                       PERROR("chmod");
-                       goto error;
-               }
-       }
-
-       /*
-        * Set the CLOEXEC flag. Return code is useless because either way, the
-        * show must go on.
-        */
-       (void) utils_set_fd_cloexec(sock);
-
-       ret = lttcomm_listen_unix_sock(sock);
-       if (ret < 0) {
-               goto error;
-       }
-
-       /*
-        * Pass 2 as size here for the thread quit pipe and client_sock. Nothing
-        * more will be added to this poll set.
-        */
-       ret = sessiond_set_thread_pollset(&events, 2);
-       if (ret < 0) {
-               goto error;
-       }
-
-       /* Add the application registration socket */
-       ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI);
-       if (ret < 0) {
-               goto error;
-       }
-
-       sessiond_notify_ready();
-
-       while (1) {
-               DBG("Health check ready");
-
-               /* Inifinite blocking call, waiting for transmission */
-restart:
-               ret = lttng_poll_wait(&events, -1);
-               if (ret < 0) {
-                       /*
-                        * Restart interrupted system call.
-                        */
-                       if (errno == EINTR) {
-                               goto restart;
-                       }
-                       goto error;
-               }
-
-               nb_fd = ret;
-
-               for (i = 0; i < nb_fd; i++) {
-                       /* Fetch once the poll data */
-                       revents = LTTNG_POLL_GETEV(&events, i);
-                       pollfd = LTTNG_POLL_GETFD(&events, i);
-
-                       if (!revents) {
-                               /* No activity for this FD (poll implementation). */
-                               continue;
-                       }
-
-                       /* Thread quit pipe has been closed. Killing thread. */
-                       ret = sessiond_check_thread_quit_pipe(pollfd, revents);
-                       if (ret) {
-                               err = 0;
-                               goto exit;
-                       }
-
-                       /* Event on the registration socket */
-                       if (pollfd == sock) {
-                               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;
-                               }
-                       }
-               }
-
-               new_sock = lttcomm_accept_unix_sock(sock);
-               if (new_sock < 0) {
-                       goto error;
-               }
-
-               /*
-                * Set the CLOEXEC flag. Return code is useless because either way, the
-                * show must go on.
-                */
-               (void) utils_set_fd_cloexec(new_sock);
-
-               DBG("Receiving data from client for health...");
-               ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg));
-               if (ret <= 0) {
-                       DBG("Nothing recv() from client... continuing");
-                       ret = close(new_sock);
-                       if (ret) {
-                               PERROR("close");
-                       }
-                       continue;
-               }
-
-               rcu_thread_online();
-
-               memset(&reply, 0, sizeof(reply));
-               for (i = 0; i < NR_HEALTH_SESSIOND_TYPES; i++) {
-                       /*
-                        * health_check_state returns 0 if health is
-                        * bad.
-                        */
-                       if (!health_check_state(health_sessiond, i)) {
-                               reply.ret_code |= 1ULL << i;
-                       }
-               }
-
-               DBG2("Health check return value %" PRIx64, reply.ret_code);
-
-               ret = send_unix_sock(new_sock, (void *) &reply, sizeof(reply));
-               if (ret < 0) {
-                       ERR("Failed to send health data back to client");
-               }
-
-               /* End of transmission */
-               ret = close(new_sock);
-               if (ret) {
-                       PERROR("close");
-               }
-       }
-
-exit:
-error:
-       if (err) {
-               ERR("Health error occurred in %s", __func__);
-       }
-       DBG("Health check thread dying");
-       unlink(config.health_unix_sock_path.value);
-       if (sock >= 0) {
-               ret = close(sock);
-               if (ret) {
-                       PERROR("close");
-               }
-       }
-
-       lttng_poll_clean(&events);
-       stop_threads();
-       rcu_unregister_thread();
-       return NULL;
-}
-
-/*
- * This thread manage all clients request using the unix client socket for
- * communication.
- */
-static void *thread_manage_clients(void *data)
-{
-       int sock = -1, ret, i, pollfd, err = -1;
-       int sock_error;
-       uint32_t revents, nb_fd;
-       struct command_ctx *cmd_ctx = NULL;
-       struct lttng_poll_event events;
-
-       DBG("[thread] Manage client started");
-
-       rcu_register_thread();
-
-       health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CMD);
-
-       health_code_update();
-
-       ret = lttcomm_listen_unix_sock(client_sock);
-       if (ret < 0) {
-               goto error_listen;
+       ret = lttcomm_listen_unix_sock(client_sock);
+       if (ret < 0) {
+               goto error_listen;
        }
 
        /*
@@ -4510,13 +4233,41 @@ static void *thread_manage_clients(void *data)
                goto error;
        }
 
-       sessiond_notify_ready();
        ret = sem_post(&load_info->message_thread_ready);
        if (ret) {
                PERROR("sem_post message_thread_ready");
                goto error;
        }
 
+       /*
+        * Wait until all support threads are initialized before accepting
+        * commands.
+        */
+       while (uatomic_read(&lttng_sessiond_ready) != 0) {
+               /*
+                * If a support thread failed to launch, it may signal that
+                * we must exit and the sessiond would never be marked as
+                * "ready".
+                *
+                * The timeout is set to 1ms, which serves as a way to
+                * pace down this check.
+                */
+               ret = sessiond_wait_for_quit_pipe(1000);
+               if (ret > 0) {
+                       goto exit;
+               }
+       }
+       /*
+        * This barrier is paired with the one in sessiond_notify_ready() to
+        * ensure that loads accessing data initialized by the other threads,
+        * on which this thread was waiting, are not performed before this point.
+        *
+        * Note that this could be a 'read' memory barrier, but a full barrier
+        * is used in case the code changes. The performance implications of
+        * this choice are minimal since this is a slow path.
+        */
+       cmm_smp_mb();
+
        /* This testpoint is after we signal readiness to the parent. */
        if (testpoint(sessiond_thread_manage_clients)) {
                goto error;
@@ -4528,7 +4279,12 @@ static void *thread_manage_clients(void *data)
 
        health_code_update();
 
+       /* Set state as running. */
+       sessiond_set_client_thread_state(true);
+
        while (1) {
+               const struct cmd_completion_handler *cmd_completion_handler;
+
                DBG("Accepting client command ...");
 
                /* Inifinite blocking call, waiting for transmission */
@@ -4671,6 +4427,18 @@ static void *thread_manage_clients(void *data)
                        continue;
                }
 
+               cmd_completion_handler = cmd_pop_completion_handler();
+               if (cmd_completion_handler) {
+                       enum lttng_error_code completion_code;
+
+                       completion_code = cmd_completion_handler->run(
+                                       cmd_completion_handler->data);
+                       if (completion_code != LTTNG_OK) {
+                               clean_command_ctx(&cmd_ctx);
+                               continue;
+                       }
+               }
+
                health_code_update();
 
                DBG("Sending response (size: %d, retcode: %s (%d))",
@@ -4748,6 +4516,9 @@ error_create_poll:
                errno = ret;
                PERROR("join_consumer ust64");
        }
+
+       /* Set state as non-running. */
+       sessiond_set_client_thread_state(false);
        return NULL;
 }
 
@@ -5048,8 +4819,8 @@ static int set_option(int opt, const char *arg, const char *optname)
                                ERR("Port overflow in --agent-tcp-port parameter: %s", arg);
                                return -1;
                        }
-                       config.agent_tcp_port = (uint32_t) v;
-                       DBG3("Agent TCP port set to non default: %u", config.agent_tcp_port);
+                       config.agent_tcp_port.begin = config.agent_tcp_port.end = (int) v;
+                       DBG3("Agent TCP port set to non default: %i", (int) v);
                }
        } else if (string_match(optname, "load") || opt == 'l') {
                if (!arg || *arg == '\0') {
@@ -5332,18 +5103,57 @@ end:
        return ret;
 }
 
+/*
+ * Create lockfile using the rundir and return its fd.
+ */
+static int create_lockfile(void)
+{
+        return utils_create_lock_file(config.lock_file_path.value);
+}
+
 /*
  * Check if the global socket is available, and if a daemon is answering at the
  * other side. If yes, error is returned.
+ *
+ * Also attempts to create and hold the lock file.
  */
 static int check_existing_daemon(void)
 {
+       int ret = 0;
+
        /* Is there anybody out there ? */
        if (lttng_session_daemon_alive()) {
-               return -EEXIST;
+               ret = -EEXIST;
+               goto end;
        }
 
-       return 0;
+       lockfile_fd = create_lockfile();
+       if (lockfile_fd < 0) {
+               ret = -EEXIST;
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static void sessiond_cleanup_lock_file(void)
+{
+       int ret;
+
+       /*
+        * Cleanup lock file by deleting it and finaly closing it which will
+        * release the file system lock.
+        */
+       if (lockfile_fd >= 0) {
+               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");
+               }
+       }
 }
 
 /*
@@ -5602,23 +5412,6 @@ static int write_pidfile(void)
         return utils_create_pid_file(getpid(), config.pid_file_path.value);
 }
 
-/*
- * Create lockfile using the rundir and return its fd.
- */
-static int create_lockfile(void)
-{
-        return utils_create_lock_file(config.lock_file_path.value);
-}
-
-/*
- * Write agent TCP port using the rundir.
- */
-static int write_agent_port(void)
-{
-       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;
@@ -5648,46 +5441,48 @@ end:
        return ret;
 }
 
-static
-struct rotation_thread_timer_queue *create_rotate_timer_queue(void)
+static void destroy_all_sessions_and_wait(void)
 {
-       struct rotation_thread_timer_queue *queue = NULL;
-
-       queue = zmalloc(sizeof(struct rotation_thread_timer_queue));
-       if (!queue) {
-               PERROR("Failed to allocate timer rotate queue");
-               goto end;
-       }
+       struct ltt_session *session, *tmp;
+       struct ltt_session_list *session_list;
 
-       queue->event_pipe = lttng_pipe_open(FD_CLOEXEC | O_NONBLOCK);
-       CDS_INIT_LIST_HEAD(&queue->list);
-       pthread_mutex_init(&queue->lock, NULL);
+       session_list = session_get_list();
+       DBG("Initiating destruction of all sessions");
 
-end:
-       return queue;
-}
-
-static
-void destroy_rotate_timer_queue(struct rotation_thread_timer_queue *queue)
-{
-       struct sessiond_rotation_timer *node, *tmp_node;
-
-       if (!queue) {
+       if (!session_list) {
                return;
        }
 
-       lttng_pipe_destroy(queue->event_pipe);
+       /*
+        * Ensure that the client thread is no longer accepting new commands,
+        * which could cause new sessions to be created.
+        */
+       sessiond_wait_client_thread_stopped();
+
+       session_lock_list();
+       /* Initiate the destruction of all sessions. */
+       cds_list_for_each_entry_safe(session, tmp,
+                       &session_list->head, list) {
+               if (!session_get(session)) {
+                       continue;
+               }
 
-       pthread_mutex_lock(&queue->lock);
-       /* Empty wait queue. */
-       cds_list_for_each_entry_safe(node, tmp_node, &queue->list, head) {
-               cds_list_del(&node->head);
-               free(node);
+               session_lock(session);
+               if (session->destroyed) {
+                       goto unlock_session;
+               }
+               (void) cmd_destroy_session(session,
+                               notification_thread_handle);
+       unlock_session:
+               session_unlock(session);
+               session_put(session);
        }
-       pthread_mutex_unlock(&queue->lock);
+       session_unlock_list();
 
-       pthread_mutex_destroy(&queue->lock);
-       free(queue);
+       /* Wait for the destruction of all sessions to complete. */
+       DBG("Waiting for the destruction of all sessions to complete");
+       session_list_wait_empty();
+       DBG("Destruction of all sessions completed");
 }
 
 /*
@@ -5701,16 +5496,12 @@ int main(int argc, char **argv)
        struct lttng_pipe *ust32_channel_monitor_pipe = NULL,
                        *ust64_channel_monitor_pipe = NULL,
                        *kernel_channel_monitor_pipe = NULL;
-       bool notification_thread_running = false;
-       bool rotation_thread_running = false;
-       bool timer_thread_running = false;
-       struct lttng_pipe *ust32_channel_rotate_pipe = NULL,
-                       *ust64_channel_rotate_pipe = NULL,
-                       *kernel_channel_rotate_pipe = NULL;
+       bool rotation_thread_launched = false;
+       bool timer_thread_launched = false;
+       struct lttng_thread *ht_cleanup_thread = NULL;
        struct timer_thread_parameters timer_thread_ctx;
        /* Queue of rotation jobs populated by the sessiond-timer. */
        struct rotation_thread_timer_queue *rotation_timer_queue = NULL;
-       sem_t notification_thread_ready;
 
        init_kernel_workarounds();
 
@@ -5721,7 +5512,7 @@ int main(int argc, char **argv)
                goto exit_set_signal_handler;
        }
 
-       if (sessiond_timer_signal_init()) {
+       if (timer_signal_init()) {
                retval = -1;
                goto exit_set_signal_handler;
        }
@@ -5739,6 +5530,12 @@ int main(int argc, char **argv)
                goto exit_set_signal_handler;
        }
 
+       /*
+        * Init config from environment variables.
+        * Command line option override env configuration per-doc. Do env first.
+        */
+       sessiond_config_apply_env_config(&config);
+
        /*
         * Parse arguments and load the daemon configuration file.
         *
@@ -5753,9 +5550,6 @@ 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
@@ -5786,6 +5580,18 @@ int main(int argc, char **argv)
 
        sessiond_config_log(&config);
 
+       if (create_lttng_rundir()) {
+               retval = -1;
+               goto exit_options;
+       }
+
+       /* Abort launch if a session daemon is already running. */
+       if (check_existing_daemon()) {
+               ERR("A session daemon is already running.");
+               retval = -1;
+               goto exit_options;
+       }
+
        /* Daemonize */
        if (config.daemonize || config.background) {
                int i;
@@ -5800,9 +5606,12 @@ int main(int argc, char **argv)
                /*
                 * We are in the child. Make sure all other file descriptors are
                 * closed, in case we are called with more opened file
-                * descriptors than the standard ones.
+                * descriptors than the standard ones and the lock file.
                 */
                for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
+                       if (i == lockfile_fd) {
+                               continue;
+                       }
                        (void) close(i);
                }
        }
@@ -5828,25 +5637,20 @@ int main(int argc, char **argv)
        }
 
        /* Create thread to clean up RCU hash tables */
-       if (init_ht_cleanup_thread(&ht_cleanup_thread)) {
+       ht_cleanup_thread = launch_ht_cleanup_thread();
+       if (!ht_cleanup_thread) {
                retval = -1;
                goto exit_ht_cleanup;
        }
 
        /* Create thread quit pipe */
-       if (init_thread_quit_pipe()) {
+       if (sessiond_init_thread_quit_pipe()) {
                retval = -1;
                goto exit_init_data;
        }
 
        /* Check if daemon is UID = 0 */
        is_root = !getuid();
-
-       if (create_lttng_rundir()) {
-               retval = -1;
-               goto exit_init_data;
-       }
-
        if (is_root) {
                /* Create global run dir with root access */
 
@@ -5863,25 +5667,6 @@ int main(int argc, char **argv)
                        retval = -1;
                        goto exit_init_data;
                }
-               kernel_channel_rotate_pipe = lttng_pipe_open(0);
-               if (!kernel_channel_rotate_pipe) {
-                       ERR("Failed to create kernel consumer channel rotate pipe");
-                       retval = -1;
-                       goto exit_init_data;
-               }
-               kconsumer_data.channel_rotate_pipe =
-                               lttng_pipe_release_writefd(
-                                       kernel_channel_rotate_pipe);
-               if (kconsumer_data.channel_rotate_pipe < 0) {
-                       retval = -1;
-                       goto exit_init_data;
-               }
-       }
-
-       lockfile_fd = create_lockfile();
-       if (lockfile_fd < 0) {
-               retval = -1;
-               goto exit_init_data;
        }
 
        /* Set consumer initial state */
@@ -5900,30 +5685,18 @@ int main(int argc, char **argv)
                retval = -1;
                goto exit_init_data;
        }
-       ust32_channel_rotate_pipe = lttng_pipe_open(0);
-       if (!ust32_channel_rotate_pipe) {
-               ERR("Failed to create 32-bit user space consumer channel rotate pipe");
-               retval = -1;
-               goto exit_init_data;
-       }
-       ustconsumer32_data.channel_rotate_pipe = lttng_pipe_release_writefd(
-                       ust32_channel_rotate_pipe);
-       if (ustconsumer32_data.channel_rotate_pipe < 0) {
-               retval = -1;
-               goto exit_init_data;
-       }
 
        /*
-        * The rotation_timer_queue structure is shared between the sessiond timer
-        * thread and the rotation thread. The main() keeps the ownership and
-        * destroys it when both threads have quit.
+        * The rotation_thread_timer_queue structure is shared between the
+        * sessiond timer thread and the rotation thread. The main thread keeps
+        * its ownership and destroys it when both threads have been joined.
         */
-       rotation_timer_queue = create_rotate_timer_queue();
+       rotation_timer_queue = rotation_thread_timer_queue_create();
        if (!rotation_timer_queue) {
                retval = -1;
                goto exit_init_data;
        }
-       timer_thread_ctx.rotation_timer_queue = rotation_timer_queue;
+       timer_thread_ctx.rotation_thread_job_queue = rotation_timer_queue;
 
        ust64_channel_monitor_pipe = lttng_pipe_open(0);
        if (!ust64_channel_monitor_pipe) {
@@ -5937,31 +5710,6 @@ int main(int argc, char **argv)
                retval = -1;
                goto exit_init_data;
        }
-       ust64_channel_rotate_pipe = lttng_pipe_open(0);
-       if (!ust64_channel_rotate_pipe) {
-               ERR("Failed to create 64-bit user space consumer channel rotate pipe");
-               retval = -1;
-               goto exit_init_data;
-       }
-       ustconsumer64_data.channel_rotate_pipe = lttng_pipe_release_writefd(
-                       ust64_channel_rotate_pipe);
-       if (ustconsumer64_data.channel_rotate_pipe < 0) {
-               retval = -1;
-               goto exit_init_data;
-       }
-
-       /*
-        * See if daemon already exist.
-        */
-       if (check_existing_daemon()) {
-               ERR("Already running daemon.\n");
-               /*
-                * We do not goto exit because we must not cleanup()
-                * because a daemon is already running.
-                */
-               retval = -1;
-               goto exit_init_data;
-       }
 
        /*
         * Init UST app hash table. Alloc hash table before this point since
@@ -6068,12 +5816,6 @@ int main(int argc, char **argv)
        /* Init UST command queue. */
        cds_wfcq_init(&ust_cmd_queue.head, &ust_cmd_queue.tail);
 
-       /*
-        * Get session list pointer. This pointer MUST NOT be free'd. This list
-        * is statically declared in session.c
-        */
-       session_list_ptr = session_get_list();
-
        cmd_init();
 
        /* Check for the application socket timeout env variable. */
@@ -6090,12 +5832,6 @@ int main(int argc, char **argv)
                retval = -1;
                goto exit_init_data;
        }
-       ret = write_agent_port();
-       if (ret) {
-               ERR("Error in write_agent_port");
-               retval = -1;
-               goto exit_init_data;
-       }
 
        /* Initialize communication library */
        lttcomm_init();
@@ -6109,50 +5845,32 @@ int main(int argc, char **argv)
        load_info->path = config.load_session_path.value;
 
        /* Create health-check thread. */
-       ret = pthread_create(&health_thread, default_pthread_attr(),
-                       thread_manage_health, (void *) NULL);
-       if (ret) {
-               errno = ret;
-               PERROR("pthread_create health");
+       if (!launch_health_management_thread()) {
                retval = -1;
                goto exit_health;
        }
 
-       /*
-        * The rotation thread needs the notification thread to be ready before
-        * creating the rotate_notification_channel, so we use this semaphore as
-        * a rendez-vous point.
-        */
-       sem_init(&notification_thread_ready, 0, 0);
-
        /* 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,
-                       &notification_thread_ready);
+                       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");
+       if (!launch_notification_thread(notification_thread_handle)) {
                retval = -1;
-               stop_threads();
                goto exit_notification;
+
        }
-       notification_thread_running = true;
 
        /* Create timer thread. */
        ret = pthread_create(&timer_thread, default_pthread_attr(),
-                       sessiond_timer_thread, &timer_thread_ctx);
+                       timer_thread_func, &timer_thread_ctx);
        if (ret) {
                errno = ret;
                PERROR("pthread_create timer");
@@ -6160,17 +5878,12 @@ int main(int argc, char **argv)
                stop_threads();
                goto exit_notification;
        }
-       timer_thread_running = true;
+       timer_thread_launched = true;
 
        /* rotation_thread_data acquires the pipes' read side. */
        rotation_thread_handle = rotation_thread_handle_create(
-                       ust32_channel_rotate_pipe,
-                       ust64_channel_rotate_pipe,
-                       kernel_channel_rotate_pipe,
-                       thread_quit_pipe[0],
                        rotation_timer_queue,
-                       notification_thread_handle,
-                       &notification_thread_ready);
+                       notification_thread_handle);
        if (!rotation_thread_handle) {
                retval = -1;
                ERR("Failed to create rotation thread shared data");
@@ -6188,7 +5901,7 @@ int main(int argc, char **argv)
                stop_threads();
                goto exit_rotation;
        }
-       rotation_thread_running = true;
+       rotation_thread_launched = true;
 
        /* Create thread to manage the client socket */
        ret = pthread_create(&client_thread, default_pthread_attr(),
@@ -6292,6 +6005,10 @@ int main(int argc, char **argv)
                PERROR("pthread_join load_session_thread");
                retval = -1;
        }
+
+       /* Initiate teardown once activity occurs on the quit pipe. */
+       sessiond_wait_for_quit_pipe(-1U);
+       destroy_all_sessions_and_wait();
 exit_load_session:
 
        if (is_root && !config.no_kernel) {
@@ -6358,14 +6075,7 @@ exit_dispatch:
 exit_client:
 exit_rotation:
 exit_notification:
-       sem_destroy(&notification_thread_ready);
-       ret = pthread_join(health_thread, &status);
-       if (ret) {
-               errno = ret;
-               PERROR("pthread_join health thread");
-               retval = -1;
-       }
-
+       lttng_thread_list_shutdown_orphans();
 exit_health:
 exit_init_data:
        /*
@@ -6388,27 +6098,8 @@ exit_init_data:
         */
        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);
-       }
-
        if (rotation_thread_handle) {
-               if (rotation_thread_running) {
+               if (rotation_thread_launched) {
                        ret = pthread_join(rotation_thread, &status);
                        if (ret) {
                                errno = ret;
@@ -6419,8 +6110,8 @@ exit_init_data:
                rotation_thread_handle_destroy(rotation_thread_handle);
        }
 
-       if (timer_thread_running) {
-               kill(getpid(), LTTNG_SESSIOND_SIG_EXIT);
+       if (timer_thread_launched) {
+               timer_exit();
                ret = pthread_join(timer_thread, &status);
                if (ret) {
                        errno = ret;
@@ -6429,25 +6120,31 @@ exit_init_data:
                }
        }
 
+       if (ht_cleanup_thread) {
+               lttng_thread_shutdown(ht_cleanup_thread);
+               lttng_thread_put(ht_cleanup_thread);
+       }
+
        /*
         * After the rotation and timer thread have quit, we can safely destroy
         * the rotation_timer_queue.
         */
-       destroy_rotate_timer_queue(rotation_timer_queue);
+       rotation_thread_timer_queue_destroy(rotation_timer_queue);
 
        rcu_thread_offline();
        rcu_unregister_thread();
 
-       ret = fini_ht_cleanup_thread(&ht_cleanup_thread);
-       if (ret) {
-               retval = -1;
+       /*
+        * 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) {
+               notification_thread_handle_destroy(notification_thread_handle);
        }
        lttng_pipe_destroy(ust32_channel_monitor_pipe);
        lttng_pipe_destroy(ust64_channel_monitor_pipe);
        lttng_pipe_destroy(kernel_channel_monitor_pipe);
-       lttng_pipe_destroy(ust32_channel_rotate_pipe);
-       lttng_pipe_destroy(ust64_channel_rotate_pipe);
-       lttng_pipe_destroy(kernel_channel_rotate_pipe);
 exit_ht_cleanup:
 
        health_app_destroy(health_sessiond);
@@ -6455,6 +6152,7 @@ exit_health_sessiond_cleanup:
 exit_create_run_as_worker_cleanup:
 
 exit_options:
+       sessiond_cleanup_lock_file();
        sessiond_cleanup_options();
 
 exit_set_signal_handler:
This page took 0.045081 seconds and 5 git commands to generate.