--- /dev/null
+/*
+ * Copyright (C) 2014 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <common/error.h>
+#include <common/config/config.h>
+
+#include "load-session-thread.h"
+#include "lttng-sessiond.h"
+
+/*
+ * Destroy the thread data previously created with the init function.
+ */
+void load_session_destroy_data(struct load_session_thread_data *data)
+{
+ if (!data) {
+ return;
+ }
+
+ if (data->sem_initialized) {
+ int ret;
+
+ ret = sem_destroy(&data->message_thread_ready);
+ if (ret) {
+ PERROR("sem_destroy message_thread_ready");
+ }
+ }
+}
+
+/*
+ * Initialize the thread data. This MUST be called before the thread load
+ * session is created.
+ *
+ * Return 0 on success else a negative value. Note that the destroy function
+ * can be called with no or partially initialized data.
+ */
+int load_session_init_data(struct load_session_thread_data **data)
+{
+ int ret;
+ struct load_session_thread_data *_data;
+
+ assert(data);
+
+ /*
+ * Allocate memory here since this function is called from the main thread
+ * can die *before* the end of the load session thread.
+ */
+ _data = zmalloc(sizeof(*_data));
+ if (!_data) {
+ PERROR("zmalloc load session info");
+ goto error;
+ }
+ ret = sem_init(&_data->message_thread_ready, 0, 0);
+ if (ret) {
+ PERROR("sem_init message_thread_ready");
+ goto error;
+ }
+ _data->sem_initialized = 1;
+
+ *data = _data;
+ return 0;
+
+error:
+ return -1;
+}
+
+/*
+ * This thread loads session configurations once the session daemon is
+ * ready to process client messages.
+ */
+void *thread_load_session(void *data)
+{
+ int ret;
+ struct load_session_thread_data *info = data;
+
+ DBG("[load-session-thread] Load session");
+
+ ret = sem_wait(&info->message_thread_ready);
+ if (ret) {
+ PERROR("sem_wait message_thread_ready");
+ goto end;
+ }
+
+ ret = config_load_session(info->path, NULL, 0);
+ if (ret) {
+ ERR("Session load failed: %s", error_get_str(ret));
+ }
+
+end:
+ sessiond_notify_ready();
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef LOAD_SESSION_THREAD_H
+#define LOAD_SESSION_THREAD_H
+
+#include <semaphore.h>
+
+/* Data passed to the thread. */
+struct load_session_thread_data {
+ /* Flag if the sem_init() has been done successfully on the sem. */
+ unsigned int sem_initialized:1;
+
+ /*
+ * The load session thread waits on that semaphore which the client thread
+ * will do a sem_post() to unblock it.
+ */
+ sem_t message_thread_ready;
+
+ /* Path where the sessions are located. */
+ const char *path;
+};
+
+void *thread_load_session(void *data);
+
+int load_session_init_data(struct load_session_thread_data **data);
+void load_session_destroy_data(struct load_session_thread_data *data);
+
+#endif /* LOAD_SESSION_THREAD_H */
#include "ust-thread.h"
#include "jul-thread.h"
#include "save.h"
+#include "load-session-thread.h"
#define CONSUMERD_FILE "lttng-consumerd"
static int opt_verbose_consumer;
static int opt_daemon, opt_background;
static int opt_no_kernel;
+static char *opt_load_session_path;
static pid_t ppid; /* Parent PID for --sig-parent option */
static pid_t child_ppid; /* Internal parent PID use with daemonize. */
static char *rundir;
{ "pidfile", 1, 0, 'p' },
{ "jul-tcp-port", 1, 0, 'J' },
{ "config", 1, 0, 'f' },
+ { "load", 1, 0, 'l' },
{ NULL, 0, 0, 0 }
};
static pthread_t health_thread;
static pthread_t ht_cleanup_thread;
static pthread_t jul_reg_thread;
+static pthread_t load_session_thread;
/*
* UST registration command queue. This queue is tied with a futex and uses a N
const char * const config_section_name = "sessiond";
+/* Load session thread information to operate. */
+struct load_session_thread_data *load_info;
+
/*
* Whether sessiond is ready for commands/health check requests.
* NR_LTTNG_SESSIOND_READY must match the number of calls to
- * lttng_sessiond_notify_ready().
+ * sessiond_notify_ready().
*/
-#define NR_LTTNG_SESSIOND_READY 2
+#define NR_LTTNG_SESSIOND_READY 3
int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY;
/* Notify parents that we are ready for cmd and health check */
-static
-void lttng_sessiond_notify_ready(void)
+LTTNG_HIDDEN
+void sessiond_notify_ready(void)
{
if (uatomic_sub_return(<tng_sessiond_ready, 1) == 0) {
/*
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);
+ }
+
/* <fun> */
DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm"
"Matthew, BEET driven development works!%c[%dm",
goto error;
}
- lttng_sessiond_notify_ready();
+ sessiond_notify_ready();
while (1) {
DBG("Health check ready");
goto error;
}
- lttng_sessiond_notify_ready();
+ sessiond_notify_ready();
+ ret = sem_post(&load_info->message_thread_ready);
+ if (ret) {
+ PERROR("sem_post message_thread_ready");
+ goto error;
+ }
/* This testpoint is after we signal readiness to the parent. */
if (testpoint(sessiond_thread_manage_clients)) {
fprintf(stderr, " --no-kernel Disable kernel tracer\n");
fprintf(stderr, " --jul-tcp-port JUL application registration TCP port\n");
fprintf(stderr, " -f --config Load daemon configuration file\n");
+ fprintf(stderr, " -l --load PATH Load session configuration\n");
}
/*
DBG3("JUL TCP port set to non default: %u", jul_tcp_port);
break;
}
+ case 'l':
+ opt_load_session_path = strdup(arg);
+ if (!opt_load_session_path) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
+ break;
default:
/* Unknown option or other error.
* Error is printed by getopt, just return */
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;
+}
+
/*
* main
*/
/* This is to get the TCP timeout value. */
lttcomm_inet_init();
+ if (load_session_init_data(&load_info) < 0) {
+ goto exit;
+ }
+ load_info->path = opt_load_session_path;
+
/*
* Initialize the health check subsystem. This call should set the
* appropriate time values.
PERROR("pthread_create kernel");
goto exit_kernel;
}
+ }
+ /* Load possible session(s). */
+ start_load_session_thread();
+
+ if (is_root && !opt_no_kernel) {
ret = pthread_join(kernel_thread, &status);
if (ret != 0) {
PERROR("pthread_join");