Fix handling of sessiond respawn after a SIGKILL
[lttng-tools.git] / ltt-sessiond / main.c
index 5636700d8fad1cd3127c9c6571b03a648782261d..1e2a0831dc80187b4b581e72ef97a037762a3fa4 100644 (file)
@@ -60,6 +60,7 @@ const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE;
 
 /* Variables */
 int opt_verbose;    /* Not static for lttngerr.h */
+int opt_verbose_kconsumerd;    /* Not static for lttngerr.h */
 int opt_quiet;      /* Not static for lttngerr.h */
 
 const char *progname;
@@ -146,10 +147,18 @@ static void teardown_kernel_session(struct ltt_session *session)
        }
 }
 
+static void stop_threads(void)
+{
+       /* Stopping all threads */
+       DBG("Terminating all threads");
+       close(thread_quit_pipe[0]);
+       close(thread_quit_pipe[1]);
+}
+
 /*
  * Cleanup the daemon
  */
-static void cleanup()
+static void cleanup(void)
 {
        int ret;
        char *cmd;
@@ -163,11 +172,6 @@ static void cleanup()
                27, 1, 31, 27, 0, 27, 1, 33, 27, 0);
        /* </fun> */
 
-       /* Stopping all threads */
-       DBG("Terminating all threads");
-       close(thread_quit_pipe[0]);
-       close(thread_quit_pipe[1]);
-
        DBG("Removing %s directory", LTTNG_RUNDIR);
        ret = asprintf(&cmd, "rm -rf " LTTNG_RUNDIR);
        if (ret < 0) {
@@ -862,6 +866,23 @@ error:
        return ret;
 }
 
+static int join_kconsumerd_thread(void)
+{
+       void *status;
+       int ret;
+
+       if (kconsumerd_pid != 0) {
+               ret = kill(kconsumerd_pid, SIGTERM);
+               if (ret) {
+                       ERR("Error killing kconsumerd");
+                       return ret;
+               }
+               return pthread_join(kconsumerd_thread, &status);
+       } else {
+               return 0;
+       }
+}
+
 /*
  * Fork and exec a kernel consumer daemon (kconsumerd).
  *
@@ -880,7 +901,7 @@ static pid_t spawn_kconsumerd(void)
                /*
                 * Exec kconsumerd.
                 */
