X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=8e1a0f35ff74c820f0cc195a55ae38bf27850b1a;hb=cec91e30b077aa46175a9964a4cf38f54276e0e4;hp=4724fabc0d6a72cf57923cea7e6da44d94563052;hpb=246be17ec5a99beae7cc40eede54b4958958d8fb;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 4724fabc..8e1a0f35 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -63,11 +62,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 +151,8 @@ struct sock_info { char wait_shm_path[PATH_MAX]; char *wait_shm_mmap; - int 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 +170,7 @@ struct sock_info global_apps = { .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME, - .session_enabled = 0, + .statedump_pending = 0, }; /* TODO: allow global_apps_sock_path override */ @@ -141,7 +185,7 @@ struct sock_info local_apps = { .socket = -1, .notify_socket = -1, - .session_enabled = 0, + .statedump_pending = 0, }; static int wait_poll_fallback; @@ -221,6 +265,16 @@ void lttng_fixup_nest_count_tls(void) asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count))); } +/* + * 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; @@ -387,6 +441,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 +473,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,18 +779,15 @@ end: error: ust_unlock(); - return ret; -} -static -void handle_pending_statedumps(struct sock_info *sock_info) -{ - int ctor_passed = sock_info->constructor_sem_posted; + /* + * 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 (ctor_passed && sock_info->session_enabled) { - sock_info->session_enabled = 0; - lttng_handle_pending_statedumps(<tng_ust_baddr_statedump); - } + return ret; } static @@ -758,9 +829,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; } @@ -933,15 +1009,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); @@ -963,8 +1044,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) { @@ -1069,9 +1149,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; } @@ -1086,9 +1164,7 @@ restart: } sock_info->socket = ret; - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1129,9 +1205,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; } @@ -1168,9 +1242,7 @@ restart: WARN("Unsupported timeout value %ld", timeout); } - ust_lock(); - - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } @@ -1201,8 +1273,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; } /* @@ -1224,8 +1295,6 @@ restart: ret = handle_message(sock_info, sock, &lum); if (ret) { ERR("Error handling message for %s socket", sock_info->name); - } else { - handle_pending_statedumps(sock_info); } continue; default: @@ -1243,8 +1312,7 @@ restart: } end: - ust_lock(); - if (lttng_ust_comm_should_quit) { + if (ust_lock()) { goto quit; } /* Cleanup socket handles before trying to reconnect */ @@ -1253,11 +1321,22 @@ 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; } +/* + * 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. @@ -1278,6 +1357,7 @@ 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(); @@ -1291,12 +1371,17 @@ void __attribute__((constructor)) lttng_ust_init(void) */ init_usterr(); init_tracepoint(); + lttng_ust_baddr_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_context_init(); + /* + * Invoke ust malloc wrapper init before starting other threads. + */ + lttng_ust_malloc_wrapper_init(); timeout_mode = get_constructor_timeout(&constructor_timeout); @@ -1328,24 +1413,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); } @@ -1405,6 +1490,7 @@ void lttng_ust_cleanup(int exiting) lttng_ring_buffer_client_overwrite_rt_exit(); lttng_ring_buffer_client_overwrite_exit(); lttng_ring_buffer_metadata_client_exit(); + lttng_ust_baddr_statedump_destroy(); exit_tracepoint(); if (!exiting) { /* Reinitialize values for fork */ @@ -1429,9 +1515,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); @@ -1451,7 +1539,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 @@ -1490,7 +1578,7 @@ void ust_before_fork(sigset_t *save_sigset) if (ret == -1) { PERROR("sigprocmask"); } - ust_lock(); + ust_lock_nocheck(); rcu_bp_before_fork(); } @@ -1543,5 +1631,5 @@ void ust_after_fork_child(sigset_t *restore_sigset) void lttng_ust_sockinfo_session_enabled(void *owner) { struct sock_info *sock_info = owner; - sock_info->session_enabled = 1; + sock_info->statedump_pending = 1; }