From 39313bf35301f186b2517e05e0bda38e138e868c Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Wed, 14 Apr 2021 13:39:03 -0400 Subject: [PATCH] Internal logging lazy-initialization Replace the initialization function by a lazy-init scheme, this way we don't loose logging messages when called from constructors across libraries or ld preloaded wrappers. Change-Id: Idb1593c025351af6aed152b31a2aab17b4d884b0 Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- src/common/logging.c | 61 +++++++++++++++++++++------ src/common/logging.h | 37 +++++++++++++--- src/lib/lttng-ust-common/ust-common.c | 3 -- src/lib/lttng-ust-ctl/ustctl.c | 2 - src/lib/lttng-ust-dl/lttng-ust-dl.c | 9 ---- src/lib/lttng-ust/lttng-ust-comm.c | 11 ++++- 6 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/common/logging.c b/src/common/logging.c index eb610833..fb3f119f 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -4,24 +4,57 @@ * Copyright (C) 2011 Mathieu Desnoyers */ +#include +#include + #include "common/logging.h" -volatile enum lttng_ust_log_level lttng_ust_log_level; +int lttng_ust_log_level = LTTNG_UST_LOG_LEVEL_UNKNOWN; -void lttng_ust_logging_init(void) +/* + * Initialize the global log level from the "LTTNG_UST_DEBUG" environment + * variable. + * + * This could end up being called concurently by multiple threads but doesn't + * require a mutex since the input is invariant across threads and the result + * will be the same. + * + * Return the current log level to save the caller a second read of the global + * log level. + */ +int lttng_ust_logging_init(void) { char *lttng_ust_debug; + int current_log_level; + + current_log_level = CMM_LOAD_SHARED(lttng_ust_log_level); + + /* + * Check early if we are initialized, this is unlikely as it's already tested + * in lttng_ust_debug_enabled before performing lazy initialization. + */ + if (caa_unlikely(current_log_level != LTTNG_UST_LOG_LEVEL_UNKNOWN)) + goto end; + + /* + * This getenv is not part of lttng_ust_getenv() because logging is + * used in the getenv initialization and thus logging must be + * initialized prior to getenv. + */ + lttng_ust_debug = getenv("LTTNG_UST_DEBUG"); + + /* + * If the LTTNG_UST_DEBUG environment variable is defined, print all + * messages, otherwise print nothing. + */ + if (lttng_ust_debug) + current_log_level = LTTNG_UST_LOG_LEVEL_DEBUG; + else + current_log_level = LTTNG_UST_LOG_LEVEL_SILENT; + + /* Initialize the log level */ + CMM_STORE_SHARED(lttng_ust_log_level, current_log_level); - if (lttng_ust_log_level == LTTNG_UST_LOG_LEVEL_UNKNOWN) { - /* - * This getenv is not part of lttng_ust_getenv() because it - * is required to print ERR() performed during getenv - * initialization. - */ - lttng_ust_debug = getenv("LTTNG_UST_DEBUG"); - if (lttng_ust_debug) - lttng_ust_log_level = LTTNG_UST_LOG_LEVEL_DEBUG; - else - lttng_ust_log_level = LTTNG_UST_LOG_LEVEL_NORMAL; - } +end: + return current_log_level; } diff --git a/src/common/logging.h b/src/common/logging.h index ab125e7c..5ebf17bf 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -16,6 +16,8 @@ #include #include +#include +#include #include "common/patient.h" #include "common/compat/tid.h" @@ -23,27 +25,48 @@ enum lttng_ust_log_level { LTTNG_UST_LOG_LEVEL_UNKNOWN = 0, - LTTNG_UST_LOG_LEVEL_NORMAL, + LTTNG_UST_LOG_LEVEL_SILENT, LTTNG_UST_LOG_LEVEL_DEBUG, }; -extern volatile enum lttng_ust_log_level lttng_ust_log_level +extern int lttng_ust_log_level /* enum lttng_ust_log_level */ __attribute__((visibility("hidden"))); -void lttng_ust_logging_init(void) +/* + * Initialize the global log level from the "LTTNG_UST_DEBUG" environment + * variable. + * + * This could end up being called concurrently by multiple threads but doesn't + * require a mutex since the input is invariant across threads and the result + * will be the same. + * + * Return the current log level to save the caller a second read of the global + * log level. + */ +int lttng_ust_logging_init(void) __attribute__((visibility("hidden"))); #ifdef LTTNG_UST_DEBUG -static inline bool lttng_ust_logging_debug_enabled(void) +static inline +bool lttng_ust_logging_debug_enabled(void) { return true; } #else /* #ifdef LTTNG_UST_DEBUG */ -static inline bool lttng_ust_logging_debug_enabled(void) +static inline +bool lttng_ust_logging_debug_enabled(void) { - return lttng_ust_log_level == LTTNG_UST_LOG_LEVEL_DEBUG; + int current_log_level; + + current_log_level = CMM_LOAD_SHARED(lttng_ust_log_level); + + /* If the global log level is unknown, lazy-initialize it. */ + if (caa_unlikely(current_log_level == LTTNG_UST_LOG_LEVEL_UNKNOWN)) + current_log_level = lttng_ust_logging_init(); + + return current_log_level == LTTNG_UST_LOG_LEVEL_DEBUG; } -#endif /* #else #ifdef LTTNG_UST_DEBUG */ +#endif /* #ifdef LTTNG_UST_DEBUG */ /* * The default component for error messages. diff --git a/src/lib/lttng-ust-common/ust-common.c b/src/lib/lttng-ust-common/ust-common.c index 036c1e28..cefff67a 100644 --- a/src/lib/lttng-ust-common/ust-common.c +++ b/src/lib/lttng-ust-common/ust-common.c @@ -13,9 +13,6 @@ void lttng_ust_common_init(void) static void lttng_ust_common_init(void) { - /* Initialize logging for liblttng-ust-common */ - lttng_ust_logging_init(); - /* * Initialize the fd-tracker, other libraries using it should also call * this in their constructor in case it gets executed before this one. diff --git a/src/lib/lttng-ust-ctl/ustctl.c b/src/lib/lttng-ust-ctl/ustctl.c index 817f89e4..394f1970 100644 --- a/src/lib/lttng-ust-ctl/ustctl.c +++ b/src/lib/lttng-ust-ctl/ustctl.c @@ -2906,8 +2906,6 @@ void ustctl_init(void) static void ustctl_init(void) { - lttng_ust_logging_init(); - lttng_ust_getenv_init(); /* Needs lttng_ust_logging_init() to be completed. */ lttng_ust_clock_init(); lttng_ust_ring_buffer_clients_init(); lttng_ust_counter_clients_init(); diff --git a/src/lib/lttng-ust-dl/lttng-ust-dl.c b/src/lib/lttng-ust-dl/lttng-ust-dl.c index 2b767e47..e07136ce 100644 --- a/src/lib/lttng-ust-dl/lttng-ust-dl.c +++ b/src/lib/lttng-ust-dl/lttng-ust-dl.c @@ -36,15 +36,6 @@ static void *(*__lttng_ust_plibc_dlmopen)(Lmid_t nsid, const char *filename, #endif static int (*__lttng_ust_plibc_dlclose)(void *handle); -static -void _lttng_ust_dl_init(void) - __attribute__((constructor)); -static -void _lttng_ust_dl_init(void) -{ - lttng_ust_logging_init(); -} - static void *_lttng_ust_dl_libc_dlopen(const char *filename, int flags) { diff --git a/src/lib/lttng-ust/lttng-ust-comm.c b/src/lib/lttng-ust/lttng-ust-comm.c index e02cffd2..cd5b378c 100644 --- a/src/lib/lttng-ust/lttng-ust-comm.c +++ b/src/lib/lttng-ust/lttng-ust-comm.c @@ -2120,8 +2120,17 @@ void lttng_ust_init(void) * sessiond (otherwise leading to errors when trying to create * sessiond before the init functions are completed). */ + + /* + * Both the logging and getenv lazy-initialization uses getenv() + * internally and thus needs to be explicitly initialized in + * liblttng-ust before we start any threads as an unsuspecting normally + * single threaded application using liblttng-ust could be using + * setenv() which is not thread-safe. + */ lttng_ust_logging_init(); - lttng_ust_getenv_init(); /* Needs lttng_ust_logging_init() to be completed. */ + lttng_ust_getenv_init(); + lttng_ust_tp_init(); lttng_ust_init_fd_tracker(); lttng_ust_clock_init(); -- 2.34.1