Fix: thread exit vs futex wait/wakeup race
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index 65f598b602fbe92830a7f62595bfd495a881634a..50eead010a3e2e72b053f4c899a49a2a02f86042 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/wait.h>
 #include <urcu/uatomic.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include <common/common.h>
 #include <common/compat/socket.h>
@@ -604,8 +605,7 @@ static void wait_consumer(struct consumer_data *consumer_data)
        ret = waitpid(consumer_data->pid, &status, 0);
        if (ret == -1) {
                PERROR("consumerd waitpid pid: %d", consumer_data->pid)
-       }
-       if (!WIFEXITED(status)) {
+       } else  if (!WIFEXITED(status)) {
                ERR("consumerd termination with error: %d",
                                WEXITSTATUS(ret));
        }
@@ -1902,6 +1902,8 @@ static void *thread_dispatch_ust_registration(void *data)
                .count = 0,
        };
 
+       rcu_register_thread();
+
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH);
 
        if (testpoint(sessiond_thread_app_reg_dispatch)) {
@@ -1914,12 +1916,16 @@ static void *thread_dispatch_ust_registration(void *data)
 
        DBG("[thread] Dispatch UST command started");
 
-       while (!CMM_LOAD_SHARED(dispatch_thread_exit)) {
+       for (;;) {
                health_code_update();
 
                /* Atomically prepare the queue futex */
                futex_nto1_prepare(&ust_cmd_queue.futex);
 
+               if (CMM_LOAD_SHARED(dispatch_thread_exit)) {
+                       break;
+               }
+
                do {
                        struct ust_app *app = NULL;
                        ust_cmd = NULL;
@@ -2135,6 +2141,7 @@ error_testpoint:
                ERR("Health error occurred in %s", __func__);
        }
        health_unregister(health_sessiond);
+       rcu_unregister_thread();
        return NULL;
 }
 
@@ -2242,10 +2249,12 @@ static void *thread_registration_apps(void *data)
                                         * lttcomm_setsockopt_snd_timeout expect msec as
                                         * parameter.
                                         */
-                                       (void) lttcomm_setsockopt_rcv_timeout(sock,
-                                                       app_socket_timeout * 1000);
-                                       (void) lttcomm_setsockopt_snd_timeout(sock,
-                                                       app_socket_timeout * 1000);
+                                       if (app_socket_timeout >= 0) {
+                                               (void) lttcomm_setsockopt_rcv_timeout(sock,
+                                                               app_socket_timeout * 1000);
+                                               (void) lttcomm_setsockopt_snd_timeout(sock,
+                                                               app_socket_timeout * 1000);
+                                       }
 
                                        /*
                                         * Set the CLOEXEC flag. Return code is useless because
@@ -3081,6 +3090,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_LIST_EVENTS:
        case LTTNG_LIST_SYSCALLS:
        case LTTNG_LIST_TRACKER_PIDS:
+       case LTTNG_DATA_PENDING:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -3317,6 +3327,8 @@ skip_domain:
        if (cmd_ctx->lsm->cmd_type == LTTNG_START_TRACE ||
                        cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) {
                switch (cmd_ctx->lsm->domain.type) {
+               case LTTNG_DOMAIN_NONE:
+                       break;
                case LTTNG_DOMAIN_JUL:
                case LTTNG_DOMAIN_LOG4J:
                case LTTNG_DOMAIN_PYTHON:
@@ -3332,6 +3344,9 @@ skip_domain:
                                goto error;
                        }
                        break;
+               default:
+                       ret = LTTNG_ERR_UNKNOWN_DOMAIN;
+                       goto error;
                }
        }
 
@@ -4365,7 +4380,7 @@ error:
        }
 
        lttng_poll_clean(&events);
-
+       stop_threads();
        rcu_unregister_thread();
        return NULL;
 }
@@ -4651,43 +4666,6 @@ error_create_poll:
        return NULL;
 }
 
-
-/*
- * usage function on stderr
- */
-static void usage(void)
-{
-       fprintf(stderr, "Usage: %s OPTIONS\n\nOptions:\n", progname);
-       fprintf(stderr, "  -h, --help                         Display this usage.\n");
-       fprintf(stderr, "  -c, --client-sock PATH             Specify path for the client unix socket\n");
-       fprintf(stderr, "  -a, --apps-sock PATH               Specify path for apps unix socket\n");
-       fprintf(stderr, "      --kconsumerd-err-sock PATH     Specify path for the kernel consumer error socket\n");
-       fprintf(stderr, "      --kconsumerd-cmd-sock PATH     Specify path for the kernel consumer command socket\n");
-       fprintf(stderr, "      --ustconsumerd32-err-sock PATH Specify path for the 32-bit UST consumer error socket\n");
-       fprintf(stderr, "      --ustconsumerd64-err-sock PATH Specify path for the 64-bit UST consumer error socket\n");
-       fprintf(stderr, "      --ustconsumerd32-cmd-sock PATH Specify path for the 32-bit UST consumer command socket\n");
-       fprintf(stderr, "      --ustconsumerd64-cmd-sock PATH Specify path for the 64-bit UST consumer command socket\n");
-       fprintf(stderr, "      --consumerd32-path PATH     Specify path for the 32-bit UST consumer daemon binary\n");
-       fprintf(stderr, "      --consumerd32-libdir PATH   Specify path for the 32-bit UST consumer daemon libraries\n");
-       fprintf(stderr, "      --consumerd64-path PATH     Specify path for the 64-bit UST consumer daemon binary\n");
-       fprintf(stderr, "      --consumerd64-libdir PATH   Specify path for the 64-bit UST consumer daemon libraries\n");
-       fprintf(stderr, "  -d, --daemonize                    Start as a daemon.\n");
-       fprintf(stderr, "  -b, --background                   Start as a daemon, keeping console open.\n");
-       fprintf(stderr, "  -g, --group NAME                   Specify the tracing group name. (default: tracing)\n");
-       fprintf(stderr, "  -V, --version                      Show version number.\n");
-       fprintf(stderr, "  -S, --sig-parent                   Send SIGUSR1 to parent pid to notify readiness.\n");
-       fprintf(stderr, "  -q, --quiet                        No output at all.\n");
-       fprintf(stderr, "  -v, --verbose                      Verbose mode. Activate DBG() macro.\n");
-       fprintf(stderr, "  -p, --pidfile FILE                 Write a pid to FILE name overriding the default value.\n");
-       fprintf(stderr, "      --verbose-consumer             Verbose mode for consumer. Activate DBG() macro.\n");
-       fprintf(stderr, "      --no-kernel                    Disable kernel tracer\n");
-       fprintf(stderr, "      --agent-tcp-port               Agent registration TCP port\n");
-       fprintf(stderr, "  -f  --config PATH                  Load daemon configuration file\n");
-       fprintf(stderr, "  -l  --load PATH                    Load session configuration\n");
-       fprintf(stderr, "      --kmod-probes                  Specify kernel module probes to load\n");
-       fprintf(stderr, "      --extra-kmod-probes            Specify extra kernel module probes to load\n");
-}
-
 static int string_match(const char *str1, const char *str2)
 {
        return (str1 && str2) && !strcmp(str1, str2);
@@ -4703,18 +4681,11 @@ static int set_option(int opt, const char *arg, const char *optname)
 {
        int ret = 0;
 
-       if (arg && arg[0] == '\0') {
-               /*
-                * This only happens if the value is read from daemon config
-                * file. This means the option requires an argument and the
-                * configuration file contains a line such as:
-                * my_option =
-                */
-               ret = -EINVAL;
-               goto end;
-       }
-
        if (string_match(optname, "client-sock") || opt == 'c') {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "-c, --client-sock");
@@ -4722,6 +4693,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(client_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "apps-sock") || opt == 'a') {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "-a, --apps-sock");
@@ -4733,6 +4708,10 @@ static int set_option(int opt, const char *arg, const char *optname)
        } else if (string_match(optname, "background") || opt == 'b') {
                opt_background = 1;
        } else if (string_match(optname, "group") || opt == 'g') {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "-g, --group");
@@ -4753,14 +4732,22 @@ static int set_option(int opt, const char *arg, const char *optname)
                        tracing_group_name_override = 1;
                }
        } else if (string_match(optname, "help") || opt == 'h') {
-               usage();
-               exit(EXIT_SUCCESS);
+               ret = utils_show_man_page(8, "lttng-sessiond");
+               if (ret) {
+                       ERR("Cannot view man page lttng-sessiond(8)");
+                       perror("exec");
+               }
+               exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
        } else if (string_match(optname, "version") || opt == 'V') {
                fprintf(stdout, "%s\n", VERSION);
                exit(EXIT_SUCCESS);
        } else if (string_match(optname, "sig-parent") || opt == 'S') {
                opt_sig_parent = 1;
        } else if (string_match(optname, "kconsumerd-err-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--kconsumerd-err-sock");
@@ -4768,6 +4755,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "kconsumerd-cmd-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--kconsumerd-cmd-sock");
@@ -4775,6 +4766,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "ustconsumerd64-err-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--ustconsumerd64-err-sock");
@@ -4782,6 +4777,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "ustconsumerd64-cmd-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--ustconsumerd64-cmd-sock");
@@ -4789,6 +4788,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "ustconsumerd32-err-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--ustconsumerd32-err-sock");
@@ -4796,6 +4799,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg);
                }
        } else if (string_match(optname, "ustconsumerd32-cmd-sock")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--ustconsumerd32-cmd-sock");
@@ -4822,9 +4829,13 @@ static int set_option(int opt, const char *arg, const char *optname)
                if (arg) {
                        opt_verbose_consumer = config_parse_value(arg);
                } else {
-                       opt_verbose_consumer += 1;
+                       opt_verbose_consumer++;
                }
        } else if (string_match(optname, "consumerd32-path")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--consumerd32-path");
@@ -4840,6 +4851,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        consumerd32_bin_override = 1;
                }
        } else if (string_match(optname, "consumerd32-libdir")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--consumerd32-libdir");
@@ -4855,6 +4870,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        consumerd32_libdir_override = 1;
                }
        } else if (string_match(optname, "consumerd64-path")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--consumerd64-path");
@@ -4870,6 +4889,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        consumerd64_bin_override = 1;
                }
        } else if (string_match(optname, "consumerd64-libdir")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--consumerd64-libdir");
@@ -4885,6 +4908,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        consumerd64_libdir_override = 1;
                }
        } else if (string_match(optname, "pidfile") || opt == 'p') {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "-p, --pidfile");
