X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=a84316a9358caeda6be0138a439c3828dd979b8e;hb=8478887d1c753e281a584c0e8a3b63f34359ff76;hp=a73808e1128f7b63fbb62422e5f7bccc5115a9b4;hpb=458d678c8e42caa810b80a99d5f6a69f24598a37;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index a73808e1..a84316a9 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 @@ -51,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 +72,14 @@ static int initialized; * * 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; @@ -97,6 +106,14 @@ static pthread_mutex_t ust_fork_mutex = PTHREAD_MUTEX_INITIALIZER; /* Should the ust comm thread quit ? */ static int lttng_ust_comm_should_quit; +/* + * This variable can be tested by applications to check whether + * lttng-ust is loaded. They simply have to define their own + * "lttng_ust_loaded" weak symbol, and test it. It is set to 1 by the + * library constructor. + */ +int lttng_ust_loaded __attribute__((weak)); + /* * Return 0 on success, -1 if should quit. * The lock is taken in both cases. @@ -105,8 +122,15 @@ static int lttng_ust_comm_should_quit; int ust_lock(void) { sigset_t sig_all_blocked, orig_mask; - int ret; + int ret, oldstate; + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + if (ret) { + ERR("pthread_setcancelstate: %s", strerror(ret)); + } + if (oldstate != PTHREAD_CANCEL_ENABLE) { + ERR("pthread_setcancelstate: unexpected oldstate"); + } sigfillset(&sig_all_blocked); ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); if (ret) { @@ -134,8 +158,15 @@ int ust_lock(void) void ust_lock_nocheck(void) { sigset_t sig_all_blocked, orig_mask; - int ret; + int ret, oldstate; + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + if (ret) { + ERR("pthread_setcancelstate: %s", strerror(ret)); + } + if (oldstate != PTHREAD_CANCEL_ENABLE) { + ERR("pthread_setcancelstate: unexpected oldstate"); + } sigfillset(&sig_all_blocked); ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); if (ret) { @@ -155,7 +186,7 @@ void ust_lock_nocheck(void) void ust_unlock(void) { sigset_t sig_all_blocked, orig_mask; - int ret; + int ret, oldstate; sigfillset(&sig_all_blocked); ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); @@ -168,6 +199,13 @@ void ust_unlock(void) if (ret) { ERR("pthread_sigmask: %s", strerror(ret)); } + ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + if (ret) { + ERR("pthread_setcancelstate: %s", strerror(ret)); + } + if (oldstate != PTHREAD_CANCEL_DISABLE) { + ERR("pthread_setcancelstate: unexpected oldstate"); + } } /* @@ -299,6 +337,24 @@ extern void lttng_ring_buffer_client_discard_exit(void); extern void lttng_ring_buffer_client_discard_rt_exit(void); extern void lttng_ring_buffer_metadata_client_exit(void); +ssize_t lttng_ust_read(int fd, void *buf, size_t len) +{ + ssize_t ret; + size_t copied = 0, to_copy = len; + + do { + ret = read(fd, buf + copied, to_copy); + if (ret > 0) { + copied += ret; + to_copy -= ret; + } + } while ((ret > 0 && to_copy > 0) + || (ret < 0 && errno == EINTR)); + if (ret > 0) { + ret = copied; + } + return ret; +} /* * Returns the HOME directory path. Caller MUST NOT free(3) the returned * pointer. @@ -308,11 +364,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"); } /* @@ -330,6 +386,16 @@ 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; @@ -384,7 +450,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) @@ -397,6 +463,9 @@ long get_timeout(void) } if (str_timeout) constructor_delay_ms = strtol(str_timeout, NULL, 10); + /* All negative values are considered as "-1". */ + if (constructor_delay_ms < -1) + constructor_delay_ms = -1; return constructor_delay_ms; } @@ -407,7 +476,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) @@ -430,7 +499,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 += @@ -439,6 +509,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; } @@ -513,8 +584,8 @@ void handle_pending_statedump(struct sock_info *sock_info) int ctor_passed = sock_info->constructor_sem_posted; if (ctor_passed && sock_info->statedump_pending) { - pthread_mutex_lock(&ust_fork_mutex); sock_info->statedump_pending = 0; + pthread_mutex_lock(&ust_fork_mutex); lttng_handle_pending_statedump(sock_info); pthread_mutex_unlock(&ust_fork_mutex); } @@ -528,19 +599,20 @@ int handle_message(struct sock_info *sock_info, const struct lttng_ust_objd_ops *ops; struct ustcomm_ust_reply lur; union ust_args args; + char ctxstr[LTTNG_UST_SYM_NAME_LEN]; /* App context string. */ ssize_t len; memset(&lur, 0, sizeof(lur)); if (ust_lock()) { ret = -LTTNG_UST_ERR_EXITING; - goto end; + goto error; } ops = objd_ops(lum->handle); if (!ops) { ret = -ENOENT; - goto end; + goto error; } switch (lum->cmd) { @@ -601,12 +673,12 @@ int handle_message(struct sock_info *sock_info, } ret = len; free(bytecode); - goto end; + goto error; } else { DBG("incorrect filter data message size: %zd", len); ret = -EINVAL; free(bytecode); - goto end; + goto error; } } bytecode->bc.len = lum->u.filter.data_size; @@ -666,12 +738,12 @@ int handle_message(struct sock_info *sock_info, } ret = len; free(node); - goto end; + goto error; } else { DBG("Incorrect exclusion data message size: %zd", len); ret = -EINVAL; free(node); - goto end; + goto error; } } if (ops->cmd) { @@ -712,11 +784,11 @@ int handle_message(struct sock_info *sock_info, goto error; } ret = len; - goto end; + goto error; } else { DBG("incorrect channel data message size: %zd", len); ret = -EINVAL; - goto end; + goto error; } } args.channel.chan_data = chan_data; @@ -737,7 +809,7 @@ int handle_message(struct sock_info *sock_info, &args.stream.shm_fd, &args.stream.wakeup_fd); if (ret) { - goto end; + goto error; } if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, @@ -747,6 +819,64 @@ int handle_message(struct sock_info *sock_info, ret = -ENOSYS; break; } + case LTTNG_UST_CONTEXT: + switch (lum->u.context.ctx) { + case LTTNG_UST_CONTEXT_APP_CONTEXT: + { + char *p; + size_t ctxlen, recvlen; + + ctxlen = strlen("$app.") + lum->u.context.u.app_ctx.provider_name_len - 1 + + strlen(":") + lum->u.context.u.app_ctx.ctx_name_len; + if (ctxlen >= LTTNG_UST_SYM_NAME_LEN) { + ERR("Application context string length size is too large: %zu bytes", + ctxlen); + ret = -EINVAL; + goto error; + } + strcpy(ctxstr, "$app."); + p = &ctxstr[strlen("$app.")]; + recvlen = ctxlen - strlen("$app."); + len = ustcomm_recv_unix_sock(sock, p, recvlen); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + default: + if (len == recvlen) { + DBG("app context data received"); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", sock_info->name); + ret = len; + goto error; + } + ret = len; + goto error; + } else { + DBG("incorrect app context data message size: %zd", len); + ret = -EINVAL; + goto error; + } + } + /* Put : between provider and ctxname. */ + p[lum->u.context.u.app_ctx.provider_name_len - 1] = ':'; + args.app_context.ctxname = ctxstr; + break; + } + default: + break; + } + if (ops->cmd) { + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + } else { + ret = -ENOSYS; + } + break; default: if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, @@ -757,7 +887,6 @@ int handle_message(struct sock_info *sock_info, break; } -end: lur.handle = lum->handle; lur.cmd = lum->cmd; lur.ret_val = ret; @@ -889,7 +1018,12 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) long page_size; page_size = sysconf(_SC_PAGE_SIZE); - if (page_size > 0) { + if (page_size <= 0) { + if (!page_size) { + errno = EINVAL; + } + PERROR("Error in sysconf(_SC_PAGE_SIZE)"); + } else { ret = munmap(sock_info->wait_shm_mmap, page_size); if (ret) { ERR("Error unmapping wait shm"); @@ -1071,7 +1205,11 @@ char *get_map_shm(struct sock_info *sock_info) char *wait_shm_mmap; page_size = sysconf(_SC_PAGE_SIZE); - if (page_size < 0) { + if (page_size <= 0) { + if (!page_size) { + errno = EINVAL; + } + PERROR("Error in sysconf(_SC_PAGE_SIZE)"); goto error; } @@ -1099,8 +1237,6 @@ error: static void wait_for_sessiond(struct sock_info *sock_info) { - int ret; - if (ust_lock()) { goto quit; } @@ -1116,23 +1252,32 @@ void wait_for_sessiond(struct sock_info *sock_info) DBG("Waiting for %s apps sessiond", sock_info->name); /* Wait for futex wakeup */ - if (uatomic_read((int32_t *) sock_info->wait_shm_mmap) == 0) { - ret = futex_async((int32_t *) sock_info->wait_shm_mmap, - FUTEX_WAIT, 0, NULL, NULL, 0); - if (ret < 0) { - if (errno == EFAULT) { - wait_poll_fallback = 1; - DBG( + if (uatomic_read((int32_t *) sock_info->wait_shm_mmap)) + goto end_wait; + + while (futex_async((int32_t *) sock_info->wait_shm_mmap, + FUTEX_WAIT, 0, NULL, NULL, 0)) { + switch (errno) { + case EWOULDBLOCK: + /* Value already changed. */ + goto end_wait; + case EINTR: + /* Retry if interrupted by signal. */ + break; /* Get out of switch. */ + case EFAULT: + wait_poll_fallback = 1; + DBG( "Linux kernels 2.6.33 to 3.0 (with the exception of stable versions) " "do not support FUTEX_WAKE on read-only memory mappings correctly. " "Please upgrade your kernel " "(fix is commit 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae in Linux kernel " "mainline). LTTng-UST will use polling mode fallback."); - if (ust_debug()) - PERROR("futex"); - } + if (ust_debug()) + PERROR("futex"); + goto end_wait; } } +end_wait: return; quit: @@ -1158,6 +1303,15 @@ void *ust_listener_thread(void *arg) int sock, ret, prev_connect_failed = 0, has_waited = 0; long timeout; + /* + * If available, add '-ust' to the end of this thread's + * process name + */ + ret = lttng_ust_setustprocname(); + if (ret) { + ERR("Unable to set UST process name"); + } + /* Restart trying to connect to the session daemon */ restart: if (prev_connect_failed) { @@ -1171,8 +1325,9 @@ restart: * deals with a killed or broken session daemon. */ sleep(5); + } else { + has_waited = 1; } - has_waited = 1; prev_connect_failed = 0; } @@ -1351,7 +1506,13 @@ restart: print_cmd(lum.cmd, lum.handle); ret = handle_message(sock_info, sock, &lum); if (ret) { - ERR("Error handling message for %s socket", sock_info->name); + ERR("Error handling message for %s socket", + sock_info->name); + /* + * Close socket if protocol error is + * detected. + */ + goto end; } continue; default: @@ -1414,12 +1575,15 @@ 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(); + lttng_ust_loaded = 1; + /* * We want precise control over the order in which we construct * our sub-libraries vs starting to receive commands from @@ -1428,14 +1592,15 @@ 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. */ @@ -1444,7 +1609,9 @@ void __attribute__((constructor)) lttng_ust_init(void) timeout_mode = get_constructor_timeout(&constructor_timeout); ret = sem_init(&constructor_wait, 0, 0); - assert(!ret); + if (ret) { + PERROR("sem_init"); + } ret = setup_local_apps(); if (ret) { @@ -1509,17 +1676,34 @@ void __attribute__((constructor)) lttng_ust_init(void) ret = sem_timedwait(&constructor_wait, &constructor_timeout); } while (ret < 0 && errno == EINTR); - if (ret < 0 && errno == ETIMEDOUT) { - ERR("Timed out waiting for lttng-sessiond"); - } else { - assert(!ret); + if (ret < 0) { + switch (errno) { + case ETIMEDOUT: + ERR("Timed out waiting for lttng-sessiond"); + break; + case EINVAL: + PERROR("sem_timedwait"); + break; + default: + ERR("Unexpected error \"%s\" returned by sem_timedwait", + strerror(errno)); + } } break; case -1:/* wait forever */ do { ret = sem_wait(&constructor_wait); } while (ret < 0 && errno == EINTR); - assert(!ret); + if (ret < 0) { + switch (errno) { + case EINVAL: + PERROR("sem_wait"); + break; + default: + ERR("Unexpected error \"%s\" returned by sem_wait", + strerror(errno)); + } + } break; case 0: /* no timeout */ break; @@ -1530,9 +1714,8 @@ static void lttng_ust_cleanup(int exiting) { cleanup_sock_info(&global_apps, exiting); - if (local_apps.allowed) { - cleanup_sock_info(&local_apps, exiting); - } + cleanup_sock_info(&local_apps, exiting); + local_apps.allowed = 0; /* * The teardown in this function all affect data structures * accessed under the UST lock by the listener thread. This @@ -1542,14 +1725,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 */ @@ -1683,11 +1865,11 @@ void ust_after_fork_child(sigset_t *restore_sigset) { if (URCU_TLS(lttng_ust_nest_count)) return; + lttng_context_vtid_reset(); DBG("process %d", getpid()); /* Release urcu mutexes */ rcu_bp_after_fork_child(); lttng_ust_cleanup(0); - lttng_context_vtid_reset(); /* Release mutexes and reenable signals */ ust_after_fork_common(restore_sigset); lttng_ust_init();