X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=88ac59655d7208f434c9e255b702a32b31758213;hb=4495dd39c05739d0fb2bc463b7c093d2459ce2b6;hp=d0641c5c6e510b01d0538d9c36b07c5c430644c6;hpb=48621a4272bdeb1e8fced511ca6bf3c4c2240c15;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index d0641c5c..88ac5965 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -46,6 +46,7 @@ #include "tracepoint-internal.h" #include "ltt-tracer-core.h" #include "compat.h" +#include "../libringbuffer/tlsfixup.h" /* * Has lttng ust comm constructor been called ? @@ -235,6 +236,7 @@ int handle_message(struct sock_info *sock_info, struct ustcomm_ust_reply lur; int shm_fd, wait_fd; union ust_args args; + ssize_t len; ust_lock(); @@ -284,28 +286,30 @@ end: //lur.ret_code = USTCOMM_SESSION_FAIL; lur.ret_code = ret; } - switch (lum->cmd) { - case LTTNG_UST_STREAM: - /* - * Special-case reply to send stream info. - * Use lum.u output. - */ - lur.u.stream.memory_map_size = *args.stream.memory_map_size; - shm_fd = *args.stream.shm_fd; - wait_fd = *args.stream.wait_fd; - break; - case LTTNG_UST_METADATA: - case LTTNG_UST_CHANNEL: - lur.u.channel.memory_map_size = *args.channel.memory_map_size; - shm_fd = *args.channel.shm_fd; - wait_fd = *args.channel.wait_fd; - break; - case LTTNG_UST_TRACER_VERSION: - lur.u.version = lum->u.version; - break; - case LTTNG_UST_TRACEPOINT_LIST_GET: - memcpy(&lur.u.tracepoint, &lum->u.tracepoint, sizeof(lur.u.tracepoint)); - break; + if (ret >= 0) { + switch (lum->cmd) { + case LTTNG_UST_STREAM: + /* + * Special-case reply to send stream info. + * Use lum.u output. + */ + lur.u.stream.memory_map_size = *args.stream.memory_map_size; + shm_fd = *args.stream.shm_fd; + wait_fd = *args.stream.wait_fd; + break; + case LTTNG_UST_METADATA: + case LTTNG_UST_CHANNEL: + lur.u.channel.memory_map_size = *args.channel.memory_map_size; + shm_fd = *args.channel.shm_fd; + wait_fd = *args.channel.wait_fd; + break; + case LTTNG_UST_TRACER_VERSION: + lur.u.version = lum->u.version; + break; + case LTTNG_UST_TRACEPOINT_LIST_GET: + memcpy(&lur.u.tracepoint, &lum->u.tracepoint, sizeof(lur.u.tracepoint)); + break; + } } ret = send_reply(sock, &lur); if (ret < 0) { @@ -317,14 +321,20 @@ end: || lum->cmd == LTTNG_UST_CHANNEL || lum->cmd == LTTNG_UST_METADATA) && lur.ret_code == USTCOMM_OK) { + int sendret = 0; + /* we also need to send the file descriptors. */ ret = ustcomm_send_fds_unix_sock(sock, &shm_fd, &shm_fd, 1, sizeof(int)); if (ret < 0) { perror("send shm_fd"); - goto error; + sendret = ret; } + /* + * The sessiond expects 2 file descriptors, even upon + * error. + */ ret = ustcomm_send_fds_unix_sock(sock, &wait_fd, &wait_fd, 1, sizeof(int)); @@ -332,6 +342,26 @@ end: perror("send wait_fd"); goto error; } + if (sendret) { + ret = sendret; + goto error; + } + } + /* + * LTTNG_UST_TRACEPOINT_FIELD_LIST_GET needs to send the field + * after the reply. + */ + if (lur.ret_code == USTCOMM_OK) { + switch (lum->cmd) { + case LTTNG_UST_TRACEPOINT_FIELD_LIST_GET: + len = ustcomm_send_unix_sock(sock, + &args.field_list.entry, + sizeof(args.field_list.entry)); + if (len != sizeof(args.field_list.entry)) { + ret = -1; + goto error; + } + } } /* * We still have the memory map reference, and the fds have been @@ -383,12 +413,12 @@ error: } static -void cleanup_sock_info(struct sock_info *sock_info) +void cleanup_sock_info(struct sock_info *sock_info, int exiting) { int ret; if (sock_info->socket != -1) { - ret = close(sock_info->socket); + ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { ERR("Error closing apps socket"); } @@ -402,7 +432,13 @@ void cleanup_sock_info(struct sock_info *sock_info) sock_info->root_handle = -1; } sock_info->constructor_sem_posted = 0; - if (sock_info->wait_shm_mmap) { + /* + * wait_shm_mmap is used by listener threads outside of the + * ust lock, so we cannot tear it down ourselves, because we + * cannot join on these threads. Leave this task to the OS + * process exit. + */ + if (!exiting && sock_info->wait_shm_mmap) { ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE)); if (ret) { ERR("Error unmapping wait shm"); @@ -662,7 +698,7 @@ restart: } if (sock_info->socket != -1) { - ret = close(sock_info->socket); + ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { ERR("Error closing %s apps socket", sock_info->name); } @@ -813,12 +849,22 @@ int get_timeout(struct timespec *constructor_timeout) void __attribute__((constructor)) lttng_ust_init(void) { struct timespec constructor_timeout; + sigset_t sig_all_blocked, orig_parent_mask; int timeout_mode; int ret; if (uatomic_xchg(&initialized, 1) == 1) return; + /* + * Fixup interdependency between TLS fixup mutex (which happens + * to be the dynamic linker mutex) and ust_lock, taken within + * the ust lock. + */ + lttng_fixup_event_tls(); + lttng_fixup_ringbuffer_tls(); + lttng_fixup_vtid_tls(); + /* * We want precise control over the order in which we construct * our sub-libraries vs starting to receive commands from @@ -840,6 +886,18 @@ void __attribute__((constructor)) lttng_ust_init(void) if (ret) { ERR("Error setting up to local apps"); } + + /* A new thread created by pthread_create inherits the signal mask + * from the parent. To avoid any signal being received by the + * listener thread, we block all signals temporarily in the parent, + * while we create the listener thread. + */ + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_parent_mask); + if (ret) { + PERROR("pthread_sigmask: %s", strerror(ret)); + } + ret = pthread_create(&local_apps.ust_listener, NULL, ust_listener_thread, &local_apps); @@ -850,6 +908,12 @@ void __attribute__((constructor)) lttng_ust_init(void) handle_register_done(&local_apps); } + /* Restore original signal mask in parent */ + ret = pthread_sigmask(SIG_SETMASK, &orig_parent_mask, NULL); + if (ret) { + PERROR("pthread_sigmask: %s", strerror(ret)); + } + switch (timeout_mode) { case 1: /* timeout wait */ do { @@ -876,10 +940,17 @@ void __attribute__((constructor)) lttng_ust_init(void) static void lttng_ust_cleanup(int exiting) { - cleanup_sock_info(&global_apps); + cleanup_sock_info(&global_apps, exiting); if (local_apps.allowed) { - cleanup_sock_info(&local_apps); + cleanup_sock_info(&local_apps, exiting); } + /* + * The teardown in this function all affect data structures + * accessed under the UST lock by the listener thread. This + * lock, along with the lttng_ust_comm_should_quit flag, ensure + * that none of these threads are accessing this data at this + * point. + */ lttng_ust_abi_exit(); lttng_ust_events_exit(); ltt_ring_buffer_client_discard_exit(); @@ -913,6 +984,7 @@ void __attribute__((destructor)) lttng_ust_exit(void) lttng_ust_comm_should_quit = 1; ust_unlock(); + /* cancel threads */ ret = pthread_cancel(global_apps.ust_listener); if (ret) { ERR("Error cancelling global ust listener thread"); @@ -923,6 +995,14 @@ void __attribute__((destructor)) lttng_ust_exit(void) ERR("Error cancelling local ust listener thread"); } } + /* + * Do NOT join threads: use of sys_futex makes it impossible to + * join the threads without using async-cancel, but async-cancel + * is delivered by a signal, which could hit the target thread + * anywhere in its code path, including while the ust_lock() is + * held, causing a deadlock for the other thread. Let the OS + * cleanup the threads if there are stalled in a syscall. + */ lttng_ust_cleanup(1); }