From ef367a93d16bb6f1a32e50e3538a56d4f18fe715 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Thu, 8 May 2014 12:02:52 -0400 Subject: [PATCH] Add a -l/--load option to the session-daemon MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This option makes it possible to set a PATH from which session configurations are loaded by the session daemon on startup. Usage: lttng-sessiond -l PATH The session configuration file found at PATH, or all those present in it if it is a directory, will be loaded. All sessions found under the user's session configuration directory and under the system session configuration directory are now loaded by default. Signed-off-by: Jérémie Galarneau Signed-off-by: David Goulet --- src/bin/lttng-sessiond/Makefile.am | 3 +- src/bin/lttng-sessiond/load-session-thread.c | 106 +++++++++++++++++++ src/bin/lttng-sessiond/load-session-thread.h | 43 ++++++++ src/bin/lttng-sessiond/lttng-sessiond.h | 2 + src/bin/lttng-sessiond/main.c | 80 ++++++++++++-- 5 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 src/bin/lttng-sessiond/load-session-thread.c create mode 100644 src/bin/lttng-sessiond/load-session-thread.h diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 71df92678..5bd62e558 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -28,7 +28,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \ testpoint.h ht-cleanup.c \ snapshot.c snapshot.h \ jul.c jul.h \ - save.h save.c + save.h save.c \ + load-session-thread.h load-session-thread.c if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \ diff --git a/src/bin/lttng-sessiond/load-session-thread.c b/src/bin/lttng-sessiond/load-session-thread.c new file mode 100644 index 000000000..845948e7c --- /dev/null +++ b/src/bin/lttng-sessiond/load-session-thread.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014 - Jérémie Galarneau + * + * 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 +#include + +#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; +} diff --git a/src/bin/lttng-sessiond/load-session-thread.h b/src/bin/lttng-sessiond/load-session-thread.h new file mode 100644 index 000000000..b7cd76340 --- /dev/null +++ b/src/bin/lttng-sessiond/load-session-thread.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 - Jérémie Galarneau + * + * 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 + +/* 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 */ diff --git a/src/bin/lttng-sessiond/lttng-sessiond.h b/src/bin/lttng-sessiond/lttng-sessiond.h index 12126273c..6ee1fe951 100644 --- a/src/bin/lttng-sessiond/lttng-sessiond.h +++ b/src/bin/lttng-sessiond/lttng-sessiond.h @@ -121,4 +121,6 @@ int sessiond_check_thread_quit_pipe(int fd, uint32_t events); void *thread_ht_cleanup(void *data); +void sessiond_notify_ready(void); + #endif /* _LTT_SESSIOND_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 052e32e0c..3a8a1b27c 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -69,6 +69,7 @@ #include "ust-thread.h" #include "jul-thread.h" #include "save.h" +#include "load-session-thread.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -80,6 +81,7 @@ static int opt_sig_parent; 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; @@ -152,6 +154,7 @@ static const struct option long_options[] = { { "pidfile", 1, 0, 'p' }, { "jul-tcp-port", 1, 0, 'J' }, { "config", 1, 0, 'f' }, + { "load", 1, 0, 'l' }, { NULL, 0, 0, 0 } }; @@ -200,6 +203,7 @@ static pthread_t dispatch_thread; 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 @@ -291,17 +295,20 @@ int is_root; /* Set to 1 if the daemon is running as root */ 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) { /* @@ -647,6 +654,15 @@ static void cleanup(void) 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); + } + /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" "Matthew, BEET driven development works!%c[%dm", @@ -3723,7 +3739,7 @@ static void *thread_manage_health(void *data) goto error; } - lttng_sessiond_notify_ready(); + sessiond_notify_ready(); while (1) { DBG("Health check ready"); @@ -3875,7 +3891,12 @@ static void *thread_manage_clients(void *data) 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)) { @@ -4110,6 +4131,7 @@ static void usage(void) 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"); } /* @@ -4229,6 +4251,13 @@ static int set_option(int opt, const char *arg, const char *optname) 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 */ @@ -4756,6 +4785,35 @@ 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; +} + /* * main */ @@ -5065,6 +5123,11 @@ int main(int argc, char **argv) /* 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. @@ -5148,7 +5211,12 @@ int main(int argc, char **argv) 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"); -- 2.34.1