X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=b290204024afcd4a761778cb5e359d42501a9ba5;hb=f968510a0810a8f1a03e181060b2fa282058d9ae;hp=0c96f012f528fd4929581107e45ba9314430a92e;hpb=bd703713989223b66362ed670e2b3b0097118f46;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 0c96f012..b2902040 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -20,6 +20,7 @@ */ #define _LGPL_SOURCE +#define _GNU_SOURCE #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +52,10 @@ #include "lttng-tracer-core.h" #include "compat.h" #include "../libringbuffer/tlsfixup.h" -#include "lttng-ust-baddr.h" +#include "lttng-ust-statedump.h" +#include "clock.h" +#include "../libringbuffer/getcpu.h" +#include "getenv.h" /* * Has lttng ust comm constructor been called ? @@ -68,9 +71,21 @@ static int initialized; * probe registration. * * ust_exit_mutex must never nest in ust_mutex. + * + * ust_fork_mutex must never nest in ust_mutex. + * + * ust_mutex_nest is a per-thread nesting counter, allowing the perf + * counter lazy initialization called by events within the statedump, + * which traces while the ust_mutex is held. + * + * ust_lock nests within the dynamic loader lock (within glibc) because + * it is taken within the library constructor. */ static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER; +/* Allow nesting the ust_mutex within the same thread. */ +static DEFINE_URCU_TLS(int, ust_mutex_nest); + /* * ust_exit_mutex protects thread_active variable wrt thread exit. It * cannot be done by ust_mutex because pthread_cancel(), which takes an @@ -80,16 +95,38 @@ static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER; */ static pthread_mutex_t ust_exit_mutex = PTHREAD_MUTEX_INITIALIZER; +/* + * ust_fork_mutex protects base address statedump tracing against forks. It + * prevents the dynamic loader lock to be taken (by base address statedump + * tracing) while a fork is happening, thus preventing deadlock issues with + * the dynamic loader lock. + */ +static pthread_mutex_t ust_fork_mutex = PTHREAD_MUTEX_INITIALIZER; + /* Should the ust comm thread quit ? */ static int lttng_ust_comm_should_quit; /* - * Return 0 on success, -1 if should quilt. + * Return 0 on success, -1 if should quit. * The lock is taken in both cases. + * Signal-safe. */ int ust_lock(void) { - pthread_mutex_lock(&ust_mutex); + sigset_t sig_all_blocked, orig_mask; + int ret; + + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (!URCU_TLS(ust_mutex_nest)++) + pthread_mutex_lock(&ust_mutex); + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } if (lttng_ust_comm_should_quit) { return -1; } else { @@ -101,15 +138,45 @@ int ust_lock(void) * ust_lock_nocheck() can be used in constructors/destructors, because * they are already nested within the dynamic loader lock, and therefore * have exclusive access against execution of liblttng-ust destructor. + * Signal-safe. */ void ust_lock_nocheck(void) { - pthread_mutex_lock(&ust_mutex); + sigset_t sig_all_blocked, orig_mask; + int ret; + + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (!URCU_TLS(ust_mutex_nest)++) + pthread_mutex_lock(&ust_mutex); + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } } +/* + * Signal-safe. + */ void ust_unlock(void) { - pthread_mutex_unlock(&ust_mutex); + sigset_t sig_all_blocked, orig_mask; + int ret; + + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (!--URCU_TLS(ust_mutex_nest)) + pthread_mutex_unlock(&ust_mutex); + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } } /* @@ -250,11 +317,11 @@ const char *get_lttng_home_dir(void) { const char *val; - val = (const char *) getenv("LTTNG_HOME"); + val = (const char *) lttng_secure_getenv("LTTNG_HOME"); if (val != NULL) { return val; } - return (const char *) getenv("HOME"); + return (const char *) lttng_secure_getenv("HOME"); } /* @@ -266,6 +333,22 @@ void lttng_fixup_nest_count_tls(void) asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count))); } +static +void lttng_fixup_ust_mutex_nest_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(ust_mutex_nest))); +} + +/* + * Fixup urcu bp TLS. + */ +static +void lttng_fixup_urcu_bp_tls(void) +{ + rcu_read_lock(); + rcu_read_unlock(); +} + int lttng_get_notify_socket(void *owner) { struct sock_info *info = owner; @@ -320,7 +403,7 @@ int setup_local_apps(void) /* * Get notify_sock timeout, in ms. - * -1: don't wait. 0: wait forever. >0: timeout, in ms. + * -1: wait forever. 0: don't wait. >0: timeout, in ms. */ static long get_timeout(void) @@ -343,7 +426,7 @@ long get_notify_sock_timeout(void) } /* - * Return values: -1: don't wait. 0: wait forever. 1: timeout wait. + * Return values: -1: wait forever. 0: don't wait. 1: timeout wait. */ static int get_constructor_timeout(struct timespec *constructor_timeout) @@ -366,7 +449,8 @@ int get_constructor_timeout(struct timespec *constructor_timeout) */ ret = clock_gettime(CLOCK_REALTIME, constructor_timeout); if (ret) { - return -1; + /* Don't wait. */ + return 0; } constructor_timeout->tv_sec += constructor_delay_ms / 1000UL; constructor_timeout->tv_nsec += @@ -375,6 +459,7 @@ int get_constructor_timeout(struct timespec *constructor_timeout) constructor_timeout->tv_sec++; constructor_timeout->tv_nsec -= 1000000000UL; } + /* Timeout wait (constructor_delay_ms). */ return 1; } @@ -450,7 +535,9 @@ void handle_pending_statedump(struct sock_info *sock_info) if (ctor_passed && 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); } } @@ -820,9 +907,14 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) sock_info->notify_socket = -1; } if (sock_info->wait_shm_mmap) { - ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE)); - if (ret) { - ERR("Error unmapping wait shm"); + long page_size; + + page_size = sysconf(_SC_PAGE_SIZE); + if (page_size > 0) { + ret = munmap(sock_info->wait_shm_mmap, page_size); + if (ret) { + ERR("Error unmapping wait shm"); + } } sock_info->wait_shm_mmap = NULL; } @@ -995,15 +1087,20 @@ error_close: static char *get_map_shm(struct sock_info *sock_info) { - size_t mmap_size = sysconf(_SC_PAGE_SIZE); + long page_size; int wait_shm_fd, ret; char *wait_shm_mmap; - wait_shm_fd = get_wait_shm(sock_info, mmap_size); + page_size = sysconf(_SC_PAGE_SIZE); + if (page_size < 0) { + goto error; + } + + wait_shm_fd = get_wait_shm(sock_info, page_size); if (wait_shm_fd < 0) { goto error; } - wait_shm_mmap = mmap(NULL, mmap_size, PROT_READ, + wait_shm_mmap = mmap(NULL, page_size, PROT_READ, MAP_SHARED, wait_shm_fd, 0); /* close shm fd immediately after taking the mmap reference */ ret = close(wait_shm_fd); @@ -1310,6 +1407,14 @@ quit: return NULL; } +/* + * Weak symbol to call when the ust malloc wrapper is not loaded. + */ +__attribute__((weak)) +void lttng_ust_malloc_wrapper_init(void) +{ +} + /* * sessiond monitoring thread: monitor presence of global and per-user * sessiond by polling the application common named pipe. @@ -1330,10 +1435,12 @@ void __attribute__((constructor)) lttng_ust_init(void) * 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(); /* * We want precise control over the order in which we construct @@ -1343,13 +1450,20 @@ void __attribute__((constructor)) lttng_ust_init(void) */ init_usterr(); init_tracepoint(); - lttng_ust_baddr_statedump_init(); + lttng_ust_clock_init(); + lttng_ust_getcpu_init(); + lttng_ust_statedump_init(); lttng_ring_buffer_metadata_client_init(); lttng_ring_buffer_client_overwrite_init(); lttng_ring_buffer_client_overwrite_rt_init(); lttng_ring_buffer_client_discard_init(); lttng_ring_buffer_client_discard_rt_init(); + lttng_perf_counter_init(); lttng_context_init(); + /* + * Invoke ust malloc wrapper init before starting other threads. + */ + lttng_ust_malloc_wrapper_init(); timeout_mode = get_constructor_timeout(&constructor_timeout); @@ -1453,12 +1567,13 @@ void lttng_ust_cleanup(int exiting) 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_ust_baddr_statedump_destroy(); + lttng_ust_statedump_destroy(); exit_tracepoint(); if (!exiting) { /* Reinitialize values for fork */ @@ -1546,6 +1661,9 @@ void ust_before_fork(sigset_t *save_sigset) if (ret == -1) { PERROR("sigprocmask"); } + + pthread_mutex_lock(&ust_fork_mutex); + ust_lock_nocheck(); rcu_bp_before_fork(); } @@ -1556,6 +1674,9 @@ static void ust_after_fork_common(sigset_t *restore_sigset) DBG("process %d", getpid()); ust_unlock(); + + pthread_mutex_unlock(&ust_fork_mutex); + /* Restore signals */ ret = sigprocmask(SIG_SETMASK, restore_sigset, NULL); if (ret == -1) {