* 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
}
}
-/*
- * 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;
}
/* 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;
}
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.
*
*/
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]);
}
/*
*
* 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;
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.
*/
}
/*
- * 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,
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);
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) {
*/
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);
/* <fun> */
DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm"
}
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);
}
/* 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;
* 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;
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;
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);
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;
}
break;
case 'h':
usage();
- exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
case 'V':
fprintf(stdout, "%s\n", VERSION);
exit(EXIT_SUCCESS);
/*
* 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];
}
/*
- * 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;
}
/*
/*
* 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];
}
/*
- * 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;
}
/*
*/
int main(int argc, char **argv)
{
- int ret = 0;
+ int ret = 0, retval = 0;
void *status;
const char *home_path, *env_app_timeout;
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();
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 */
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 */
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);
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;
}
/*
*/
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 */
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);
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);
/*
* 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
* 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 */
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.");
}
}
}
/* 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. */
/* 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. */
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();
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;
}
/* 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);
}