#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <signal.h>
+#include <limits.h>
#include <urcu/uatomic.h>
#include <urcu/futex.h>
#include <urcu/compiler.h>
#include <lttng/ust-ctl.h>
#include <urcu/tls-compat.h>
#include <ust-comm.h>
+#include <ust-fd.h>
#include <usterr-signal-safe.h>
#include <helper.h>
#include "tracepoint-internal.h"
#include "lttng-tracer-core.h"
#include "compat.h"
-#include "../libringbuffer/tlsfixup.h"
+#include "../libringbuffer/rb-init.h"
#include "lttng-ust-statedump.h"
#include "clock.h"
#include "../libringbuffer/getcpu.h"
#include "getenv.h"
+/* Concatenate lttng ust shared library name with its major version number. */
+#define LTTNG_UST_LIB_SO_NAME "liblttng-ust.so." LTTNG_UST_LIBRARY_VERSION_MAJOR
+
/*
* Has lttng ust comm constructor been called ?
*/
{
const char *val;
- val = (const char *) lttng_secure_getenv("LTTNG_HOME");
+ val = (const char *) lttng_getenv("LTTNG_HOME");
if (val != NULL) {
return val;
}
- return (const char *) lttng_secure_getenv("HOME");
+ return (const char *) lttng_getenv("HOME");
}
/*
lttng_fixup_nest_count_tls();
lttng_fixup_procname_tls();
lttng_fixup_ust_mutex_nest_tls();
+ lttng_ust_fixup_fd_tracker_tls();
}
int lttng_get_notify_socket(void *owner)
long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS;
if (!got_timeout_env) {
- str_timeout = getenv("LTTNG_UST_REGISTER_TIMEOUT");
+ str_timeout = lttng_getenv("LTTNG_UST_REGISTER_TIMEOUT");
got_timeout_env = 1;
}
if (str_timeout)
return 1;
}
+static
+void get_allow_blocking(void)
+{
+ const char *str_allow_blocking =
+ lttng_getenv("LTTNG_UST_ALLOW_BLOCKING");
+
+ if (str_allow_blocking) {
+ DBG("%s environment variable is set",
+ "LTTNG_UST_ALLOW_BLOCKING");
+ lttng_ust_ringbuffer_set_allow_blocking();
+ }
+}
+
static
int register_to_sessiond(int socket, enum ustctl_socket_type type)
{
}
}
DBG("Return value: %d", lur.ret_val);
+
+ ust_unlock();
+
+ /*
+ * Performed delayed statedump operations outside of the UST
+ * lock. We need to take the dynamic loader lock before we take
+ * the UST lock internally within handle_pending_statedump().
+ */
+ handle_pending_statedump(sock_info);
+
+ if (ust_lock()) {
+ ret = -LTTNG_UST_ERR_EXITING;
+ goto error;
+ }
+
ret = send_reply(sock, &lur);
if (ret < 0) {
DBG("error sending reply");
error:
ust_unlock();
- /*
- * Performed delayed statedump operations outside of the UST
- * lock. We need to take the dynamic loader lock before we take
- * the UST lock internally within handle_pending_statedump().
- */
- handle_pending_statedump(sock_info);
-
return ret;
}
goto error;
}
+ lttng_ust_lock_fd_tracker();
wait_shm_fd = get_wait_shm(sock_info, page_size);
if (wait_shm_fd < 0) {
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(wait_shm_fd);
+ if (ret < 0) {
+ ret = close(wait_shm_fd);
+ if (!ret) {
+ PERROR("Error closing fd");
+ }
+ lttng_ust_unlock_fd_tracker();
goto error;
}
+
+ wait_shm_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+
wait_shm_mmap = mmap(NULL, page_size, PROT_READ,
MAP_SHARED, wait_shm_fd, 0);
+
/* close shm fd immediately after taking the mmap reference */
+ lttng_ust_lock_fd_tracker();
ret = close(wait_shm_fd);
- if (ret) {
+ if (!ret) {
+ lttng_ust_delete_fd_from_tracker(wait_shm_fd);
+ } else {
PERROR("Error closing fd");
}
+ lttng_ust_unlock_fd_tracker();
+
if (wait_shm_mmap == MAP_FAILED) {
DBG("mmap error (can be caused by race with sessiond). Fallback to poll mode.");
goto error;
void *ust_listener_thread(void *arg)
{
struct sock_info *sock_info = arg;
- int sock, ret, prev_connect_failed = 0, has_waited = 0;
+ int sock, ret, prev_connect_failed = 0, has_waited = 0, fd;
long timeout;
lttng_ust_fixup_tls();
prev_connect_failed = 0;
}
+ if (ust_lock()) {
+ goto quit;
+ }
+
if (sock_info->socket != -1) {
+ /* FD tracker is updated by ustcomm_close_unix_sock() */
ret = ustcomm_close_unix_sock(sock_info->socket);
if (ret) {
ERR("Error closing %s ust cmd socket",
sock_info->socket = -1;
}
if (sock_info->notify_socket != -1) {
+ /* FD tracker is updated by ustcomm_close_unix_sock() */
ret = ustcomm_close_unix_sock(sock_info->notify_socket);
if (ret) {
ERR("Error closing %s ust notify socket",
sock_info->notify_socket = -1;
}
+
/*
* Register. We need to perform both connect and sending
* registration message before doing the next connect otherwise
* first connect registration message.
*/
/* Connect cmd socket */
+ lttng_ust_lock_fd_tracker();
ret = ustcomm_connect_unix_sock(sock_info->sock_path,
get_connect_sock_timeout());
if (ret < 0) {
+ lttng_ust_unlock_fd_tracker();
DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name);
prev_connect_failed = 1;
- if (ust_lock()) {
- goto quit;
- }
-
/*
* If we cannot find the sessiond daemon, don't delay
* constructor execution.
ust_unlock();
goto restart;
}
+ fd = ret;
+ ret = lttng_ust_add_fd_to_tracker(fd);
+ if (ret < 0) {
+ ret = close(fd);
+ if (ret) {
+ PERROR("close on sock_info->socket");
+ }
+ ret = -1;
+ lttng_ust_unlock_fd_tracker();
+ ust_unlock();
+ goto quit;
+ }
+
sock_info->socket = ret;
+ lttng_ust_unlock_fd_tracker();
+ ust_unlock();
+ /*
+ * Unlock/relock ust lock because connect is blocking (with
+ * timeout). Don't delay constructors on the ust lock for too
+ * long.
+ */
if (ust_lock()) {
goto quit;
}
}
ust_unlock();
+ /*
+ * Unlock/relock ust lock because connect is blocking (with
+ * timeout). Don't delay constructors on the ust lock for too
+ * long.
+ */
+ if (ust_lock()) {
+ goto quit;
+ }
/* Connect notify socket */
+ lttng_ust_lock_fd_tracker();
ret = ustcomm_connect_unix_sock(sock_info->sock_path,
get_connect_sock_timeout());
if (ret < 0) {
+ lttng_ust_unlock_fd_tracker();
DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name);
prev_connect_failed = 1;
- if (ust_lock()) {
- goto quit;
- }
-
/*
* If we cannot find the sessiond daemon, don't delay
* constructor execution.
ust_unlock();
goto restart;
}
+
+ fd = ret;
+ ret = lttng_ust_add_fd_to_tracker(fd);
+ if (ret < 0) {
+ ret = close(fd);
+ if (ret) {
+ PERROR("close on sock_info->notify_socket");
+ }
+ ret = -1;
+ lttng_ust_unlock_fd_tracker();
+ ust_unlock();
+ goto quit;
+ }
+
sock_info->notify_socket = ret;
+ lttng_ust_unlock_fd_tracker();
+
+ ust_unlock();
+ /*
+ * Unlock/relock ust lock because connect is blocking (with
+ * timeout). Don't delay constructors on the ust lock for too
+ * long.
+ */
+ if (ust_lock()) {
+ goto quit;
+ }
timeout = get_notify_sock_timeout();
if (timeout >= 0) {
WARN("Unsupported timeout value %ld", timeout);
}
- if (ust_lock()) {
- goto quit;
- }
-
ret = register_to_sessiond(sock_info->notify_socket,
USTCTL_SOCKET_NOTIFY);
if (ret < 0) {
pthread_attr_t thread_attr;
int timeout_mode;
int ret;
+ void *handle;
if (uatomic_xchg(&initialized, 1) == 1)
return;
lttng_ust_loaded = 1;
+ /*
+ * We need to ensure that the liblttng-ust library is not unloaded to avoid
+ * the unloading of code used by the ust_listener_threads as we can not
+ * reliably know when they exited. To do that, manually load
+ * liblttng-ust.so to increment the dynamic loader's internal refcount for
+ * this library so it never becomes zero, thus never gets unloaded from the
+ * address space of the process. Since we are already running in the
+ * constructor of the LTTNG_UST_LIB_SO_NAME library, calling dlopen will
+ * simply increment the refcount and no additionnal work is needed by the
+ * dynamic loader as the shared library is already loaded in the address
+ * space. As a safe guard, we use the RTLD_NODELETE flag to prevent
+ * unloading of the UST library if its refcount becomes zero (which should
+ * never happen). Do the return value check but discard the handle at the
+ * end of the function as it's not needed.
+ */
+ handle = dlopen(LTTNG_UST_LIB_SO_NAME, RTLD_LAZY | RTLD_NODELETE);
+ if (!handle) {
+ ERR("dlopen of liblttng-ust shared library (%s).", LTTNG_UST_LIB_SO_NAME);
+ }
+
/*
* We want precise control over the order in which we construct
* our sub-libraries vs starting to receive commands from
* sessiond before the init functions are completed).
*/
init_usterr();
+ lttng_ust_getenv_init(); /* Needs init_usterr() to be completed. */
init_tracepoint();
+ lttng_ust_init_fd_tracker();
lttng_ust_clock_init();
lttng_ust_getcpu_init();
lttng_ust_statedump_init();
timeout_mode = get_constructor_timeout(&constructor_timeout);
+ get_allow_blocking();
+
ret = sem_init(&constructor_wait, 0, 0);
if (ret) {
PERROR("sem_init");
{
if (URCU_TLS(lttng_ust_nest_count))
return;
+ lttng_context_vpid_reset();
lttng_context_vtid_reset();
+ lttng_context_procname_reset();
DBG("process %d", getpid());
/* Release urcu mutexes */
rcu_bp_after_fork_child();