Fix: add -b, --background option
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index de4736643010143c6af8c7a554f1682ddaebc651..bbdf141b2409825ee1b900453b2914ec03d7c9d3 100644 (file)
@@ -20,6 +20,7 @@
 #include <getopt.h>
 #include <grp.h>
 #include <limits.h>
+#include <paths.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdio.h>
@@ -44,6 +45,7 @@
 #include <common/futex.h>
 #include <common/relayd/relayd.h>
 #include <common/utils.h>
+#include <common/daemonize.h>
 
 #include "lttng-sessiond.h"
 #include "buffer-registry.h"
@@ -63,6 +65,7 @@
 #include "health-sessiond.h"
 #include "testpoint.h"
 #include "ust-thread.h"
+#include "jul-thread.h"
 
 #define CONSUMERD_FILE "lttng-consumerd"
 
@@ -71,12 +74,16 @@ static const char *tracing_group_name = DEFAULT_TRACING_GROUP;
 static const char *opt_pidfile;
 static int opt_sig_parent;
 static int opt_verbose_consumer;
-static int opt_daemon;
+static int opt_daemon, opt_background;
 static int opt_no_kernel;
 static int is_root;                    /* Set to 1 if the daemon is running as root */
 static pid_t ppid;          /* Parent PID for --sig-parent option */
+static pid_t child_ppid;    /* Internal parent PID use with daemonize. */
 static char *rundir;
 
+/* Set to 1 when a SIGUSR1 signal is received. */
+static int recv_child_signal;
+
 /*
  * Consumer daemon specific control data. Every value not initialized here is
  * set to 0 by the static definition.
@@ -156,6 +163,7 @@ static pthread_t kernel_thread;
 static pthread_t dispatch_thread;
 static pthread_t health_thread;
 static pthread_t ht_cleanup_thread;
+static pthread_t jul_reg_thread;
 
 /*
  * UST registration command queue. This queue is tied with a futex and uses a N
@@ -233,6 +241,41 @@ long page_size;
 /* Application health monitoring */
 struct health_app *health_sessiond;
 