-               if (opt_verbose > 1) {
+               if (opt_verbose > 1 || opt_verbose_kconsumerd) {
                        verbosity = "--verbose";
                } else {
                        verbosity = "--quiet";
@@ -2260,6 +2281,7 @@ static void usage(void)
        fprintf(stderr, "  -S, --sig-parent                   Send SIGCHLD 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, "      --verbose-kconsumerd           Verbose mode for kconsumerd. Activate DBG() macro.\n");
 }
 
 /*
@@ -2281,12 +2303,13 @@ static int parse_args(int argc, char **argv)
                { "version", 0, 0, 'V' },
                { "quiet", 0, 0, 'q' },
                { "verbose", 0, 0, 'v' },
+               { "verbose-kconsumerd", 0, 0, 'Z' },
                { NULL, 0, 0, 0 }
        };
 
        while (1) {
                int option_index = 0;
-               c = getopt_long(argc, argv, "dhqvVS" "a:c:g:s:E:C:", long_options, &option_index);
+               c = getopt_long(argc, argv, "dhqvVS" "a:c:g:s:E:C:Z", long_options, &option_index);
                if (c == -1) {
                        break;
                }
@@ -2332,6 +2355,9 @@ static int parse_args(int argc, char **argv)
                        /* Verbose level can increase using multiple -v */
                        opt_verbose += 1;
                        break;
+               case 'Z':
+                       opt_verbose_kconsumerd += 1;
+                       break;
                default:
                        /* Unknown option or other error.
                         * Error is printed by getopt, just return */
@@ -2347,7 +2373,7 @@ static int parse_args(int argc, char **argv)
  *         apps_sock - The communication socket for all UST apps.
  *         client_sock - The communication of the cli tool (lttng).
  */
-static int init_daemon_socket()
+static int init_daemon_socket(void)
 {
        int ret = 0;
        mode_t old_umask;
@@ -2392,18 +2418,21 @@ end:
 }
 
 /*
- * Check if the global socket is available.  If yes, error is returned.
+ * Check if the global socket is available, and if a daemon is answering
+ * at the other side. If yes, error is returned.
  */
-static int check_existing_daemon()
+static int check_existing_daemon(void)
 {
        int ret;
 
-       ret = access(client_unix_sock_path, F_OK);
-       if (ret == 0) {
-               ret = access(apps_unix_sock_path, F_OK);
-       }
-
-       return ret;
+       if (access(client_unix_sock_path, F_OK) < 0 &&
+           access(apps_unix_sock_path, F_OK) < 0)
+               return 0;
+       /* Is there anybody out there ? */
+       if (lttng_session_daemon_alive())
+               return -EEXIST;
+       else
+               return 0;
 }
 
 /*
@@ -2536,26 +2565,27 @@ error:
 
 /*
  * Signal handler for the daemon
+ *
+ * Simply stop all worker threads, leaving main() return gracefully
+ * after joining all threads and calling cleanup().
  */
 static void sighandler(int sig)
 {
        switch (sig) {
-               case SIGPIPE:
-                       DBG("SIGPIPE catched");
-                       return;
-               case SIGINT:
-                       DBG("SIGINT catched");
-                       cleanup();
-                       break;
-               case SIGTERM:
-                       DBG("SIGTERM catched");
-                       cleanup();
-                       break;
-               default:
-                       break;
+       case SIGPIPE:
+               DBG("SIGPIPE catched");
+               return;
+       case SIGINT:
+               DBG("SIGINT catched");
+               stop_threads();
+               break;
+       case SIGTERM:
+               DBG("SIGTERM catched");
+               stop_threads();
+               break;
+       default:
+               break;
        }
-
-       exit(EXIT_SUCCESS);
 }
 
 /*
@@ -2625,14 +2655,14 @@ int main(int argc, char **argv)
        const char *home_path;
 
        /* Create thread quit pipe */
-       if (init_thread_quit_pipe() < 0) {
-               goto exit;
+       if ((ret = init_thread_quit_pipe()) < 0) {
+               goto error;
        }
 
        /* Parse arguments */
        progname = argv[0];
        if ((ret = parse_args(argc, argv) < 0)) {
-               goto exit;
+               goto error;
        }
 
        /* Daemonize */
@@ -2640,7 +2670,7 @@ int main(int argc, char **argv)
                ret = daemon(0, 0);
                if (ret < 0) {
                        perror("daemon");
-                       goto exit;
+                       goto error;
                }
        }
 
@@ -2650,7 +2680,7 @@ int main(int argc, char **argv)
        if (is_root) {
                ret = create_lttng_rundir();
                if (ret < 0) {
-                       goto exit;
+                       goto error;
                }
 
                if (strlen(apps_unix_sock_path) == 0) {
@@ -2667,7 +2697,8 @@ int main(int argc, char **argv)
                if (home_path == NULL) {
                        /* TODO: Add --socket PATH option */
                        ERR("Can't get HOME directory for sockets creation.");
-                       goto exit;
+                       ret = -EPERM;
+                       goto error;
                }
 
                if (strlen(apps_unix_sock_path) == 0) {
@@ -2686,17 +2717,15 @@ int main(int argc, char **argv)
        DBG("Application socket path %s", apps_unix_sock_path);
 
        /*
-        * See if daemon already exist. If any of the two socket needed by the
-        * daemon are present, this test fails. However, if the daemon is killed
-        * with a SIGKILL, those unix socket must be unlinked by hand.
+        * See if daemon already exist.
         */
-       if ((ret = check_existing_daemon()) == 0) {
+       if ((ret = check_existing_daemon()) < 0) {
                ERR("Already running daemon.\n");
                /*
-                * We do not goto error because we must not cleanup() because a daemon
-                * is already running.
+                * We do not goto exit because we must not cleanup()
+                * because a daemon is already running.
                 */
-               goto exit;
+               goto error;
        }
 
        /* After this point, we can safely call cleanup() so goto error is used */
@@ -2710,7 +2739,7 @@ int main(int argc, char **argv)
        if (is_root) {
                ret = set_kconsumerd_sockets();
                if (ret < 0) {
-                       goto error;
+                       goto exit;
                }
 
                /* Setup kernel tracer */
@@ -2720,18 +2749,18 @@ int main(int argc, char **argv)
                set_ulimit();
        }
 
-       if (set_signal_handler() < 0) {
-               goto error;
+       if ((ret = set_signal_handler()) < 0) {
+               goto exit;
        }
 
        /* Setup the needed unix socket */
-       if (init_daemon_socket() < 0) {
-               goto error;
+       if ((ret = init_daemon_socket()) < 0) {
+               goto exit;
        }
 
        /* Set credentials to socket */
-       if (is_root && (set_permissions() < 0)) {
-               goto error;
+       if (is_root && ((ret = set_permissions()) < 0)) {
+               goto exit;
        }
 
        /* Get parent pid if -S, --sig-parent is specified. */
@@ -2740,8 +2769,8 @@ int main(int argc, char **argv)
        }
 
        /* Setup the kernel pipe for waking up the kernel thread */
-       if (create_kernel_poll_pipe() < 0) {
-               goto error;
+       if ((ret = create_kernel_poll_pipe()) < 0) {
+               goto exit;
        }
 
        /*
@@ -2750,41 +2779,61 @@ int main(int argc, char **argv)
         */
        session_list_ptr = get_session_list();
 
-       while (1) {
-               /* Create thread to manage the client socket */
-               ret = pthread_create(&client_thread, NULL, thread_manage_clients, (void *) NULL);
-               if (ret != 0) {
-                       perror("pthread_create");
-                       goto error;
-               }
+       /* Create thread to manage the client socket */
+       ret = pthread_create(&client_thread, NULL, thread_manage_clients, (void *) NULL);
+       if (ret != 0) {
+               perror("pthread_create");
+               goto exit_client;
+       }
 
-               /* Create thread to manage application socket */
-               ret = pthread_create(&apps_thread, NULL, thread_manage_apps, (void *) NULL);
-               if (ret != 0) {
-                       perror("pthread_create");
-                       goto error;
-               }
+       /* Create thread to manage application socket */
+       ret = pthread_create(&apps_thread, NULL, thread_manage_apps, (void *) NULL);
+       if (ret != 0) {
+               perror("pthread_create");
+               goto exit_apps;
+       }
 
-               /* Create kernel thread to manage kernel event */
-               ret = pthread_create(&kernel_thread, NULL, thread_manage_kernel, (void *) NULL);
-               if (ret != 0) {
-                       perror("pthread_create");
-                       goto error;
-               }
+       /* Create kernel thread to manage kernel event */
+       ret = pthread_create(&kernel_thread, NULL, thread_manage_kernel, (void *) NULL);
+       if (ret != 0) {
+               perror("pthread_create");
+               goto exit_kernel;
+       }
 
-               ret = pthread_join(client_thread, &status);
-               if (ret != 0) {
-                       perror("pthread_join");
-                       goto error;
-               }
+       ret = pthread_join(kernel_thread, &status);
+       if (ret != 0) {
+               perror("pthread_join");
+               goto error;     /* join error, exit without cleanup */
        }
 
-       cleanup();
-       exit(EXIT_SUCCESS);
+exit_kernel:
+       ret = pthread_join(apps_thread, &status);
+       if (ret != 0) {
+               perror("pthread_join");
+               goto error;     /* join error, exit without cleanup */
+       }
 
-error:
-       cleanup();
+exit_apps:
+       ret = pthread_join(client_thread, &status);
+       if (ret != 0) {
+               perror("pthread_join");
+               goto error;     /* join error, exit without cleanup */
+       }
 
+       ret = join_kconsumerd_thread();
+       if (ret != 0) {
+               perror("join_kconsumerd");
+               goto error;     /* join error, exit without cleanup */
+       }
+
+exit_client:
 exit:
+       /*
+        * cleanup() is called when no other thread is running.
+        */
+       cleanup();
+       if (!ret)
+               exit(EXIT_SUCCESS);
+error:
        exit(EXIT_FAILURE);
 }
This page took 0.029239 seconds and 4 git commands to generate.