#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
+#include <pthread.h>
#include <urcu/system.h>
#include "common/logging.h"
#include "common/macros.h"
char *value;
};
-static
-int lttng_ust_getenv_is_init = 0;
+/* lttng_ust_getenv_init_mutex provides mutual exclusion for initialization. */
+static pthread_mutex_t lttng_ust_getenv_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int lttng_ust_getenv_is_init = 0;
static struct lttng_env lttng_env[] = {
/*
- * LTTNG_UST_DEBUG is used directly by snprintf, because it
- * needs to be already set for ERR() used in
- * lttng_ust_getenv_init().
+ * LTTNG_UST_DEBUG and LTTNG_UST_ABORT_ON_CRITICAL are used directly by
+ * the internal logging, because they need to be already set for ERR()
+ * used in lttng_ust_getenv_init().
*/
{ "LTTNG_UST_DEBUG", LTTNG_ENV_NOT_SECURE, NULL, },
+ { "LTTNG_UST_ABORT_ON_CRITICAL", LTTNG_ENV_NOT_SECURE, NULL, },
/* Env. var. which can be used in setuid/setgid executables. */
{ "LTTNG_UST_WITHOUT_BADDR_STATEDUMP", LTTNG_ENV_NOT_SECURE, NULL, },
struct lttng_env *e;
bool found = false;
- if (!CMM_LOAD_SHARED(lttng_ust_getenv_is_init))
- abort();
+ /*
+ * Perform lazy initialization of lttng_ust_getenv for early use
+ * by library constructors.
+ */
+ lttng_ust_getenv_init();
for (i = 0; i < LTTNG_ARRAY_SIZE(lttng_env); i++) {
e = <tng_env[i];
{
size_t i;
- if (CMM_LOAD_SHARED(lttng_ust_getenv_is_init))
+ /*
+ * Return early if the init has already completed.
+ */
+ if (CMM_LOAD_SHARED(lttng_ust_getenv_is_init)) {
+ /*
+ * Load lttng_ust_getenv_is_init before reading environment cache.
+ */
+ cmm_smp_rmb();
return;
+ }
+
+ pthread_mutex_lock(<tng_ust_getenv_init_mutex);
+
+ /*
+ * Check again if the init has completed in another thread now that we
+ * have acquired the mutex.
+ */
+ if (lttng_ust_getenv_is_init)
+ goto end_init;
for (i = 0; i < LTTNG_ARRAY_SIZE(lttng_env); i++) {
struct lttng_env *e = <tng_env[i];
}
e->value = getenv(e->key);
}
+
+ /*
+ * Store environment cache before setting lttng_ust_getenv_is_init to 1.
+ */
+ cmm_smp_wmb();
CMM_STORE_SHARED(lttng_ust_getenv_is_init, 1);
+end_init:
+ pthread_mutex_unlock(<tng_ust_getenv_init_mutex);
}