X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=c6640954c6aa77d34203cbc6cda8c32eae34d7c6;hb=3327ac33b865cf2ee76934ded1c4b3b177edc3b9;hp=2d3766f1326ff407351e3d41088d2d5c0aacf094;hpb=13436238c6418c33e4eb3c3ab8e2a466f1597fd2;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 2d3766f1..c6640954 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -52,7 +52,7 @@ #include "lttng-tracer-core.h" #include "compat.h" #include "../libringbuffer/tlsfixup.h" -#include "../liblttng-ust-baddr/lttng-ust-baddr.h" +#include "lttng-ust-baddr.h" /* * Has lttng ust comm constructor been called ? @@ -63,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: @@ -108,7 +152,8 @@ struct sock_info { char wait_shm_path[PATH_MAX]; char *wait_shm_mmap; - struct lttng_session *session_enabled; + /* Keep track of lazy state dump not performed yet. */ + int statedump_pending; }; /* Socket from app (connect) to session daemon (listen) for communication */ @@ -126,7 +171,7 @@ struct sock_info global_apps = { .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME, - .session_enabled = NULL, + .statedump_pending = 0, }; /* TODO: allow global_apps_sock_path override */ @@ -141,7 +186,7 @@ struct sock_info local_apps = { .socket = -1, .notify_socket = -1, - .session_enabled = NULL, + .statedump_pending = 0, }; static int wait_poll_fallback; @@ -387,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) @@ -397,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; } @@ -705,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; } @@ -952,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) { @@ -1058,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; } @@ -1075,9 +1145,7 @@ restart: } sock_info->socket = ret; - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1118,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; } @@ -1157,9 +1223,7 @@ restart: WARN("Unsupported timeout value %ld", timeout); } - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1190,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; } /* @@ -1213,14 +1276,6 @@ restart: ret = handle_message(sock_info, sock, &lum); if (ret) { ERR("Error handling message for %s socket", sock_info->name); - } else { - struct lttng_session *session; - - session = sock_info->session_enabled; - if (session) { - sock_info->session_enabled = NULL; - lttng_ust_baddr_statedump(session); - } } continue; default: @@ -1238,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 */ @@ -1248,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; } @@ -1323,7 +1380,7 @@ void __attribute__((constructor)) lttng_ust_init(void) ERR("pthread_attr_setdetachstate: %s", strerror(ret)); } - ust_lock(); + ust_lock_nocheck(); ret = pthread_create(&global_apps.ust_listener, &thread_attr, ust_listener_thread, &global_apps); if (ret) { @@ -1333,7 +1390,7 @@ void __attribute__((constructor)) lttng_ust_init(void) ust_unlock(); if (local_apps.allowed) { - ust_lock(); + ust_lock_nocheck(); ret = pthread_create(&local_apps.ust_listener, &thread_attr, ust_listener_thread, &local_apps); if (ret) { @@ -1424,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); @@ -1446,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 @@ -1485,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(); } @@ -1535,9 +1594,8 @@ void ust_after_fork_child(sigset_t *restore_sigset) lttng_ust_init(); } -void lttng_ust_sockinfo_session_enabled(void *owner, - struct lttng_session *session_enabled) +void lttng_ust_sockinfo_session_enabled(void *owner) { struct sock_info *sock_info = owner; - sock_info->session_enabled = session_enabled; + sock_info->statedump_pending = 1; }