#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"
/* Should the ust comm thread quit ? */
static int lttng_ust_comm_should_quit;
+/*
+ * This variable can be tested by applications to check whether
+ * lttng-ust is loaded. They simply have to define their own
+ * "lttng_ust_loaded" weak symbol, and test it. It is set to 1 by the
+ * library constructor.
+ */
+int lttng_ust_loaded __attribute__((weak));
+
/*
* Return 0 on success, -1 if should quit.
* The lock is taken in both cases.
rcu_read_unlock();
}
+void lttng_ust_fixup_tls(void)
+{
+ lttng_fixup_urcu_bp_tls();
+ lttng_fixup_ringbuffer_tls();
+ lttng_fixup_vtid_tls();
+ 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)
{
struct sock_info *info = owner;
}
/*
- * Get notify_sock timeout, in ms.
+ * Get socket timeout, in ms.
* -1: wait forever. 0: don't wait. >0: timeout, in ms.
*/
static
return constructor_delay_ms;
}
+/* Timeout for notify socket send and recv. */
static
long get_notify_sock_timeout(void)
{
return get_timeout();
}
+/* Timeout for connecting to cmd and notify sockets. */
+static
+long get_connect_sock_timeout(void)
+{
+ return get_timeout();
+}
+
/*
* Return values: -1: wait forever. 0: don't wait. 1: timeout wait.
*/
return 1;
}
+static
+void get_blocking_retry_timeout(void)
+{
+ const char *str_blocking_retry_timeout =
+ lttng_secure_getenv("LTTNG_UST_BLOCKING_RETRY_TIMEOUT");
+
+ if (str_blocking_retry_timeout) {
+ long timeout = strtol(str_blocking_retry_timeout, NULL, 10);
+
+ if (timeout < 0)
+ timeout = -1;
+ if (timeout > INT_MAX) {
+ WARN("Saturating %s value from %ld to %d\n",
+ "LTTNG_UST_BLOCKING_RETRY_TIMEOUT",
+ timeout, INT_MAX);
+ timeout = INT_MAX;
+ }
+ DBG("%s environment variable value is %ld",
+ "LTTNG_UST_BLOCKING_RETRY_TIMEOUT",
+ timeout);
+ lttng_ust_ringbuffer_set_retry_timeout(timeout);
+ }
+}
+
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;
}
+ lttng_ust_add_fd_to_tracker(wait_shm_fd);
+ 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;
int sock, ret, prev_connect_failed = 0, has_waited = 0;
long timeout;
+ lttng_ust_fixup_tls();
/*
* If available, add '-ust' to the end of this thread's
* process name
}
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;
}
+ if (ust_lock()) {
+ goto quit;
+ }
+
/*
* Register. We need to perform both connect and sending
* registration message before doing the next connect otherwise
* first connect registration message.
*/
/* Connect cmd socket */
- ret = ustcomm_connect_unix_sock(sock_info->sock_path);
+ 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;
}
+ lttng_ust_add_fd_to_tracker(ret);
+ lttng_ust_unlock_fd_tracker();
sock_info->socket = ret;
+ 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 */
- ret = ustcomm_connect_unix_sock(sock_info->sock_path);
+ 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;
}
+ lttng_ust_add_fd_to_tracker(ret);
+ lttng_ust_unlock_fd_tracker();
sock_info->notify_socket = ret;
+ 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) {
{
}
-static
-void init_ust_env(void)
-{
- if (putenv("LTTNG_UST_LOADED=1"))
- DBG("Error setting LTTNG_UST_LOADED environment variable");
-}
-
/*
* sessiond monitoring thread: monitor presence of global and per-user
* sessiond by polling the application common named pipe.
* to be the dynamic linker mutex) and ust_lock, taken within
* the ust lock.
*/
- lttng_fixup_urcu_bp_tls();
- lttng_fixup_ringbuffer_tls();
- lttng_fixup_vtid_tls();
- lttng_fixup_nest_count_tls();
- lttng_fixup_procname_tls();
- lttng_fixup_ust_mutex_nest_tls();
+ lttng_ust_fixup_tls();
- init_ust_env();
+ lttng_ust_loaded = 1;
/*
* We want precise control over the order in which we construct
*/
init_usterr();
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_blocking_retry_timeout();
+
ret = sem_init(&constructor_wait, 0, 0);
if (ret) {
PERROR("sem_init");
{
cleanup_sock_info(&global_apps, exiting);
cleanup_sock_info(&local_apps, exiting);
+ local_apps.allowed = 0;
/*
* The teardown in this function all affect data structures
* accessed under the UST lock by the listener thread. This
sigset_t all_sigs;
int ret;
+ /* Fixup lttng-ust TLS. */
+ lttng_ust_fixup_tls();
+
if (URCU_TLS(lttng_ust_nest_count))
return;
/* Disable signals */
{
if (URCU_TLS(lttng_ust_nest_count))
return;
+ lttng_context_vtid_reset();
DBG("process %d", getpid());
/* Release urcu mutexes */
rcu_bp_after_fork_child();
lttng_ust_cleanup(0);
- lttng_context_vtid_reset();
/* Release mutexes and reenable signals */
ust_after_fork_common(restore_sigset);
lttng_ust_init();