X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=6eb4a892f7bf7d343ec3d77b8e9d6ab0cea38b33;hb=c0bbbd5af5c91c2f7b7b23fcc860b3e48754c059;hp=597712bc1313057daaa4ee32730b46c3951eb78d;hpb=86e361632f8cb161d6cf3cfd1bb964a7f7fa0a52;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 597712bc..6eb4a892 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include "lttng-tracer-core.h" #include "compat.h" #include "../libringbuffer/tlsfixup.h" +#include "lttng-ust-baddr.h" /* * Has lttng ust comm constructor been called ? @@ -61,11 +63,55 @@ static int initialized; * The ust_lock/ust_unlock lock is used as a communication thread mutex. * Held when handling a command, also held by fork() to deal with * removal of threads, and by exit path. + * + * The UST lock is the centralized mutex across UST tracing control and + * probe registration. + * + * ust_exit_mutex must never nest in ust_mutex. + */ +static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * ust_exit_mutex protects thread_active variable wrt thread exit. It + * cannot be done by ust_mutex because pthread_cancel(), which takes an + * internal libc lock, cannot nest within ust_mutex. + * + * It never nests within a ust_mutex. */ +static pthread_mutex_t ust_exit_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. + * The lock is taken in both cases. + */ +int ust_lock(void) +{ + pthread_mutex_lock(&ust_mutex); + if (lttng_ust_comm_should_quit) { + return -1; + } else { + return 0; + } +} + +/* + * 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. + */ +void ust_lock_nocheck(void) +{ + pthread_mutex_lock(&ust_mutex); +} + +void ust_unlock(void) +{ + pthread_mutex_unlock(&ust_mutex); +} + /* * Wait for either of these before continuing to the main * program: @@ -106,6 +152,8 @@ struct sock_info { char wait_shm_path[PATH_MAX]; char *wait_shm_mmap; + /* Keep track of lazy state dump not performed yet. */ + int statedump_pending; }; /* Socket from app (connect) to session daemon (listen) for communication */ @@ -122,6 +170,8 @@ struct sock_info global_apps = { .notify_socket = -1, .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME, + + .statedump_pending = 0, }; /* TODO: allow global_apps_sock_path override */ @@ -135,6 +185,8 @@ struct sock_info local_apps = { .socket = -1, .notify_socket = -1, + + .statedump_pending = 0, }; static int wait_poll_fallback; @@ -380,6 +432,28 @@ int handle_register_done(struct sock_info *sock_info) 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. + * + * 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. + */ +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) { + sock_info->statedump_pending = 0; + lttng_handle_pending_statedump(sock_info); + } +} + static int handle_message(struct sock_info *sock_info, int sock, struct ustcomm_ust_msg *lum) @@ -390,11 +464,9 @@ int handle_message(struct sock_info *sock_info, union ust_args args; ssize_t len; - ust_lock(); - memset(&lur, 0, sizeof(lur)); - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { ret = -LTTNG_UST_ERR_EXITING; goto end; } @@ -698,6 +770,14 @@ end: 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; } @@ -945,8 +1025,7 @@ void wait_for_sessiond(struct sock_info *sock_info) { int ret; - ust_lock(); - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } if (wait_poll_fallback) { @@ -1051,9 +1130,7 @@ restart: DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); prev_connect_failed = 1; - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1068,9 +1145,7 @@ restart: } sock_info->socket = ret; - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1111,9 +1186,7 @@ restart: DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); prev_connect_failed = 1; - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1150,9 +1223,7 @@ restart: WARN("Unsupported timeout value %ld", timeout); } - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1183,8 +1254,7 @@ restart: switch (len) { case 0: /* orderly shutdown */ DBG("%s lttng-sessiond has performed an orderly shutdown", sock_info->name); - ust_lock(); - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } /* @@ -1223,8 +1293,7 @@ restart: } end: - ust_lock(); - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } /* Cleanup socket handles before trying to reconnect */ @@ -1233,8 +1302,11 @@ end: goto restart; /* try to reconnect */ quit: - sock_info->thread_active = 0; ust_unlock(); + + pthread_mutex_lock(&ust_exit_mutex); + sock_info->thread_active = 0; + pthread_mutex_unlock(&ust_exit_mutex); return NULL; } @@ -1308,24 +1380,24 @@ void __attribute__((constructor)) lttng_ust_init(void) ERR("pthread_attr_setdetachstate: %s", strerror(ret)); } - ust_lock(); + 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; - ust_unlock(); + pthread_mutex_unlock(&ust_exit_mutex); if (local_apps.allowed) { - ust_lock(); + pthread_mutex_lock(&ust_exit_mutex); ret = pthread_create(&local_apps.ust_listener, &thread_attr, ust_listener_thread, &local_apps); if (ret) { ERR("pthread_create local: %s", strerror(ret)); } local_apps.thread_active = 1; - ust_unlock(); + pthread_mutex_unlock(&ust_exit_mutex); } else { handle_register_done(&local_apps); } @@ -1409,9 +1481,11 @@ void __attribute__((destructor)) lttng_ust_exit(void) * mutexes to ensure it is not in a mutex critical section when * pthread_cancel is later called. */ - ust_lock(); + ust_lock_nocheck(); lttng_ust_comm_should_quit = 1; + ust_unlock(); + pthread_mutex_lock(&ust_exit_mutex); /* cancel threads */ if (global_apps.thread_active) { ret = pthread_cancel(global_apps.ust_listener); @@ -1431,7 +1505,7 @@ void __attribute__((destructor)) lttng_ust_exit(void) local_apps.thread_active = 0; } } - ust_unlock(); + pthread_mutex_unlock(&ust_exit_mutex); /* * Do NOT join threads: use of sys_futex makes it impossible to @@ -1470,7 +1544,7 @@ void ust_before_fork(sigset_t *save_sigset) if (ret == -1) { PERROR("sigprocmask"); } - ust_lock(); + ust_lock_nocheck(); rcu_bp_before_fork(); } @@ -1519,3 +1593,9 @@ void ust_after_fork_child(sigset_t *restore_sigset) ust_after_fork_common(restore_sigset); lttng_ust_init(); } + +void lttng_ust_sockinfo_session_enabled(void *owner) +{ + struct sock_info *sock_info = owner; + sock_info->statedump_pending = 1; +}