@@ -4897,6 +4924,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        }
                }
        } else if (string_match(optname, "agent-tcp-port")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--agent-tcp-port");
@@ -4921,6 +4952,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        DBG3("Agent TCP port set to non default: %u", agent_tcp_port);
                }
        } else if (string_match(optname, "load") || opt == 'l') {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "-l, --load");
@@ -4933,6 +4968,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        }
                }
        } else if (string_match(optname, "kmod-probes")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--kmod-probes");
@@ -4945,6 +4984,10 @@ static int set_option(int opt, const char *arg, const char *optname)
                        }
                }
        } else if (string_match(optname, "extra-kmod-probes")) {
+               if (!arg || *arg == '\0') {
+                       ret = -EINVAL;
+                       goto end;
+               }
                if (lttng_is_setuid_setgid()) {
                        WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
                                "--extra-kmod-probes");
@@ -5379,9 +5422,6 @@ error:
 static void sighandler(int sig)
 {
        switch (sig) {
-       case SIGPIPE:
-               DBG("SIGPIPE caught");
-               return;
        case SIGINT:
                DBG("SIGINT caught");
                stop_threads();
@@ -5413,9 +5453,10 @@ static int set_signal_handler(void)
                return ret;
        }
 
-       sa.sa_handler = sighandler;
        sa.sa_mask = sigset;
        sa.sa_flags = 0;
+
+       sa.sa_handler = sighandler;
        if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
                PERROR("sigaction");
                return ret;
@@ -5426,12 +5467,13 @@ static int set_signal_handler(void)
                return ret;
        }
 
-       if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
+       if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) {
                PERROR("sigaction");
                return ret;
        }
 
