X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=bc3a6bb445735baf9937ab699be70cab02c3a11c;hp=0b116e11820ff70ee483c132b2eef4215840a5d9;hb=4a15001e426da818990dc21f1d423fd04b6cd492;hpb=73664f816b1512231bf44679eea5a3c91ca619ec diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 0b116e118..bc3a6bb44 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -189,6 +189,7 @@ static int kernel_poll_pipe[2] = { -1, -1 }; * for all threads when receiving an event on the pipe. */ static int thread_quit_pipe[2] = { -1, -1 }; +static int ht_cleanup_quit_pipe[2] = { -1, -1 }; /* * This pipe is used to inform the thread managing application communication @@ -384,10 +385,9 @@ void setup_consumerd_path(void) } } -/* - * 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) +static +int __sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size, + int *a_pipe) { int ret; @@ -399,7 +399,7 @@ int sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size) } /* Add quit pipe */ - ret = lttng_poll_add(events, thread_quit_pipe[0], LPOLLIN | LPOLLERR); + ret = lttng_poll_add(events, a_pipe[0], LPOLLIN | LPOLLERR); if (ret < 0) { goto error; } @@ -410,6 +410,33 @@ 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); +} + +/* + * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. + */ +int sessiond_set_ht_cleanup_thread_pollset(struct lttng_poll_event *events, + size_t size) +{ + return __sessiond_set_thread_pollset(events, size, + ht_cleanup_quit_pipe); +} + +static +int __sessiond_check_thread_quit_pipe(int fd, uint32_t events, int a_pipe) +{ + if (fd == a_pipe && (events & LPOLLIN)) { + return 1; + } + return 0; +} + /* * Check if the thread quit pipe was triggered. * @@ -417,11 +444,19 @@ error: */ int sessiond_check_thread_quit_pipe(int fd, uint32_t events) { - if (fd == thread_quit_pipe[0] && (events & LPOLLIN)) { - return 1; - } + return __sessiond_check_thread_quit_pipe(fd, events, + thread_quit_pipe[0]); +} - return 0; +/* + * Check if the ht_cleanup thread quit pipe was triggered. + * + * Return 1 if it was triggered else 0; + */ +int sessiond_check_ht_cleanup_quit(int fd, uint32_t events) +{ + return __sessiond_check_thread_quit_pipe(fd, events, + ht_cleanup_quit_pipe[0]); } /* @@ -429,18 +464,18 @@ int sessiond_check_thread_quit_pipe(int fd, uint32_t events) * * Return -1 on error or 0 if all pipes are created. */ -static int init_thread_quit_pipe(void) +static int __init_thread_quit_pipe(int *a_pipe) { int ret, i; - ret = pipe(thread_quit_pipe); + ret = pipe(a_pipe); if (ret < 0) { PERROR("thread quit pipe"); goto error; } for (i = 0; i < 2; i++) { - ret = fcntl(thread_quit_pipe[i], F_SETFD, FD_CLOEXEC); + ret = fcntl(a_pipe[i], F_SETFD, FD_CLOEXEC); if (ret < 0) { PERROR("fcntl"); goto error; @@ -451,6 +486,16 @@ error: return ret; } +static int init_thread_quit_pipe(void) +{ + return __init_thread_quit_pipe(thread_quit_pipe); +} + +static int init_ht_cleanup_quit_pipe(void) +{ + return __init_thread_quit_pipe(ht_cleanup_quit_pipe); +} + /* * Stop all threads by closing the thread quit pipe. */ @@ -537,15 +582,15 @@ static int generate_lock_file_path(char *path, size_t len) } /* - * Cleanup the daemon + * Cleanup the session daemon's data structures. */ -static void cleanup(void) +static void sessiond_cleanup(void) { int ret; struct ltt_session *sess, *stmp; char path[PATH_MAX]; - DBG("Cleaning up"); + DBG("Cleanup sessiond"); /* * Close the thread quit pipe. It has already done its job, @@ -649,34 +694,6 @@ static void cleanup(void) close_consumer_sockets(); - /* - * If the override option is set, the pointer points to a *non* const thus - * freeing it even though the variable type is set to const. - */ - if (tracing_group_name_override) { - free((void *) tracing_group_name); - } - if (consumerd32_bin_override) { - free((void *) consumerd32_bin); - } - if (consumerd64_bin_override) { - free((void *) consumerd64_bin); - } - if (consumerd32_libdir_override) { - free((void *) consumerd32_libdir); - } - if (consumerd64_libdir_override) { - free((void *) consumerd64_libdir); - } - - if (opt_pidfile) { - free(opt_pidfile); - } - - if (opt_load_session_path) { - free(opt_load_session_path); - } - if (load_info) { load_session_destroy_data(load_info); free(load_info); @@ -689,7 +706,8 @@ static void cleanup(void) if (lockfile_fd >= 0) { char lockfile_path[PATH_MAX]; - ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path)); + ret = generate_lock_file_path(lockfile_path, + sizeof(lockfile_path)); if (ret > 0) { ret = remove(lockfile_path); if (ret < 0) { @@ -709,6 +727,39 @@ static void cleanup(void) */ free(rundir); +} + +/* + * Cleanup the daemon's option data structures. + */ +static void sessiond_cleanup_options(void) +{ + DBG("Cleaning up options"); + + /* + * If the override option is set, the pointer points to a *non* const + * thus freeing it even though the variable type is set to const. + */ + if (tracing_group_name_override) { + free((void *) tracing_group_name); + } + if (consumerd32_bin_override) { + free((void *) consumerd32_bin); + } + if (consumerd64_bin_override) { + free((void *) consumerd64_bin); + } + if (consumerd32_libdir_override) { + free((void *) consumerd32_libdir); + } + if (consumerd64_libdir_override) { + free((void *) consumerd64_libdir); + } + + free(opt_pidfile); + free(opt_load_session_path); + free(kmod_probes_list); + free(kmod_extra_probes_list); /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" @@ -873,42 +924,47 @@ static int update_kernel_stream(struct consumer_data *consumer_data, int fd) } ksess = session->kernel_session; - cds_list_for_each_entry(channel, &ksess->channel_list.head, list) { - if (channel->fd == fd) { - DBG("Channel found, updating kernel streams"); - ret = kernel_open_channel_stream(channel); - if (ret < 0) { - goto error; - } - /* Update the stream global counter */ - ksess->stream_count_global += ret; + cds_list_for_each_entry(channel, + &ksess->channel_list.head, list) { + struct lttng_ht_iter iter; + struct consumer_socket *socket; - /* - * Have we already sent fds to the consumer? If yes, it means - * that tracing is started so it is safe to send our updated - * stream fds. - */ - if (ksess->consumer_fds_sent == 1 && ksess->consumer != NULL) { - struct lttng_ht_iter iter; - struct consumer_socket *socket; - - rcu_read_lock(); - 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, - channel, ksess, - session->output_traces ? 1 : 0); - pthread_mutex_unlock(socket->lock); - if (ret < 0) { - rcu_read_unlock(); - goto error; - } - } + if (channel->fd != fd) { + continue; + } + DBG("Channel found, updating kernel streams"); + ret = kernel_open_channel_stream(channel); + if (ret < 0) { + goto error; + } + /* Update the stream global counter */ + ksess->stream_count_global += ret; + + /* + * Have we already sent fds to the consumer? If yes, it + * means that tracing is started so it is safe to send + * our updated stream fds. + */ + if (ksess->consumer_fds_sent != 1 + || ksess->consumer == NULL) { + ret = -1; + goto error; + } + + rcu_read_lock(); + 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, + channel, ksess, + session->output_traces ? 1 : 0); + pthread_mutex_unlock(socket->lock); + if (ret < 0) { rcu_read_unlock(); + goto error; } - goto error; } + rcu_read_unlock(); } session_unlock(session); } @@ -2148,7 +2204,7 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) /* Setup pthread condition */ ret = pthread_condattr_init(&consumer_data->condattr); - if (ret != 0) { + if (ret) { errno = ret; PERROR("pthread_condattr_init consumer data"); goto error; @@ -2160,14 +2216,14 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) * for a more details and how we noticed it. */ ret = pthread_condattr_setclock(&consumer_data->condattr, CLOCK_MONOTONIC); - if (ret != 0) { + if (ret) { errno = ret; PERROR("pthread_condattr_setclock consumer data"); goto error; } ret = pthread_cond_init(&consumer_data->cond, &consumer_data->condattr); - if (ret != 0) { + if (ret) { errno = ret; PERROR("pthread_cond_init consumer data"); goto error; @@ -2175,7 +2231,8 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) ret = pthread_create(&consumer_data->thread, NULL, thread_manage_consumer, consumer_data); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create consumer"); ret = -1; goto error; @@ -2271,7 +2328,7 @@ static int join_consumer_thread(struct consumer_data *consumer_data) int ret; ret = kill(consumer_data->pid, SIGTERM); if (ret) { - ERR("Error killing consumer daemon"); + PERROR("Error killing consumer daemon"); return ret; } return pthread_join(consumer_data->thread, &status); @@ -4193,6 +4250,28 @@ error_create_poll: DBG("Client thread dying"); rcu_unregister_thread(); + + /* + * Since we are creating the consumer threads, we own them, so we need + * to join them before our thread exits. + */ + ret = join_consumer_thread(&kconsumer_data); + if (ret) { + errno = ret; + PERROR("join_consumer"); + } + + ret = join_consumer_thread(&ustconsumer32_data); + if (ret) { + errno = ret; + PERROR("join_consumer ust32"); + } + + ret = join_consumer_thread(&ustconsumer64_data); + if (ret) { + errno = ret; + PERROR("join_consumer ust64"); + } return NULL; } @@ -4291,7 +4370,7 @@ static int set_option(int opt, const char *arg, const char *optname) break; case 'h': usage(); - exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); case 'V': fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); @@ -4926,7 +5005,7 @@ static void set_ulimit(void) /* * Write pidfile using the rundir and opt_pidfile. */ -static void write_pidfile(void) +static int write_pidfile(void) { int ret; char pidfile_path[PATH_MAX]; @@ -4946,13 +5025,11 @@ static void write_pidfile(void) } /* - * Create pid file in rundir. Return value is of no importance. The - * execution will continue even though we are not able to write the file. + * Create pid file in rundir. */ - (void) utils_create_pid_file(getpid(), pidfile_path); - + ret = utils_create_pid_file(getpid(), pidfile_path); error: - return; + return ret; } /* @@ -4976,7 +5053,7 @@ error: /* * Write agent TCP port using the rundir. */ -static void write_agent_port(void) +static int write_agent_port(void) { int ret; char path[PATH_MAX]; @@ -4991,43 +5068,12 @@ static void write_agent_port(void) } /* - * Create TCP agent port file in rundir. Return value is of no importance. - * The execution will continue even though we are not able to write the - * file. + * Create TCP agent port file in rundir. */ - (void) utils_create_pid_file(agent_tcp_port, path); + ret = utils_create_pid_file(agent_tcp_port, path); error: - return; -} - -/* - * Start the load session thread and dettach from it so the main thread can - * continue. This does not return a value since whatever the outcome, the main - * thread will continue. - */ -static void start_load_session_thread(void) -{ - int ret; - - /* Create session loading thread. */ - ret = pthread_create(&load_session_thread, NULL, thread_load_session, - load_info); - if (ret != 0) { - PERROR("pthread_create load_session_thread"); - goto error_create; - } - - ret = pthread_detach(load_session_thread); - if (ret != 0) { - PERROR("pthread_detach load_session_thread"); - } - - /* Everything went well so don't cleanup anything. */ - -error_create: - /* The cleanup() function will destroy the load_info data. */ - return; + return ret; } /* @@ -5035,7 +5081,7 @@ error_create: */ int main(int argc, char **argv) { - int ret = 0; + int ret = 0, retval = 0; void *status; const char *home_path, *env_app_timeout; @@ -5043,8 +5089,9 @@ int main(int argc, char **argv) rcu_register_thread(); - if ((ret = set_signal_handler()) < 0) { - goto error; + if (set_signal_handler()) { + retval = -1; + goto exit_set_signal_handler; } setup_consumerd_path(); @@ -5056,10 +5103,18 @@ int main(int argc, char **argv) WARN("Fallback page size to %ld", page_size); } - /* Parse arguments and load the daemon configuration file */ + /* + * Parse arguments and load the daemon configuration file. + * + * We have an exit_options exit path to free memory reserved by + * set_options. This is needed because the rest of sessiond_cleanup() + * depends on ht_cleanup_thread, which depends on lttng_daemonize, which + * depends on set_options. + */ progname = argv[0]; - if ((ret = set_options(argc, argv)) < 0) { - goto error; + if (set_options(argc, argv)) { + retval = -1; + goto exit_options; } /* Daemonize */ @@ -5069,22 +5124,61 @@ int main(int argc, char **argv) ret = lttng_daemonize(&child_ppid, &recv_child_signal, !opt_background); if (ret < 0) { - goto error; + retval = -1; + goto exit_options; } /* * 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. + * 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); } } + /* + * Starting from here, we can create threads. This needs to be after + * lttng_daemonize due to RCU. + */ + + /* + * Initialize the health check subsystem. This call should set the + * appropriate time values. + */ + health_sessiond = health_app_create(NR_HEALTH_SESSIOND_TYPES); + if (!health_sessiond) { + PERROR("health_app_create error"); + retval = -1; + goto exit_health_sessiond_cleanup; + } + + if (init_ht_cleanup_quit_pipe()) { + retval = -1; + goto exit_ht_cleanup_quit_pipe; + } + + /* Setup the thread ht_cleanup communication pipe. */ + if (utils_create_pipe_cloexec(ht_cleanup_pipe)) { + retval = -1; + goto exit_ht_cleanup_pipe; + } + + /* Create thread to clean up RCU hash tables */ + ret = pthread_create(&ht_cleanup_thread, NULL, + thread_ht_cleanup, (void *) NULL); + if (ret) { + errno = ret; + PERROR("pthread_create ht_cleanup"); + retval = -1; + goto exit_ht_cleanup; + } + /* Create thread quit pipe */ - if ((ret = init_thread_quit_pipe()) < 0) { - goto error; + if (init_thread_quit_pipe()) { + retval = -1; + goto exit_init_data; } /* Check if daemon is UID = 0 */ @@ -5093,42 +5187,67 @@ int main(int argc, char **argv) if (is_root) { rundir = strdup(DEFAULT_LTTNG_RUNDIR); if (!rundir) { - ret = -ENOMEM; - goto error; + retval = -1; + goto exit_init_data; } /* Create global run dir with root access */ - ret = create_lttng_rundir(rundir); - if (ret < 0) { - goto error; + if (create_lttng_rundir(rundir)) { + retval = -1; + goto exit_init_data; } if (strlen(apps_unix_sock_path) == 0) { - snprintf(apps_unix_sock_path, PATH_MAX, + ret = snprintf(apps_unix_sock_path, PATH_MAX, DEFAULT_GLOBAL_APPS_UNIX_SOCK); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } if (strlen(client_unix_sock_path) == 0) { - snprintf(client_unix_sock_path, PATH_MAX, + ret = snprintf(client_unix_sock_path, PATH_MAX, DEFAULT_GLOBAL_CLIENT_UNIX_SOCK); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } /* Set global SHM for ust */ if (strlen(wait_shm_path) == 0) { - snprintf(wait_shm_path, PATH_MAX, + ret = snprintf(wait_shm_path, PATH_MAX, DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } if (strlen(health_unix_sock_path) == 0) { - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), + ret = snprintf(health_unix_sock_path, + sizeof(health_unix_sock_path), DEFAULT_GLOBAL_HEALTH_UNIX_SOCK); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } /* Setup kernel consumerd path */ - snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, + ret = snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, DEFAULT_KCONSUMERD_ERR_SOCK_PATH, rundir); - snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, + if (ret < 0) { + retval = -1; + goto exit_init_data; + } + ret = snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, DEFAULT_KCONSUMERD_CMD_SOCK_PATH, rundir); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } DBG2("Kernel consumer err path: %s", kconsumer_data.err_unix_sock_path); @@ -5139,8 +5258,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."); - ret = -EPERM; - goto error; + retval = -1; + goto exit_init_data; } /* @@ -5149,42 +5268,64 @@ int main(int argc, char **argv) */ ret = asprintf(&rundir, DEFAULT_LTTNG_HOME_RUNDIR, home_path); if (ret < 0) { - ret = -ENOMEM; - goto error; + retval = -1; + goto exit_init_data; } - ret = create_lttng_rundir(rundir); - if (ret < 0) { - goto error; + if (create_lttng_rundir(rundir)) { + retval = -1; + goto exit_init_data; } if (strlen(apps_unix_sock_path) == 0) { - snprintf(apps_unix_sock_path, PATH_MAX, - DEFAULT_HOME_APPS_UNIX_SOCK, home_path); + ret = snprintf(apps_unix_sock_path, PATH_MAX, + DEFAULT_HOME_APPS_UNIX_SOCK, + home_path); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } /* Set the cli tool unix socket path */ if (strlen(client_unix_sock_path) == 0) { - snprintf(client_unix_sock_path, PATH_MAX, - DEFAULT_HOME_CLIENT_UNIX_SOCK, home_path); + ret = snprintf(client_unix_sock_path, PATH_MAX, + DEFAULT_HOME_CLIENT_UNIX_SOCK, + home_path); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } /* Set global SHM for ust */ if (strlen(wait_shm_path) == 0) { - snprintf(wait_shm_path, PATH_MAX, - DEFAULT_HOME_APPS_WAIT_SHM_PATH, getuid()); + ret = snprintf(wait_shm_path, PATH_MAX, + DEFAULT_HOME_APPS_WAIT_SHM_PATH, + getuid()); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } /* Set health check Unix path */ if (strlen(health_unix_sock_path) == 0) { - snprintf(health_unix_sock_path, sizeof(health_unix_sock_path), - DEFAULT_HOME_HEALTH_UNIX_SOCK, home_path); + ret = snprintf(health_unix_sock_path, + sizeof(health_unix_sock_path), + DEFAULT_HOME_HEALTH_UNIX_SOCK, + home_path); + if (ret < 0) { + retval = -1; + goto exit_init_data; + } } } lockfile_fd = create_lockfile(); if (lockfile_fd < 0) { - goto error; + retval = -1; + goto exit_init_data; } /* Set consumer initial state */ @@ -5197,10 +5338,20 @@ int main(int argc, char **argv) DBG("LTTng run directory path: %s", rundir); /* 32 bits consumerd path setup */ - snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, + ret = snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH, rundir); - snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, + if (ret < 0) { + PERROR("snprintf 32-bit consumer error socket path"); + retval = -1; + goto exit_init_data; + } + ret = snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH, rundir); + if (ret < 0) { + PERROR("snprintf 32-bit consumer command socket path"); + retval = -1; + goto exit_init_data; + } DBG2("UST consumer 32 bits err path: %s", ustconsumer32_data.err_unix_sock_path); @@ -5208,10 +5359,20 @@ int main(int argc, char **argv) ustconsumer32_data.cmd_unix_sock_path); /* 64 bits consumerd path setup */ - snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, + ret = snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH, rundir); - snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, + if (ret < 0) { + PERROR("snprintf 64-bit consumer error socket path"); + retval = -1; + goto exit_init_data; + } + ret = snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH, rundir); + if (ret < 0) { + PERROR("snprintf 64-bit consumer command socket path"); + retval = -1; + goto exit_init_data; + } DBG2("UST consumer 64 bits err path: %s", ustconsumer64_data.err_unix_sock_path); @@ -5221,29 +5382,32 @@ int main(int argc, char **argv) /* * See if daemon already exist. */ - if ((ret = check_existing_daemon()) < 0) { + 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. */ - goto error; + retval = -1; + goto exit_init_data; } /* * Init UST app hash table. Alloc hash table before this point since * cleanup() can get called after that point. */ - ust_app_ht_alloc(); + if (ust_app_ht_alloc()) { + retval = -1; + goto exit_init_data; + } /* Initialize agent domain subsystem. */ - if ((ret = agent_setup()) < 0) { + if (agent_setup()) { /* ENOMEM at this point. */ - goto error; + retval = -1; + goto exit_init_data; } - /* After this point, we can safely call cleanup() with "goto exit" */ - /* * These actions must be executed as root. We do that *after* setting up * the sockets path because we MUST make the check for another daemon using @@ -5251,9 +5415,9 @@ int main(int argc, char **argv) * kernel tracer. */ if (is_root) { - ret = set_consumer_sockets(&kconsumer_data, rundir); - if (ret < 0) { - goto exit; + if (set_consumer_sockets(&kconsumer_data, rundir)) { + retval = -1; + goto exit_init_data; } /* Setup kernel tracer */ @@ -5262,8 +5426,9 @@ int main(int argc, char **argv) if (kernel_tracer_fd >= 0) { ret = syscall_init_table(); if (ret < 0) { - ERR("Unable to populate syscall table. Syscall tracing" - " won't work for this session daemon."); + ERR("Unable to populate syscall table. " + "Syscall tracing won't work " + "for this session daemon."); } } } @@ -5274,24 +5439,26 @@ int main(int argc, char **argv) /* init lttng_fd tracking must be done after set_ulimit. */ lttng_fd_init(); - ret = set_consumer_sockets(&ustconsumer64_data, rundir); - if (ret < 0) { - goto exit; + if (set_consumer_sockets(&ustconsumer64_data, rundir)) { + retval = -1; + goto exit_init_data; } - ret = set_consumer_sockets(&ustconsumer32_data, rundir); - if (ret < 0) { - goto exit; + if (set_consumer_sockets(&ustconsumer32_data, rundir)) { + retval = -1; + goto exit_init_data; } /* Setup the needed unix socket */ - if ((ret = init_daemon_socket()) < 0) { - goto exit; + if (init_daemon_socket()) { + retval = -1; + goto exit_init_data; } /* Set credentials to socket */ - if (is_root && ((ret = set_permissions(rundir)) < 0)) { - goto exit; + if (is_root && set_permissions(rundir)) { + retval = -1; + goto exit_init_data; } /* Get parent pid if -S, --sig-parent is specified. */ @@ -5301,24 +5468,22 @@ int main(int argc, char **argv) /* Setup the kernel pipe for waking up the kernel thread */ if (is_root && !opt_no_kernel) { - if ((ret = utils_create_pipe_cloexec(kernel_poll_pipe)) < 0) { - goto exit; + if (utils_create_pipe_cloexec(kernel_poll_pipe)) { + retval = -1; + goto exit_init_data; } } - /* Setup the thread ht_cleanup communication pipe. */ - if (utils_create_pipe_cloexec(ht_cleanup_pipe) < 0) { - goto exit; - } - /* Setup the thread apps communication pipe. */ - if ((ret = utils_create_pipe_cloexec(apps_cmd_pipe)) < 0) { - goto exit; + if (utils_create_pipe_cloexec(apps_cmd_pipe)) { + retval = -1; + goto exit_init_data; } /* Setup the thread apps notify communication pipe. */ - if (utils_create_pipe_cloexec(apps_cmd_notify_pipe) < 0) { - goto exit; + if (utils_create_pipe_cloexec(apps_cmd_notify_pipe)) { + retval = -1; + goto exit_init_data; } /* Initialize global buffer per UID and PID registry. */ @@ -5329,8 +5494,8 @@ int main(int argc, char **argv) cds_wfcq_init(&ust_cmd_queue.head, &ust_cmd_queue.tail); /* - * Get session list pointer. This pointer MUST NOT be free(). This list is - * statically declared in session.c + * 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(); @@ -5347,90 +5512,97 @@ int main(int argc, char **argv) app_socket_timeout = DEFAULT_APP_SOCKET_RW_TIMEOUT; } - write_pidfile(); - write_agent_port(); + ret = write_pidfile(); + if (ret) { + ERR("Error in write_pidfile"); + 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(); - /* This is to get the TCP timeout value. */ + /* Initialize TCP timeout values */ lttcomm_inet_init(); if (load_session_init_data(&load_info) < 0) { - goto exit; + retval = -1; + goto exit_init_data; } load_info->path = opt_load_session_path; - /* - * Initialize the health check subsystem. This call should set the - * appropriate time values. - */ - health_sessiond = health_app_create(NR_HEALTH_SESSIOND_TYPES); - if (!health_sessiond) { - PERROR("health_app_create error"); - goto exit_health_sessiond_cleanup; - } - - /* Create thread to clean up RCU hash tables */ - ret = pthread_create(&ht_cleanup_thread, NULL, - thread_ht_cleanup, (void *) NULL); - if (ret != 0) { - PERROR("pthread_create ht_cleanup"); - goto exit_ht_cleanup; - } - /* Create health-check thread */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create health"); + retval = -1; goto exit_health; } /* Create thread to manage the client socket */ ret = pthread_create(&client_thread, NULL, thread_manage_clients, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create clients"); + retval = -1; goto exit_client; } /* Create thread to dispatch registration */ ret = pthread_create(&dispatch_thread, NULL, thread_dispatch_ust_registration, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create dispatch"); + retval = -1; goto exit_dispatch; } /* Create thread to manage application registration. */ ret = pthread_create(®_apps_thread, NULL, thread_registration_apps, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create registration"); + retval = -1; goto exit_reg_apps; } /* Create thread to manage application socket */ ret = pthread_create(&apps_thread, NULL, thread_manage_apps, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create apps"); + retval = -1; goto exit_apps; } /* Create thread to manage application notify socket */ ret = pthread_create(&apps_notify_thread, NULL, ust_thread_manage_notify, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create notify"); + retval = -1; goto exit_apps_notify; } /* Create agent registration thread. */ ret = pthread_create(&agent_reg_thread, NULL, agent_thread_manage_registration, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create agent"); + retval = -1; goto exit_agent_reg; } @@ -5439,111 +5611,146 @@ int main(int argc, char **argv) /* Create kernel thread to manage kernel event */ ret = pthread_create(&kernel_thread, NULL, thread_manage_kernel, (void *) NULL); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_create kernel"); + retval = -1; goto exit_kernel; } } - /* Load possible session(s). */ - start_load_session_thread(); + /* Create session loading thread. */ + ret = pthread_create(&load_session_thread, NULL, thread_load_session, + load_info); + if (ret) { + errno = ret; + PERROR("pthread_create load_session_thread"); + retval = -1; + goto exit_load_session; + } + + /* + * This is where we start awaiting program completion (e.g. through + * signal that asks threads to teardown). + */ + + ret = pthread_join(load_session_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join load_session_thread"); + retval = -1; + } +exit_load_session: if (is_root && !opt_no_kernel) { ret = pthread_join(kernel_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join"); - goto error; /* join error, exit without cleanup */ + retval = -1; } } - exit_kernel: + ret = pthread_join(agent_reg_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join agent"); - goto error; /* join error, exit without cleanup */ + retval = -1; } - exit_agent_reg: + ret = pthread_join(apps_notify_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join apps notify"); - goto error; /* join error, exit without cleanup */ + retval = -1; } - exit_apps_notify: + ret = pthread_join(apps_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join apps"); - goto error; /* join error, exit without cleanup */ + retval = -1; } - - exit_apps: + ret = pthread_join(reg_apps_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join"); - goto error; /* join error, exit without cleanup */ + retval = -1; } - exit_reg_apps: + ret = pthread_join(dispatch_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join"); - goto error; /* join error, exit without cleanup */ + retval = -1; } - exit_dispatch: + ret = pthread_join(client_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join"); - goto error; /* join error, exit without cleanup */ - } - - ret = join_consumer_thread(&kconsumer_data); - if (ret != 0) { - PERROR("join_consumer"); - goto error; /* join error, exit without cleanup */ + retval = -1; } +exit_client: - ret = join_consumer_thread(&ustconsumer32_data); - if (ret != 0) { - PERROR("join_consumer ust32"); - goto error; /* join error, exit without cleanup */ + ret = pthread_join(health_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join health thread"); + retval = -1; } +exit_health: - ret = join_consumer_thread(&ustconsumer64_data); - if (ret != 0) { - PERROR("join_consumer ust64"); - goto error; /* join error, exit without cleanup */ - } +exit_init_data: + /* + * sessiond_cleanup() is called when no other thread is running, except + * the ht_cleanup thread, which is needed to destroy the hash tables. + */ + rcu_thread_online(); + sessiond_cleanup(); + rcu_thread_offline(); + rcu_unregister_thread(); -exit_client: - ret = pthread_join(health_thread, &status); - if (ret != 0) { - PERROR("pthread_join health thread"); - goto error; /* join error, exit without cleanup */ + ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]); + if (ret < 0) { + ERR("write error on ht_cleanup quit pipe"); + retval = -1; } -exit_health: ret = pthread_join(ht_cleanup_thread, &status); - if (ret != 0) { + if (ret) { + errno = ret; PERROR("pthread_join ht cleanup thread"); - goto error; /* join error, exit without cleanup */ + retval = -1; } exit_ht_cleanup: - health_app_destroy(health_sessiond); -exit_health_sessiond_cleanup: -exit: + + utils_close_pipe(ht_cleanup_pipe); +exit_ht_cleanup_pipe: + /* - * cleanup() is called when no other thread is running. + * Close the ht_cleanup quit pipe. */ - rcu_thread_online(); - cleanup(); - rcu_thread_offline(); - rcu_unregister_thread(); - if (!ret) { + utils_close_pipe(ht_cleanup_quit_pipe); +exit_ht_cleanup_quit_pipe: + + health_app_destroy(health_sessiond); +exit_health_sessiond_cleanup: + +exit_options: + sessiond_cleanup_options(); + +exit_set_signal_handler: + if (!retval) { exit(EXIT_SUCCESS); + } else { + exit(EXIT_FAILURE); } -error: - exit(EXIT_FAILURE); }