*/
#define _LGPL_SOURCE
-#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/mman.h>
#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 "futex.h"
#include <urcu/compiler.h>
+#include <lttng/urcu/urcu-ust.h>
+#include <lttng/align.h>
#include <lttng/ust-events.h>
#include <lttng/ust-abi.h>
#include <lttng/ust.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"
+#include "ust-events-internal.h"
+
+/* Concatenate lttng ust shared library name with its major version number. */
+#define LTTNG_UST_LIB_SO_NAME "liblttng-ust.so." __ust_stringify(CONFIG_LTTNG_UST_LIBRARY_VERSION_MAJOR)
/*
* Has lttng ust comm constructor been called ?
*
* ust_lock nests within the dynamic loader lock (within glibc) because
* it is taken within the library constructor.
+ *
+ * The ust fd tracker lock nests within the ust_mutex.
*/
static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER;
/* 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.
int ust_lock(void)
{
sigset_t sig_all_blocked, orig_mask;
- int ret;
+ int ret, oldstate;
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
+ if (ret) {
+ ERR("pthread_setcancelstate: %s", strerror(ret));
+ }
+ if (oldstate != PTHREAD_CANCEL_ENABLE) {
+ ERR("pthread_setcancelstate: unexpected oldstate");
+ }
sigfillset(&sig_all_blocked);
ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
if (ret) {
void ust_lock_nocheck(void)
{
sigset_t sig_all_blocked, orig_mask;
- int ret;
+ int ret, oldstate;
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
+ if (ret) {
+ ERR("pthread_setcancelstate: %s", strerror(ret));
+ }
+ if (oldstate != PTHREAD_CANCEL_ENABLE) {
+ ERR("pthread_setcancelstate: unexpected oldstate");
+ }
sigfillset(&sig_all_blocked);
ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
if (ret) {
void ust_unlock(void)
{
sigset_t sig_all_blocked, orig_mask;
- int ret;
+ int ret, oldstate;
sigfillset(&sig_all_blocked);
ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
if (ret) {
ERR("pthread_sigmask: %s", strerror(ret));
}
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ if (ret) {
+ ERR("pthread_setcancelstate: %s", strerror(ret));
+ }
+ if (oldstate != PTHREAD_CANCEL_DISABLE) {
+ ERR("pthread_setcancelstate: unexpected oldstate");
+ }
}
/*
/*
* Doing this for both the global and local sessiond.
*/
-static int sem_count = { 2 };
+enum {
+ sem_count_initial_value = 4,
+};
+
+static int sem_count = sem_count_initial_value;
/*
* Counting nesting within lttng-ust. Used to ensure that calling fork()
const char *name;
pthread_t ust_listener; /* listener thread */
int root_handle;
- int constructor_sem_posted;
+ int registration_done;
int allowed;
int global;
int thread_active;
char *wait_shm_mmap;
/* Keep track of lazy state dump not performed yet. */
int statedump_pending;
+ int initial_statedump_done;
+ /* Keep procname for statedump */
+ char procname[LTTNG_UST_ABI_PROCNAME_LEN];
};
/* Socket from app (connect) to session daemon (listen) for communication */
.global = 1,
.root_handle = -1,
- .allowed = 1,
+ .registration_done = 0,
+ .allowed = 0,
.thread_active = 0,
.sock_path = LTTNG_DEFAULT_RUNDIR "/" LTTNG_UST_SOCK_FILENAME,
.wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME,
.statedump_pending = 0,
+ .initial_statedump_done = 0,
+ .procname[0] = '\0'
};
/* TODO: allow global_apps_sock_path override */
.name = "local",
.global = 0,
.root_handle = -1,
+ .registration_done = 0,
.allowed = 0, /* Check setuid bit first */
.thread_active = 0,
.notify_socket = -1,
.statedump_pending = 0,
+ .initial_statedump_done = 0,
+ .procname[0] = '\0'
};
static int wait_poll_fallback;
[ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
[ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+ [ LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE ] = "Create event notifier group",
+
/* Session FD commands */
[ LTTNG_UST_CHANNEL ] = "Create Channel",
[ LTTNG_UST_SESSION_START ] = "Start Session",
/* Event FD commands */
[ LTTNG_UST_FILTER ] = "Create Filter",
[ LTTNG_UST_EXCLUSION ] = "Add exclusions to event",
+
+ /* Event notifier group commands */
+ [ LTTNG_UST_EVENT_NOTIFIER_CREATE ] = "Create event notifier",
+
+ /* Session and event notifier group commands */
+ [ LTTNG_UST_COUNTER ] = "Create Counter",
+
+ /* Counter commands */
+ [ LTTNG_UST_COUNTER_GLOBAL ] = "Create Counter Global",
+ [ LTTNG_UST_COUNTER_CPU ] = "Create Counter CPU",
};
static const char *str_timeout;
extern void lttng_ring_buffer_client_discard_exit(void);
extern void lttng_ring_buffer_client_discard_rt_exit(void);
extern void lttng_ring_buffer_metadata_client_exit(void);
+extern void lttng_counter_client_percpu_32_modular_init(void);
+extern void lttng_counter_client_percpu_32_modular_exit(void);
+extern void lttng_counter_client_percpu_64_modular_init(void);
+extern void lttng_counter_client_percpu_64_modular_exit(void);
+static char *get_map_shm(struct sock_info *sock_info);
+
+ssize_t lttng_ust_read(int fd, void *buf, size_t len)
+{
+ ssize_t ret;
+ size_t copied = 0, to_copy = len;
+
+ do {
+ ret = read(fd, buf + copied, to_copy);
+ if (ret > 0) {
+ copied += ret;
+ to_copy -= ret;
+ }
+ } while ((ret > 0 && to_copy > 0)
+ || (ret < 0 && errno == EINTR));
+ if (ret > 0) {
+ ret = copied;
+ }
+ return ret;
+}
/*
* Returns the HOME directory path. Caller MUST NOT free(3) the returned
* pointer.
{
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");
}
/*
static
void lttng_fixup_urcu_bp_tls(void)
{
- rcu_read_lock();
- rcu_read_unlock();
+ (void) lttng_ust_urcu_read_ongoing();
+}
+
+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_perf_counter_tls();
+ lttng_ust_fixup_fd_tracker_tls();
+ lttng_fixup_cgroup_ns_tls();
+ lttng_fixup_ipc_ns_tls();
+ lttng_fixup_net_ns_tls();
+ lttng_fixup_time_ns_tls();
+ lttng_fixup_uts_ns_tls();
}
int lttng_get_notify_socket(void *owner)
return info->notify_socket;
}
+
+LTTNG_HIDDEN
+char* lttng_ust_sockinfo_get_procname(void *owner)
+{
+ struct sock_info *info = owner;
+
+ return info->procname;
+}
+
static
void print_cmd(int cmd, int handle)
{
lttng_ust_obj_get_name(handle), handle);
}
+static
+int setup_global_apps(void)
+{
+ int ret = 0;
+ assert(!global_apps.wait_shm_mmap);
+
+ global_apps.wait_shm_mmap = get_map_shm(&global_apps);
+ if (!global_apps.wait_shm_mmap) {
+ WARN("Unable to get map shm for global apps. Disabling LTTng-UST global tracing.");
+ global_apps.allowed = 0;
+ ret = -EIO;
+ goto error;
+ }
+
+ global_apps.allowed = 1;
+ lttng_pthread_getname_np(global_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN);
+error:
+ return ret;
+}
static
int setup_local_apps(void)
{
+ int ret = 0;
const char *home_dir;
uid_t uid;
+ assert(!local_apps.wait_shm_mmap);
+
uid = getuid();
/*
* Disallow per-user tracing for setuid binaries.
*/
if (uid != geteuid()) {
assert(local_apps.allowed == 0);
- return 0;
+ ret = 0;
+ goto end;
}
home_dir = get_lttng_home_dir();
if (!home_dir) {
WARN("HOME environment variable not set. Disabling LTTng-UST per-user tracing.");
assert(local_apps.allowed == 0);
- return -ENOENT;
+ ret = -ENOENT;
+ goto end;
}
local_apps.allowed = 1;
snprintf(local_apps.sock_path, PATH_MAX, "%s/%s/%s",
snprintf(local_apps.wait_shm_path, PATH_MAX, "/%s-%u",
LTTNG_UST_WAIT_FILENAME,
uid);
- return 0;
+
+ local_apps.wait_shm_mmap = get_map_shm(&local_apps);
+ if (!local_apps.wait_shm_mmap) {
+ WARN("Unable to get map shm for local apps. Disabling LTTng-UST per-user tracing.");
+ local_apps.allowed = 0;
+ ret = -EIO;
+ goto end;
+ }
+
+ lttng_pthread_getname_np(local_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN);
+end:
+ return ret;
}
/*
- * Get notify_sock timeout, in ms.
+ * Get socket timeout, in ms.
* -1: wait forever. 0: don't wait. >0: timeout, in ms.
*/
static
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)
constructor_delay_ms = strtol(str_timeout, NULL, 10);
+ /* All negative values are considered as "-1". */
+ if (constructor_delay_ms < -1)
+ constructor_delay_ms = -1;
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_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)
{
}
static
-int handle_register_done(struct sock_info *sock_info)
+void decrement_sem_count(unsigned int count)
{
int ret;
- if (sock_info->constructor_sem_posted)
- return 0;
- sock_info->constructor_sem_posted = 1;
+ assert(uatomic_read(&sem_count) >= count);
+
if (uatomic_read(&sem_count) <= 0) {
- return 0;
+ return;
}
- ret = uatomic_add_return(&sem_count, -1);
+
+ ret = uatomic_add_return(&sem_count, -count);
if (ret == 0) {
ret = sem_post(&constructor_wait);
assert(!ret);
}
+}
+
+static
+int handle_register_done(struct sock_info *sock_info)
+{
+ if (sock_info->registration_done)
+ return 0;
+ sock_info->registration_done = 1;
+
+ decrement_sem_count(1);
+ if (!sock_info->statedump_pending) {
+ sock_info->initial_statedump_done = 1;
+ decrement_sem_count(1);
+ }
+
+ return 0;
+}
+
+static
+int handle_register_failed(struct sock_info *sock_info)
+{
+ if (sock_info->registration_done)
+ return 0;
+ sock_info->registration_done = 1;
+ sock_info->initial_statedump_done = 1;
+
+ decrement_sem_count(2);
+
return 0;
}
/*
* Only execute pending statedump after the constructor semaphore has
- * been posted by each listener thread. This means statedump will only
- * be performed after the "registration done" command is received from
- * each session daemon the application is connected to.
+ * been posted by the current listener thread. This means statedump will
+ * only be performed after the "registration done" command is received
+ * from this thread's session daemon.
*
* This ensures we don't run into deadlock issues with the dynamic
* loader mutex, which is held while the constructor is called and
* waiting on the constructor semaphore. All operations requiring this
* dynamic loader lock need to be postponed using this mechanism.
+ *
+ * In a scenario with two session daemons connected to the application,
+ * it is possible that the first listener thread which receives the
+ * registration done command issues its statedump while the dynamic
+ * loader lock is still held by the application constructor waiting on
+ * the semaphore. It will however be allowed to proceed when the
+ * second session daemon sends the registration done command to the
+ * second listener thread. This situation therefore does not produce
+ * a deadlock.
*/
static
void handle_pending_statedump(struct sock_info *sock_info)
{
- int ctor_passed = sock_info->constructor_sem_posted;
-
- if (ctor_passed && sock_info->statedump_pending) {
+ if (sock_info->registration_done && sock_info->statedump_pending) {
sock_info->statedump_pending = 0;
pthread_mutex_lock(&ust_fork_mutex);
lttng_handle_pending_statedump(sock_info);
pthread_mutex_unlock(&ust_fork_mutex);
+
+ if (!sock_info->initial_statedump_done) {
+ sock_info->initial_statedump_done = 1;
+ decrement_sem_count(1);
+ }
+ }
+}
+
+static inline
+const char *bytecode_type_str(uint32_t cmd)
+{
+ switch (cmd) {
+ case LTTNG_UST_CAPTURE:
+ return "capture";
+ case LTTNG_UST_FILTER:
+ return "filter";
+ default:
+ abort();
+ }
+}
+
+static
+int handle_bytecode_recv(struct sock_info *sock_info,
+ int sock, struct ustcomm_ust_msg *lum)
+{
+ struct lttng_ust_bytecode_node *bytecode;
+ enum lttng_ust_bytecode_node_type type;
+ const struct lttng_ust_objd_ops *ops;
+ uint32_t data_size, data_size_max, reloc_offset;
+ uint64_t seqnum;
+ ssize_t len;
+ int ret = 0;
+
+ switch (lum->cmd) {
+ case LTTNG_UST_FILTER:
+ type = LTTNG_UST_BYTECODE_NODE_TYPE_FILTER;
+ data_size = lum->u.filter.data_size;
+ data_size_max = FILTER_BYTECODE_MAX_LEN;
+ reloc_offset = lum->u.filter.reloc_offset;
+ seqnum = lum->u.filter.seqnum;
+ break;
+ case LTTNG_UST_CAPTURE:
+ type = LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE;
+ data_size = lum->u.capture.data_size;
+ data_size_max = CAPTURE_BYTECODE_MAX_LEN;
+ reloc_offset = lum->u.capture.reloc_offset;
+ seqnum = lum->u.capture.seqnum;
+ break;
+ default:
+ abort();
+ }
+
+ if (data_size > data_size_max) {
+ ERR("Bytecode %s data size is too large: %u bytes",
+ bytecode_type_str(lum->cmd), data_size);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (reloc_offset > data_size) {
+ ERR("Bytecode %s reloc offset %u is not within data",
+ bytecode_type_str(lum->cmd), reloc_offset);
+ ret = -EINVAL;
+ goto end;
}
+
+ /* Allocate the structure AND the `data[]` field. */
+ bytecode = zmalloc(sizeof(*bytecode) + data_size);
+ if (!bytecode) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ bytecode->bc.len = data_size;
+ bytecode->bc.reloc_offset = reloc_offset;
+ bytecode->bc.seqnum = seqnum;
+ bytecode->type = type;
+
+ len = ustcomm_recv_unix_sock(sock, bytecode->bc.data, bytecode->bc.len);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error_free_bytecode;
+ default:
+ if (len == bytecode->bc.len) {
+ DBG("Bytecode %s data received",
+ bytecode_type_str(lum->cmd));
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d",
+ (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection",
+ sock_info->name);
+ ret = len;
+ goto error_free_bytecode;
+ }
+ ret = len;
+ goto error_free_bytecode;
+ } else {
+ DBG("Incorrect %s bytecode data message size: %zd",
+ bytecode_type_str(lum->cmd), len);
+ ret = -EINVAL;
+ goto error_free_bytecode;
+ }
+ }
+
+ ops = objd_ops(lum->handle);
+ if (!ops) {
+ ret = -ENOENT;
+ goto error_free_bytecode;
+ }
+
+ if (ops->cmd) {
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) bytecode,
+ NULL, sock_info);
+ if (ret)
+ goto error_free_bytecode;
+ /* don't free bytecode if everything went fine. */
+ } else {
+ ret = -ENOSYS;
+ goto error_free_bytecode;
+ }
+
+ goto end;
+
+error_free_bytecode:
+ free(bytecode);
+end:
+ return ret;
}
static
const struct lttng_ust_objd_ops *ops;
struct ustcomm_ust_reply lur;
union ust_args args;
+ char ctxstr[LTTNG_UST_SYM_NAME_LEN]; /* App context string. */
ssize_t len;
memset(&lur, 0, sizeof(lur));
if (ust_lock()) {
ret = -LTTNG_UST_ERR_EXITING;
- goto end;
+ goto error;
}
ops = objd_ops(lum->handle);
if (!ops) {
ret = -ENOENT;
- goto end;
+ goto error;
}
switch (lum->cmd) {
else
ret = lttng_ust_objd_unref(lum->handle, 1);
break;
+ case LTTNG_UST_CAPTURE:
case LTTNG_UST_FILTER:
- {
- /* Receive filter data */
- struct lttng_ust_filter_bytecode_node *bytecode;
-
- if (lum->u.filter.data_size > FILTER_BYTECODE_MAX_LEN) {
- ERR("Filter data size is too large: %u bytes",
- lum->u.filter.data_size);
- ret = -EINVAL;
+ ret = handle_bytecode_recv(sock_info, sock, lum);
+ if (ret)
goto error;
- }
+ break;
+ case LTTNG_UST_EXCLUSION:
+ {
+ /* Receive exclusion names */
+ struct lttng_ust_excluder_node *node;
+ unsigned int count;
- if (lum->u.filter.reloc_offset > lum->u.filter.data_size) {
- ERR("Filter reloc offset %u is not within data",
- lum->u.filter.reloc_offset);
- ret = -EINVAL;
+ count = lum->u.exclusion.count;
+ if (count == 0) {
+ /* There are no names to read */
+ ret = 0;
goto error;
}
-
- bytecode = zmalloc(sizeof(*bytecode) + lum->u.filter.data_size);
- if (!bytecode) {
+ node = zmalloc(sizeof(*node) +
+ count * LTTNG_UST_SYM_NAME_LEN);
+ if (!node) {
ret = -ENOMEM;
goto error;
}
- len = ustcomm_recv_unix_sock(sock, bytecode->bc.data,
- lum->u.filter.data_size);
+ node->excluder.count = count;
+ len = ustcomm_recv_unix_sock(sock, node->excluder.names,
+ count * LTTNG_UST_SYM_NAME_LEN);
switch (len) {
case 0: /* orderly shutdown */
ret = 0;
- free(bytecode);
+ free(node);
goto error;
default:
- if (len == lum->u.filter.data_size) {
- DBG("filter data received");
+ if (len == count * LTTNG_UST_SYM_NAME_LEN) {
+ DBG("Exclusion data received");
break;
} else if (len < 0) {
DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
if (len == -ECONNRESET) {
ERR("%s remote end closed connection", sock_info->name);
ret = len;
- free(bytecode);
+ free(node);
goto error;
}
ret = len;
- free(bytecode);
- goto end;
+ free(node);
+ goto error;
} else {
- DBG("incorrect filter data message size: %zd", len);
+ DBG("Incorrect exclusion data message size: %zd", len);
ret = -EINVAL;
- free(bytecode);
- goto end;
+ free(node);
+ goto error;
}
}
- bytecode->bc.len = lum->u.filter.data_size;
- bytecode->bc.reloc_offset = lum->u.filter.reloc_offset;
- bytecode->bc.seqnum = lum->u.filter.seqnum;
if (ops->cmd) {
ret = ops->cmd(lum->handle, lum->cmd,
- (unsigned long) bytecode,
+ (unsigned long) node,
&args, sock_info);
if (ret) {
- free(bytecode);
+ free(node);
}
- /* don't free bytecode if everything went fine. */
+ /* Don't free exclusion data if everything went fine. */
} else {
ret = -ENOSYS;
- free(bytecode);
+ free(node);
}
break;
}
- case LTTNG_UST_EXCLUSION:
+ case LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE:
{
- /* Receive exclusion names */
- struct lttng_ust_excluder_node *node;
- unsigned int count;
+ int event_notifier_notif_fd;
- count = lum->u.exclusion.count;
- if (count == 0) {
- /* There are no names to read */
+ len = ustcomm_recv_event_notifier_notif_fd_from_sessiond(sock,
+ &event_notifier_notif_fd);
+ switch (len) {
+ case 0: /* orderly shutdown */
ret = 0;
goto error;
+ case 1:
+ break;
+ default:
+ if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d",
+ (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection",
+ sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto error;
+ } else {
+ DBG("Incorrect event notifier fd message size: %zd",
+ len);
+ ret = -EINVAL;
+ goto error;
+ }
}
- node = zmalloc(sizeof(*node) +
- count * LTTNG_UST_SYM_NAME_LEN);
- if (!node) {
- ret = -ENOMEM;
- goto error;
- }
- node->excluder.count = count;
- len = ustcomm_recv_unix_sock(sock, node->excluder.names,
- count * LTTNG_UST_SYM_NAME_LEN);
+ args.event_notifier_handle.event_notifier_notif_fd =
+ event_notifier_notif_fd;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+ case LTTNG_UST_CHANNEL:
+ {
+ void *chan_data;
+ int wakeup_fd;
+
+ len = ustcomm_recv_channel_from_sessiond(sock,
+ &chan_data, lum->u.channel.len,
+ &wakeup_fd);
switch (len) {
case 0: /* orderly shutdown */
ret = 0;
- free(node);
goto error;
default:
- if (len == count * LTTNG_UST_SYM_NAME_LEN) {
- DBG("Exclusion data received");
+ if (len == lum->u.channel.len) {
+ DBG("channel data received");
break;
} else if (len < 0) {
DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
if (len == -ECONNRESET) {
ERR("%s remote end closed connection", sock_info->name);
ret = len;
- free(node);
goto error;
}
ret = len;
- free(node);
- goto end;
+ goto error;
} else {
- DBG("Incorrect exclusion data message size: %zd", len);
+ DBG("incorrect channel data message size: %zd", len);
ret = -EINVAL;
- free(node);
- goto end;
+ goto error;
}
}
- if (ops->cmd) {
+ args.channel.chan_data = chan_data;
+ args.channel.wakeup_fd = wakeup_fd;
+ if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
- (unsigned long) node,
+ (unsigned long) &lum->u,
&args, sock_info);
- if (ret) {
- free(node);
+ else
+ ret = -ENOSYS;
+ if (args.channel.wakeup_fd >= 0) {
+ int close_ret;
+
+ lttng_ust_lock_fd_tracker();
+ close_ret = close(args.channel.wakeup_fd);
+ lttng_ust_unlock_fd_tracker();
+ args.channel.wakeup_fd = -1;
+ if (close_ret)
+ PERROR("close");
+ }
+ free(args.channel.chan_data);
+ break;
+ }
+ case LTTNG_UST_STREAM:
+ {
+ int close_ret;
+
+ /* Receive shm_fd, wakeup_fd */
+ ret = ustcomm_recv_stream_from_sessiond(sock,
+ NULL,
+ &args.stream.shm_fd,
+ &args.stream.wakeup_fd);
+ if (ret) {
+ goto error;
+ }
+
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ if (args.stream.shm_fd >= 0) {
+ lttng_ust_lock_fd_tracker();
+ close_ret = close(args.stream.shm_fd);
+ lttng_ust_unlock_fd_tracker();
+ args.stream.shm_fd = -1;
+ if (close_ret)
+ PERROR("close");
+ }
+ if (args.stream.wakeup_fd >= 0) {
+ lttng_ust_lock_fd_tracker();
+ close_ret = close(args.stream.wakeup_fd);
+ lttng_ust_unlock_fd_tracker();
+ args.stream.wakeup_fd = -1;
+ if (close_ret)
+ PERROR("close");
+ }
+ break;
+ }
+ case LTTNG_UST_CONTEXT:
+ switch (lum->u.context.ctx) {
+ case LTTNG_UST_CONTEXT_APP_CONTEXT:
+ {
+ char *p;
+ size_t ctxlen, recvlen;
+
+ ctxlen = strlen("$app.") + lum->u.context.u.app_ctx.provider_name_len - 1
+ + strlen(":") + lum->u.context.u.app_ctx.ctx_name_len;
+ if (ctxlen >= LTTNG_UST_SYM_NAME_LEN) {
+ ERR("Application context string length size is too large: %zu bytes",
+ ctxlen);
+ ret = -EINVAL;
+ goto error;
}
- /* Don't free exclusion data if everything went fine. */
+ strcpy(ctxstr, "$app.");
+ p = &ctxstr[strlen("$app.")];
+ recvlen = ctxlen - strlen("$app.");
+ len = ustcomm_recv_unix_sock(sock, p, recvlen);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ default:
+ if (len == recvlen) {
+ DBG("app context data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto error;
+ } else {
+ DBG("incorrect app context data message size: %zd", len);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ /* Put : between provider and ctxname. */
+ p[lum->u.context.u.app_ctx.provider_name_len - 1] = ':';
+ args.app_context.ctxname = ctxstr;
+ break;
+ }
+ default:
+ break;
+ }
+ if (ops->cmd) {
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
} else {
ret = -ENOSYS;
- free(node);
}
break;
- }
- case LTTNG_UST_CHANNEL:
+ case LTTNG_UST_COUNTER:
{
- void *chan_data;
- int wakeup_fd;
+ void *counter_data;
- len = ustcomm_recv_channel_from_sessiond(sock,
- &chan_data, lum->u.channel.len,
- &wakeup_fd);
+ len = ustcomm_recv_counter_from_sessiond(sock,
+ &counter_data, lum->u.counter.len);
switch (len) {
case 0: /* orderly shutdown */
ret = 0;
goto error;
default:
- if (len == lum->u.channel.len) {
- DBG("channel data received");
+ if (len == lum->u.counter.len) {
+ DBG("counter data received");
break;
} else if (len < 0) {
DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
goto error;
}
ret = len;
- goto end;
+ goto error;
} else {
- DBG("incorrect channel data message size: %zd", len);
+ DBG("incorrect counter data message size: %zd", len);
ret = -EINVAL;
- goto end;
+ goto error;
}
}
- args.channel.chan_data = chan_data;
- args.channel.wakeup_fd = wakeup_fd;
+ args.counter.counter_data = counter_data;
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
(unsigned long) &lum->u,
ret = -ENOSYS;
break;
}
- case LTTNG_UST_STREAM:
+ case LTTNG_UST_COUNTER_GLOBAL:
{
- /* Receive shm_fd, wakeup_fd */
- ret = ustcomm_recv_stream_from_sessiond(sock,
- &lum->u.stream.len,
- &args.stream.shm_fd,
- &args.stream.wakeup_fd);
+ /* Receive shm_fd */
+ ret = ustcomm_recv_counter_shm_from_sessiond(sock,
+ &args.counter_shm.shm_fd);
if (ret) {
- goto end;
+ goto error;
+ }
+
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+ case LTTNG_UST_COUNTER_CPU:
+ {
+ /* Receive shm_fd */
+ ret = ustcomm_recv_counter_shm_from_sessiond(sock,
+ &args.counter_shm.shm_fd);
+ if (ret) {
+ goto error;
}
+
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
(unsigned long) &lum->u,
ret = -ENOSYS;
break;
}
+ case LTTNG_UST_EVENT_NOTIFIER_CREATE:
+ {
+ /* Receive struct lttng_ust_event_notifier */
+ struct lttng_ust_event_notifier event_notifier;
+
+ if (sizeof(event_notifier) != lum->u.event_notifier.len) {
+ DBG("incorrect event notifier data message size: %u", lum->u.event_notifier.len);
+ ret = -EINVAL;
+ goto error;
+ }
+ len = ustcomm_recv_unix_sock(sock, &event_notifier, sizeof(event_notifier));
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ default:
+ if (len == sizeof(event_notifier)) {
+ DBG("event notifier data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto error;
+ } else {
+ DBG("incorrect event notifier data message size: %zd", len);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &event_notifier,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+
default:
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
break;
}
-end:
lur.handle = lum->handle;
lur.cmd = lum->cmd;
lur.ret_val = ret;
}
}
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;
}
}
sock_info->root_handle = -1;
}
- sock_info->constructor_sem_posted = 0;
+ sock_info->registration_done = 0;
+ sock_info->initial_statedump_done = 0;
/*
* wait_shm_mmap, socket and notify socket are used by listener
if (sock_info->wait_shm_mmap) {
long page_size;
- page_size = sysconf(_SC_PAGE_SIZE);
- if (page_size > 0) {
+ page_size = LTTNG_UST_PAGE_SIZE;
+ if (page_size <= 0) {
+ if (!page_size) {
+ errno = EINVAL;
+ }
+ PERROR("Error in sysconf(_SC_PAGE_SIZE)");
+ } else {
ret = munmap(sock_info->wait_shm_mmap, page_size);
if (ret) {
ERR("Error unmapping wait shm");
char *wait_shm_mmap;
page_size = sysconf(_SC_PAGE_SIZE);
- if (page_size < 0) {
+ if (page_size <= 0) {
+ if (!page_size) {
+ errno = EINVAL;
+ }
+ PERROR("Error in sysconf(_SC_PAGE_SIZE)");
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;
static
void wait_for_sessiond(struct sock_info *sock_info)
{
- int ret;
-
+ /* Use ust_lock to check if we should quit. */
if (ust_lock()) {
goto quit;
}
if (wait_poll_fallback) {
goto error;
}
- if (!sock_info->wait_shm_mmap) {
- sock_info->wait_shm_mmap = get_map_shm(sock_info);
- if (!sock_info->wait_shm_mmap)
- goto error;
- }
ust_unlock();
+ assert(sock_info->wait_shm_mmap);
+
DBG("Waiting for %s apps sessiond", sock_info->name);
/* Wait for futex wakeup */
- if (uatomic_read((int32_t *) sock_info->wait_shm_mmap) == 0) {
- ret = futex_async((int32_t *) sock_info->wait_shm_mmap,
- FUTEX_WAIT, 0, NULL, NULL, 0);
- if (ret < 0) {
- if (errno == EFAULT) {
- wait_poll_fallback = 1;
- DBG(
+ if (uatomic_read((int32_t *) sock_info->wait_shm_mmap))
+ goto end_wait;
+
+ while (lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap,
+ FUTEX_WAIT, 0, NULL, NULL, 0)) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ /* Value already changed. */
+ goto end_wait;
+ case EINTR:
+ /* Retry if interrupted by signal. */
+ break; /* Get out of switch. */
+ case EFAULT:
+ wait_poll_fallback = 1;
+ DBG(
"Linux kernels 2.6.33 to 3.0 (with the exception of stable versions) "
"do not support FUTEX_WAKE on read-only memory mappings correctly. "
"Please upgrade your kernel "
"(fix is commit 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae in Linux kernel "
"mainline). LTTng-UST will use polling mode fallback.");
- if (ust_debug())
- PERROR("futex");
- }
+ if (ust_debug())
+ PERROR("futex");
+ goto end_wait;
}
}
+end_wait:
return;
quit:
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();
+ /*
+ * If available, add '-ust' to the end of this thread's
+ * process name
+ */
+ ret = lttng_ust_setustprocname();
+ if (ret) {
+ ERR("Unable to set UST process name");
+ }
+
/* Restart trying to connect to the session daemon */
restart:
if (prev_connect_failed) {
* deals with a killed or broken session daemon.
*/
sleep(5);
+ } else {
+ has_waited = 1;
}
- has_waited = 1;
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 */
- 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.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
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;
}
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
}
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.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
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) {
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto end;
print_cmd(lum.cmd, lum.handle);
ret = handle_message(sock_info, sock, &lum);
if (ret) {
- ERR("Error handling message for %s socket", sock_info->name);
+ ERR("Error handling message for %s socket",
+ sock_info->name);
+ /*
+ * Close socket if protocol error is
+ * detected.
+ */
+ goto end;
}
continue;
default:
pthread_attr_t thread_attr;
int timeout_mode;
int ret;
+ void *handle;
if (uatomic_xchg(&initialized, 1) == 1)
return;
* 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();
+
+ 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
* 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();
lttng_ring_buffer_client_overwrite_rt_init();
lttng_ring_buffer_client_discard_init();
lttng_ring_buffer_client_discard_rt_init();
+ lttng_counter_client_percpu_32_modular_init();
+ lttng_counter_client_percpu_64_modular_init();
lttng_perf_counter_init();
- lttng_context_init();
/*
* Invoke ust malloc wrapper init before starting other threads.
*/
timeout_mode = get_constructor_timeout(&constructor_timeout);
+ get_allow_blocking();
+
ret = sem_init(&constructor_wait, 0, 0);
- assert(!ret);
+ if (ret) {
+ PERROR("sem_init");
+ }
+
+ ret = setup_global_apps();
+ if (ret) {
+ assert(global_apps.allowed == 0);
+ DBG("global apps setup returned %d", ret);
+ }
ret = setup_local_apps();
if (ret) {
+ assert(local_apps.allowed == 0);
DBG("local apps setup returned %d", ret);
}
ERR("pthread_attr_setdetachstate: %s", strerror(ret));
}
- pthread_mutex_lock(&ust_exit_mutex);
- ret = pthread_create(&global_apps.ust_listener, &thread_attr,
- ust_listener_thread, &global_apps);
- if (ret) {
- ERR("pthread_create global: %s", strerror(ret));
+ if (global_apps.allowed) {
+ pthread_mutex_lock(&ust_exit_mutex);
+ ret = pthread_create(&global_apps.ust_listener, &thread_attr,
+ ust_listener_thread, &global_apps);
+ if (ret) {
+ ERR("pthread_create global: %s", strerror(ret));
+ }
+ global_apps.thread_active = 1;
+ pthread_mutex_unlock(&ust_exit_mutex);
+ } else {
+ handle_register_done(&global_apps);
}
- global_apps.thread_active = 1;
- pthread_mutex_unlock(&ust_exit_mutex);
if (local_apps.allowed) {
pthread_mutex_lock(&ust_exit_mutex);
ret = sem_timedwait(&constructor_wait,
&constructor_timeout);
} while (ret < 0 && errno == EINTR);
- if (ret < 0 && errno == ETIMEDOUT) {
- ERR("Timed out waiting for lttng-sessiond");
- } else {
- assert(!ret);
+ if (ret < 0) {
+ switch (errno) {
+ case ETIMEDOUT:
+ ERR("Timed out waiting for lttng-sessiond");
+ break;
+ case EINVAL:
+ PERROR("sem_timedwait");
+ break;
+ default:
+ ERR("Unexpected error \"%s\" returned by sem_timedwait",
+ strerror(errno));
+ }
}
break;
case -1:/* wait forever */
do {
ret = sem_wait(&constructor_wait);
} while (ret < 0 && errno == EINTR);
- assert(!ret);
+ if (ret < 0) {
+ switch (errno) {
+ case EINVAL:
+ PERROR("sem_wait");
+ break;
+ default:
+ ERR("Unexpected error \"%s\" returned by sem_wait",
+ strerror(errno));
+ }
+ }
break;
case 0: /* no timeout */
break;
void lttng_ust_cleanup(int exiting)
{
cleanup_sock_info(&global_apps, exiting);
- if (local_apps.allowed) {
- cleanup_sock_info(&local_apps, exiting);
- }
+ cleanup_sock_info(&local_apps, exiting);
+ local_apps.allowed = 0;
+ global_apps.allowed = 0;
/*
* The teardown in this function all affect data structures
* accessed under the UST lock by the listener thread. This
*/
lttng_ust_abi_exit();
lttng_ust_events_exit();
- lttng_context_exit();
lttng_perf_counter_exit();
lttng_ring_buffer_client_discard_rt_exit();
lttng_ring_buffer_client_discard_exit();
lttng_ring_buffer_client_overwrite_rt_exit();
lttng_ring_buffer_client_overwrite_exit();
lttng_ring_buffer_metadata_client_exit();
+ lttng_counter_client_percpu_32_modular_exit();
+ lttng_counter_client_percpu_64_modular_exit();
lttng_ust_statedump_destroy();
exit_tracepoint();
if (!exiting) {
/* Reinitialize values for fork */
- sem_count = 2;
+ sem_count = sem_count_initial_value;
lttng_ust_comm_should_quit = 0;
initialized = 0;
}
lttng_ust_cleanup(1);
}
+static
+void ust_context_ns_reset(void)
+{
+ lttng_context_pid_ns_reset();
+ lttng_context_cgroup_ns_reset();
+ lttng_context_ipc_ns_reset();
+ lttng_context_mnt_ns_reset();
+ lttng_context_net_ns_reset();
+ lttng_context_user_ns_reset();
+ lttng_context_time_ns_reset();
+ lttng_context_uts_ns_reset();
+}
+
+static
+void ust_context_vuids_reset(void)
+{
+ lttng_context_vuid_reset();
+ lttng_context_veuid_reset();
+ lttng_context_vsuid_reset();
+}
+
+static
+void ust_context_vgids_reset(void)
+{
+ lttng_context_vgid_reset();
+ lttng_context_vegid_reset();
+ lttng_context_vsgid_reset();
+}
+
/*
* We exclude the worker threads across fork and clone (except
* CLONE_VM), because these system calls only keep the forking thread
sigset_t all_sigs;
int ret;
+ /* Fixup lttng-ust TLS. */
+ lttng_ust_fixup_tls();
+
if (URCU_TLS(lttng_ust_nest_count))
return;
/* Disable signals */
pthread_mutex_lock(&ust_fork_mutex);
ust_lock_nocheck();
- rcu_bp_before_fork();
+ lttng_ust_urcu_before_fork();
+ if (lttng_ust_liburcu_bp_before_fork)
+ lttng_ust_liburcu_bp_before_fork();
+ lttng_ust_lock_fd_tracker();
+ lttng_perf_lock();
}
static void ust_after_fork_common(sigset_t *restore_sigset)
int ret;
DBG("process %d", getpid());
+ lttng_perf_unlock();
+ lttng_ust_unlock_fd_tracker();
ust_unlock();
pthread_mutex_unlock(&ust_fork_mutex);
if (URCU_TLS(lttng_ust_nest_count))
return;
DBG("process %d", getpid());
- rcu_bp_after_fork_parent();
+ lttng_ust_urcu_after_fork_parent();
+ if (lttng_ust_liburcu_bp_after_fork_parent)
+ lttng_ust_liburcu_bp_after_fork_parent();
/* Release mutexes and reenable signals */
ust_after_fork_common(restore_sigset);
}
{
if (URCU_TLS(lttng_ust_nest_count))
return;
+ lttng_context_vpid_reset();
+ lttng_context_vtid_reset();
+ lttng_context_procname_reset();
+ ust_context_ns_reset();
+ ust_context_vuids_reset();
+ ust_context_vgids_reset();
DBG("process %d", getpid());
/* Release urcu mutexes */
- rcu_bp_after_fork_child();
+ lttng_ust_urcu_after_fork_child();
+ if (lttng_ust_liburcu_bp_after_fork_child)
+ lttng_ust_liburcu_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();
}
+void ust_after_setns(void)
+{
+ ust_context_ns_reset();
+ ust_context_vuids_reset();
+ ust_context_vgids_reset();
+}
+
+void ust_after_unshare(void)
+{
+ ust_context_ns_reset();
+ ust_context_vuids_reset();
+ ust_context_vgids_reset();
+}
+
+void ust_after_setuid(void)
+{
+ ust_context_vuids_reset();
+}
+
+void ust_after_seteuid(void)
+{
+ ust_context_vuids_reset();
+}
+
+void ust_after_setreuid(void)
+{
+ ust_context_vuids_reset();
+}
+
+void ust_after_setresuid(void)
+{
+ ust_context_vuids_reset();
+}
+
+void ust_after_setgid(void)
+{
+ ust_context_vgids_reset();
+}
+
+void ust_after_setegid(void)
+{
+ ust_context_vgids_reset();
+}
+
+void ust_after_setregid(void)
+{
+ ust_context_vgids_reset();
+}
+
+void ust_after_setresgid(void)
+{
+ ust_context_vgids_reset();
+}
+
void lttng_ust_sockinfo_session_enabled(void *owner)
{
struct sock_info *sock_info = owner;