-       if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) {
+       sa.sa_handler = SIG_IGN;
+       if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
                PERROR("sigaction");
                return ret;
        }
@@ -5471,7 +5513,10 @@ static int write_pidfile(void)
        assert(rundir);
 
        if (opt_pidfile) {
-               strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path));
+               if (lttng_strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path))) {
+                       ret = -1;
+                       goto error;
+               }
        } else {
                /* Build pidfile path from rundir and opt_pidfile. */
                ret = snprintf(pidfile_path, sizeof(pidfile_path), "%s/"
@@ -6182,6 +6227,12 @@ exit_client:
 exit_health:
 
 exit_init_data:
+       /*
+        * Wait for all pending call_rcu work to complete before tearing
+        * down data structures. call_rcu worker may be trying to
+        * perform lookups in those structures.
+        */
+       rcu_barrier();
        /*
         * sessiond_cleanup() is called when no other thread is running, except
         * the ht_cleanup thread, which is needed to destroy the hash tables.
@@ -6191,6 +6242,13 @@ exit_init_data:
        rcu_thread_offline();
        rcu_unregister_thread();
 
+       /*
+        * Ensure all prior call_rcu are done. call_rcu callbacks may push
+        * hash tables to the ht_cleanup thread. Therefore, we ensure that
+        * the queue is empty before shutting down the clean-up thread.
+        */
+       rcu_barrier();
+
        ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]);
        if (ret < 0) {
                ERR("write error on ht_cleanup quit pipe");
@@ -6220,9 +6278,6 @@ exit_health_sessiond_cleanup:
 exit_create_run_as_worker_cleanup:
 
 exit_options:
-       /* Ensure all prior call_rcu are done. */
-       rcu_barrier();
-
        sessiond_cleanup_options();
 
 exit_set_signal_handler:
This page took 0.0298890000000001 seconds and 4 git commands to generate.