+/* JUL TCP port for registration. Used by the JUL thread. */
+unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT;
+
+/*
+ * Whether sessiond is ready for commands/health check requests.
+ * NR_LTTNG_SESSIOND_READY must match the number of calls to
+ * lttng_sessiond_notify_ready().
+ */
+#define NR_LTTNG_SESSIOND_READY                2
+int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY;
+
+/* Notify parents that we are ready for cmd and health check */
+static
+void lttng_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 (opt_sig_parent) {
+                       kill(ppid, SIGUSR1);
+               }
+
+               /*
+                * Notify the parent of the fork() process that we are
+                * ready.
+                */
+               if (opt_daemon || opt_background) {
+                       kill(child_ppid, SIGUSR1);
+               }
+       }
+}
+
 static
 void setup_consumerd_path(void)
 {
@@ -450,6 +493,11 @@ static void cleanup(void)
        DBG("Removing %s", path);
        (void) unlink(path);
 
+       snprintf(path, PATH_MAX, "%s/%s", rundir,
+                       DEFAULT_LTTNG_SESSIOND_JULPORT_FILE);
+       DBG("Removing %s", path);
+       (void) unlink(path);
+
        /* kconsumerd */
        snprintf(path, PATH_MAX,
                DEFAULT_KCONSUMERD_ERR_SOCK_PATH,
@@ -489,6 +537,12 @@ static void cleanup(void)
        DBG("Removing directory %s", path);
        (void) rmdir(path);
 
+       /*
+        * We do NOT rmdir rundir because there are other processes
+        * using it, for instance lttng-relayd, which can start in
+        * parallel with this teardown.
+        */
+
        free(rundir);
 
        DBG("Cleaning up all sessions");
@@ -780,13 +834,13 @@ static void *thread_manage_kernel(void *data)
         */
        lttng_poll_init(&events);
 
-       if (testpoint(thread_manage_kernel)) {
+       if (testpoint(sessiond_thread_manage_kernel)) {
                goto error_testpoint;
        }
 
        health_code_update();
 
-       if (testpoint(thread_manage_kernel_before_loop)) {
+       if (testpoint(sessiond_thread_manage_kernel_before_loop)) {
                goto error_testpoint;
        }
 
@@ -855,9 +909,8 @@ static void *thread_manage_kernel(void *data)
 
                        /* Check for data on kernel pipe */
                        if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) {
-                               do {
-                                       ret = read(kernel_poll_pipe[0], &tmp, 1);
-                               } while (ret < 0 && errno == EINTR);
+                               (void) lttng_read(kernel_poll_pipe[0],
+                                       &tmp, 1);
                                /*
                                 * Ret value is useless here, if this pipe gets any actions an
                                 * update is required anyway.
@@ -967,7 +1020,7 @@ static void *thread_manage_consumer(void *data)
 restart:
        health_poll_entry();
 
-       if (testpoint(thread_manage_consumer)) {
+       if (testpoint(sessiond_thread_manage_consumer)) {
                goto error;
        }
 
@@ -1229,6 +1282,7 @@ error_poll:
 static void *thread_manage_apps(void *data)
 {
        int i, ret, pollfd, err = -1;
+       ssize_t size_ret;
        uint32_t revents, nb_fd;
        struct lttng_poll_event events;
 
@@ -1239,7 +1293,7 @@ static void *thread_manage_apps(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_MANAGE);
 
-       if (testpoint(thread_manage_apps)) {
+       if (testpoint(sessiond_thread_manage_apps)) {
                goto error_testpoint;
        }
 
@@ -1255,7 +1309,7 @@ static void *thread_manage_apps(void *data)
                goto error;
        }
 
-       if (testpoint(thread_manage_apps_before_loop)) {
+       if (testpoint(sessiond_thread_manage_apps_before_loop)) {
                goto error;
        }
 
@@ -1304,10 +1358,8 @@ static void *thread_manage_apps(void *data)
                                        int sock;
 
                                        /* Empty pipe */
-                                       do {
-                                               ret = read(apps_cmd_pipe[0], &sock, sizeof(sock));
-                                       } while (ret < 0 && errno == EINTR);
-                                       if (ret < 0 || ret < sizeof(sock)) {
+                                       size_ret = lttng_read(apps_cmd_pipe[0], &sock, sizeof(sock));
+                                       if (size_ret < sizeof(sock)) {
                                                PERROR("read apps cmd pipe");
                                                goto error;
                                        }
@@ -1325,23 +1377,7 @@ static void *thread_manage_apps(void *data)
                                                goto error;
                                        }
 
-                                       /*
-                                        * Set socket timeout for both receiving and ending.
-                                        * app_socket_timeout is in seconds, whereas
-                                        * lttcomm_setsockopt_rcv_timeout and
-                                        * 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);
-
                                        DBG("Apps with sock %d added to poll set", sock);
-
-                                       health_code_update();
-
-                                       break;
                                }
                        } else {
                                /*
@@ -1357,7 +1393,6 @@ static void *thread_manage_apps(void *data)
 
                                        /* Socket closed on remote end. */
                                        ust_app_unregister(pollfd);
-                                       break;
                                }
                        }
 
@@ -1402,7 +1437,7 @@ error_testpoint:
  */
 static int send_socket_to_thread(int fd, int sock)
 {
-       int ret;
+       ssize_t ret;
 
        /*
         * It's possible that the FD is set as invalid with -1 concurrently just
@@ -1413,10 +1448,8 @@ static int send_socket_to_thread(int fd, int sock)
                goto error;
        }
 
-       do {
-               ret = write(fd, &sock, sizeof(sock));
-       } while (ret < 0 && errno == EINTR);
-       if (ret < 0 || ret != sizeof(sock)) {
+       ret = lttng_write(fd, &sock, sizeof(sock));
+       if (ret < sizeof(sock)) {
                PERROR("write apps pipe %d", fd);
                if (ret < 0) {
                        ret = -errno;
@@ -1427,7 +1460,7 @@ static int send_socket_to_thread(int fd, int sock)
        /* All good. Don't send back the write positive ret value. */
        ret = 0;
 error:
-       return ret;
+       return (int) ret;
 }
 
 /*
@@ -1531,6 +1564,10 @@ static void *thread_dispatch_ust_registration(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH);
 
+       if (testpoint(sessiond_thread_app_reg_dispatch)) {
+               goto error_testpoint;
+       }
+
        health_code_update();
 
        CDS_INIT_LIST_HEAD(&wait_queue.head);
@@ -1580,7 +1617,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                        if (ret < 0) {
                                                PERROR("close ust sock dispatch %d", ust_cmd->sock);
                                        }
-                                       lttng_fd_put(1, LTTNG_FD_APPS);
+                                       lttng_fd_put(LTTNG_FD_APPS, 1);
                                        free(ust_cmd);
                                        goto error;
                                }
@@ -1594,7 +1631,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                        if (ret < 0) {
                                                PERROR("close ust sock dispatch %d", ust_cmd->sock);
                                        }
-                                       lttng_fd_put(1, LTTNG_FD_APPS);
+                                       lttng_fd_put(LTTNG_FD_APPS, 1);
                                        free(wait_node);
                                        free(ust_cmd);
                                        continue;
@@ -1642,7 +1679,7 @@ static void *thread_dispatch_ust_registration(void *data)
                                        if (ret < 0) {
                                                PERROR("close ust sock dispatch %d", ust_cmd->sock);
                                        }
-                                       lttng_fd_put(1, LTTNG_FD_APPS);
+                                       lttng_fd_put(LTTNG_FD_APPS, 1);
                                }
                                free(ust_cmd);
                        }
@@ -1735,6 +1772,7 @@ error:
                free(wait_node);
        }
 
+error_testpoint:
        DBG("Dispatch thread dying");
        if (err) {
                health_error();
@@ -1762,7 +1800,7 @@ static void *thread_registration_apps(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG);
 
-       if (testpoint(thread_registration_apps)) {
+       if (testpoint(sessiond_thread_registration_apps)) {
                goto error_testpoint;
        }
 
@@ -1839,6 +1877,18 @@ static void *thread_registration_apps(void *data)
                                                goto error;
                                        }
 
+                                       /*
+                                        * Set socket timeout for both receiving and ending.
+                                        * app_socket_timeout is in seconds, whereas
+                                        * lttcomm_setsockopt_rcv_timeout and
+                                        * 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);
+
                                        /*
                                         * Set the CLOEXEC flag. Return code is useless because
                                         * either way, the show must go on.
@@ -1911,11 +1961,6 @@ static void *thread_registration_apps(void *data)
 
 exit:
 error:
-       if (err) {
-               health_error();
-               ERR("Health error occurred in %s", __func__);
-       }
-
        /* Notify that the registration thread is gone */
        notify_ust_apps(0);
 
@@ -1940,6 +1985,10 @@ error_listen:
 error_create_poll:
 error_testpoint:
        DBG("UST Registration thread cleanup complete");
+       if (err) {
+               health_error();
+               ERR("Health error occurred in %s", __func__);
+       }
        health_unregister(health_sessiond);
 
        return NULL;
@@ -2410,6 +2459,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
                consumer = session->kernel_session->consumer;
                dir_name = DEFAULT_KERNEL_TRACE_DIR;
                break;
+       case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_UST:
                DBG3("Copying tracing session consumer output in UST session");
                if (session->ust_session->consumer) {
@@ -2453,6 +2503,7 @@ static int create_ust_session(struct ltt_session *session,
        assert(session->consumer);
 
        switch (domain->type) {
+       case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_UST:
                break;
        default:
@@ -2744,6 +2795,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
                }
 
                break;
+       case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_UST:
        {
                if (!ust_app_supported()) {
@@ -2835,6 +2887,7 @@ skip_domain:
        if (cmd_ctx->lsm->cmd_type == LTTNG_START_TRACE ||
                        cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) {
                switch (cmd_ctx->lsm->domain.type) {
+               case LTTNG_DOMAIN_JUL:
                case LTTNG_DOMAIN_UST:
                        if (uatomic_read(&ust_consumerd_state) != CONSUMER_STARTED) {
                                ret = LTTNG_ERR_NO_USTCONSUMERD;
@@ -2916,9 +2969,74 @@ skip_domain:
        }
        case LTTNG_ENABLE_EVENT:
        {
+               struct lttng_event_exclusion *exclusion = NULL;
+               struct lttng_filter_bytecode *bytecode = NULL;
+
+               /* Handle exclusion events and receive it from the client. */
+               if (cmd_ctx->lsm->u.enable.exclusion_count > 0) {
+                       size_t count = cmd_ctx->lsm->u.enable.exclusion_count;
+
+                       exclusion = zmalloc(sizeof(struct lttng_event_exclusion) +
+                                       (count * LTTNG_SYMBOL_NAME_LEN));
+                       if (!exclusion) {
+                               ret = LTTNG_ERR_EXCLUSION_NOMEM;
+                               goto error;
+                       }
+
+                       DBG("Receiving var len exclusion event list from client ...");
+                       exclusion->count = count;
+                       ret = lttcomm_recv_unix_sock(sock, exclusion->names,
+                                       count * LTTNG_SYMBOL_NAME_LEN);
+                       if (ret <= 0) {
+                               DBG("Nothing recv() from client var len data... continuing");
+                               *sock_error = 1;
+                               free(exclusion);
+                               ret = LTTNG_ERR_EXCLUSION_INVAL;
+                               goto error;
+                       }
+               }
+
+               /* Handle filter and get bytecode from client. */
+               if (cmd_ctx->lsm->u.enable.bytecode_len > 0) {
+                       size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len;
+
+                       if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               free(exclusion);
+                               goto error;
+                       }
+
+                       bytecode = zmalloc(bytecode_len);
+                       if (!bytecode) {
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_NOMEM;
+                               goto error;
+                       }
+
+                       /* Receive var. len. data */
+                       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");
+                               *sock_error = 1;
+                               free(bytecode);
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               goto error;
+                       }
+
+                       if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) {
+                               free(bytecode);
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               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, NULL, kernel_poll_pipe[1]);
+                               &cmd_ctx->lsm->u.enable.event, bytecode, exclusion,
+                               kernel_poll_pipe[1]);
                break;
        }
        case LTTNG_ENABLE_ALL_EVENT:
@@ -3242,46 +3360,6 @@ skip_domain:
                                cmd_ctx->lsm->u.reg.path, cdata);
                break;
        }
-       case LTTNG_ENABLE_EVENT_WITH_FILTER:
-       {
-               struct lttng_filter_bytecode *bytecode;
-
-               if (cmd_ctx->lsm->u.enable.bytecode_len > LTTNG_FILTER_MAX_LEN) {
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-               if (cmd_ctx->lsm->u.enable.bytecode_len == 0) {
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-               bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len);
-               if (!bytecode) {
-                       ret = LTTNG_ERR_FILTER_NOMEM;
-                       goto error;
-               }
-               /* Receive var. len. data */
-               DBG("Receiving var len data from client ...");
-               ret = lttcomm_recv_unix_sock(sock, bytecode,
-                               cmd_ctx->lsm->u.enable.bytecode_len);
-               if (ret <= 0) {
-                       DBG("Nothing recv() from client var len data... continuing");
-                       *sock_error = 1;
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-
-               if (bytecode->len + sizeof(*bytecode)
-                               != cmd_ctx->lsm->u.enable.bytecode_len) {
-                       free(bytecode);
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       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, bytecode, kernel_poll_pipe[1]);
-               break;
-       }
        case LTTNG_DATA_PENDING:
        {
                ret = cmd_data_pending(cmd_ctx->session);
@@ -3524,6 +3602,8 @@ static void *thread_manage_health(void *data)
                goto error;
        }
 
+       lttng_sessiond_notify_ready();
+
        while (1) {
                DBG("Health check ready");
 
@@ -3652,10 +3732,6 @@ static void *thread_manage_clients(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CMD);
 
-       if (testpoint(thread_manage_clients)) {
-               goto error_testpoint;
-       }
-
        health_code_update();
 
        ret = lttcomm_listen_unix_sock(client_sock);
@@ -3678,14 +3754,14 @@ static void *thread_manage_clients(void *data)
                goto error;
        }
 
-       /*
-        * Notify parent pid that we are ready to accept command for client side.
-        */
-       if (opt_sig_parent) {
-               kill(ppid, SIGUSR1);
+       lttng_sessiond_notify_ready();
+
+       /* This testpoint is after we signal readiness to the parent. */
+       if (testpoint(sessiond_thread_manage_clients)) {
+               goto error;
        }
 
-       if (testpoint(thread_manage_clients_before_loop)) {
+       if (testpoint(sessiond_thread_manage_clients_before_loop)) {
                goto error;
        }
 
@@ -3860,7 +3936,6 @@ error:
 
 error_listen:
 error_create_poll:
-error_testpoint:
        unlink(client_unix_sock_path);
        if (client_sock >= 0) {
                ret = close(client_sock);
@@ -3903,14 +3978,16 @@ static void usage(void)
        fprintf(stderr, "      --consumerd64-path PATH     Specify path for the 64-bit UST consumer daemon binary\n");
        fprintf(stderr, "      --consumerd64-libdir PATH   Specify path for the 64-bit UST consumer daemon libraries\n");
        fprintf(stderr, "  -d, --daemonize                    Start as a daemon.\n");
+       fprintf(stderr, "  -b, --background                   Start as a daemon, keeping console open.\n");
        fprintf(stderr, "  -g, --group NAME                   Specify the tracing group name. (default: tracing)\n");
        fprintf(stderr, "  -V, --version                      Show version number.\n");
-       fprintf(stderr, "  -S, --sig-parent                   Send SIGCHLD to parent pid to notify readiness.\n");
+       fprintf(stderr, "  -S, --sig-parent                   Send SIGUSR1 to parent pid to notify readiness.\n");
        fprintf(stderr, "  -q, --quiet                        No output at all.\n");
        fprintf(stderr, "  -v, --verbose                      Verbose mode. Activate DBG() macro.\n");
        fprintf(stderr, "  -p, --pidfile FILE                 Write a pid to FILE name overriding the default value.\n");
        fprintf(stderr, "      --verbose-consumer             Verbose mode for consumer. Activate DBG() macro.\n");
        fprintf(stderr, "      --no-kernel                    Disable kernel tracer\n");
+       fprintf(stderr, "      --jul-tcp-port                 JUL application registration TCP port\n");
 }
 
 /*
@@ -3943,12 +4020,14 @@ static int parse_args(int argc, char **argv)
                { "verbose-consumer", 0, 0, 'Z' },
                { "no-kernel", 0, 0, 'N' },
                { "pidfile", 1, 0, 'p' },
+               { "jul-tcp-port", 1, 0, 'J' },
+               { "background", 0, 0, 'b' },
                { NULL, 0, 0, 0 }
        };
 
        while (1) {
                int option_index = 0;
-               c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:",
+               c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:b",
                                long_options, &option_index);
                if (c == -1) {
                        break;
@@ -3970,6 +4049,9 @@ static int parse_args(int argc, char **argv)
                case 'd':
                        opt_daemon = 1;
                        break;
+               case 'b':
+                       opt_background = 1;
+                       break;
                case 'g':
                        tracing_group_name = optarg;
                        break;
@@ -4028,6 +4110,24 @@ static int parse_args(int argc, char **argv)
                case 'p':
                        opt_pidfile = optarg;
                        break;
+               case 'J': /* JUL TCP port. */
+               {
+                       unsigned long v;
+
+                       errno = 0;
+                       v = strtoul(optarg, NULL, 0);
+                       if (errno != 0 || !isdigit(optarg[0])) {
+                               ERR("Wrong value in --jul-tcp-port parameter: %s", optarg);
+                               return -1;
+                       }
+                       if (v == 0 || v >= 65535) {
+                               ERR("Port overflow in --jul-tcp-port parameter: %s", optarg);
+                               return -1;
+                       }
+                       jul_tcp_port = (uint32_t) v;
+                       DBG3("JUL TCP port set to non default: %u", jul_tcp_port);
+                       break;
+               }
                default:
                        /* Unknown option or other error.
                         * Error is printed by getopt, just return */
@@ -4306,6 +4406,9 @@ static void sighandler(int sig)
                DBG("SIGTERM caught");
                stop_threads();
                break;
+       case SIGUSR1:
+               CMM_STORE_SHARED(recv_child_signal, 1);
+               break;
        default:
                break;
        }
@@ -4344,7 +4447,12 @@ static int set_signal_handler(void)
                return ret;
        }
 
-       DBG("Signal handler set for SIGTERM, SIGPIPE and SIGINT");
+       if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) {
+               PERROR("sigaction");
+               return ret;
+       }
+
+       DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE and SIGINT");
 
        return ret;
 }
@@ -4400,6 +4508,34 @@ error:
        return;
 }
 
+/*
+ * Write JUL TCP port using the rundir.
+ */
+static void write_julport(void)
+{
+       int ret;
+       char path[PATH_MAX];
+
+       assert(rundir);
+
+       ret = snprintf(path, sizeof(path), "%s/"
+                       DEFAULT_LTTNG_SESSIOND_JULPORT_FILE, rundir);
+       if (ret < 0) {
+               PERROR("snprintf julport path");
+               goto error;
+       }
+
+       /*
+        * Create TCP JUL port file in rundir. Return value is of no importance.
+        * The execution will continue even though we are not able to write the
+        * file.
+        */
+       (void) utils_create_pid_file(jul_tcp_port, path);
+
+error:
+       return;
+}
+
 /*
  * main
  */
@@ -4413,6 +4549,10 @@ int main(int argc, char **argv)
 
        rcu_register_thread();
 
+       if ((ret = set_signal_handler()) < 0) {
+               goto error;
+       }
+
        setup_consumerd_path();
 
        page_size = sysconf(_SC_PAGESIZE);
@@ -4429,23 +4569,19 @@ int main(int argc, char **argv)
        }
 
        /* Daemonize */
-       if (opt_daemon) {
+       if (opt_daemon || opt_background) {
                int i;
 
-               /*
-                * fork
-                * child: setsid, close FD 0, 1, 2, chdir /
-                * parent: exit (if fork is successful)
-                */
-               ret = daemon(0, 0);
+               ret = lttng_daemonize(&child_ppid, &recv_child_signal,
+                       !opt_background);
                if (ret < 0) {
-                       PERROR("daemon");
                        goto error;
                }
+
                /*
-                * 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.
+                * We are in the child. Make sure all other file descriptors are
+                * closed, in case we are called with more opened file descriptors than
+                * the standard ones.
                 */
                for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
                        (void) close(i);
@@ -4597,6 +4733,12 @@ int main(int argc, char **argv)
         */
        ust_app_ht_alloc();
 
+       /* Initialize JUL domain subsystem. */
+       if ((ret = jul_init()) < 0) {
+               /* ENOMEM at this point. */
+               goto error;
+       }
+
        /* After this point, we can safely call cleanup() with "goto exit" */
 
        /*
@@ -4632,10 +4774,6 @@ int main(int argc, char **argv)
                goto exit;
        }
 
-       if ((ret = set_signal_handler()) < 0) {
-               goto exit;
-       }
-
        /* Setup the needed unix socket */
        if ((ret = init_daemon_socket()) < 0) {
                goto exit;
@@ -4700,6 +4838,7 @@ int main(int argc, char **argv)
        }
 
        write_pidfile();
+       write_julport();
 
        /* Initialize communication library */
        lttcomm_init();
@@ -4716,7 +4855,7 @@ int main(int argc, char **argv)
                goto exit_health_sessiond_cleanup;
        }
 
-       /* Create thread to manage the client socket */
+       /* Create thread to clean up RCU hash tables */
        ret = pthread_create(&ht_cleanup_thread, NULL,
                        thread_ht_cleanup, (void *) NULL);
        if (ret != 0) {
@@ -4724,7 +4863,7 @@ int main(int argc, char **argv)
                goto exit_ht_cleanup;
        }
 
-       /* Create thread to manage the client socket */
+       /* Create health-check thread */
        ret = pthread_create(&health_thread, NULL,
                        thread_manage_health, (void *) NULL);
        if (ret != 0) {
@@ -4772,6 +4911,14 @@ int main(int argc, char **argv)
                goto exit_apps_notify;
        }
 
+       /* Create JUL registration thread. */
+       ret = pthread_create(&jul_reg_thread, NULL,
+                       jul_thread_manage_registration, (void *) NULL);
+       if (ret != 0) {
+               PERROR("pthread_create apps");
+               goto exit_jul_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 */
@@ -4790,6 +4937,13 @@ int main(int argc, char **argv)
        }
 
 exit_kernel:
+       ret = pthread_join(jul_reg_thread, &status);
+       if (ret != 0) {
+               PERROR("pthread_join JUL");
+               goto error;     /* join error, exit without cleanup */
+       }
+
+exit_jul_reg:
        ret = pthread_join(apps_notify_thread, &status);
        if (ret != 0) {
                PERROR("pthread_join apps notify");
This page took 0.034602 seconds and 4 git commands to generate.