X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=256cbdc625ef19f6da306124542a6e0a08ab593f;hb=37dddb65504eff070a64fb4a8f1c56ee81c3173c;hp=5a4b6bd8693ed5b427f8baf693a903949d025547;hpb=32ce85691c17b331072b1c0df96f69e8b388d134;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 5a4b6bd8..256cbdc6 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 ? @@ -106,6 +108,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 +126,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 +141,8 @@ struct sock_info local_apps = { .socket = -1, .notify_socket = -1, + + .statedump_pending = 0, }; static int wait_poll_fallback; @@ -172,15 +180,39 @@ static const char *cmd_name_mapping[] = { /* Event FD commands */ [ LTTNG_UST_FILTER ] = "Create Filter", + [ LTTNG_UST_EXCLUSION ] = "Add exclusions to event", }; +static const char *str_timeout; +static int got_timeout_env; + extern void lttng_ring_buffer_client_overwrite_init(void); +extern void lttng_ring_buffer_client_overwrite_rt_init(void); extern void lttng_ring_buffer_client_discard_init(void); +extern void lttng_ring_buffer_client_discard_rt_init(void); extern void lttng_ring_buffer_metadata_client_init(void); extern void lttng_ring_buffer_client_overwrite_exit(void); +extern void lttng_ring_buffer_client_overwrite_rt_exit(void); 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); +/* + * Returns the HOME directory path. Caller MUST NOT free(3) the returned + * pointer. + */ +static +const char *get_lttng_home_dir(void) +{ + const char *val; + + val = (const char *) getenv("LTTNG_HOME"); + if (val != NULL) { + return val; + } + return (const char *) getenv("HOME"); +} + /* * Force a read (imply TLS fixup for dlopen) of TLS variables. */ @@ -202,10 +234,12 @@ void print_cmd(int cmd, int handle) { const char *cmd_name = "Unknown"; - if (cmd_name_mapping[cmd]) { + if (cmd >= 0 && cmd < LTTNG_ARRAY_SIZE(cmd_name_mapping) + && cmd_name_mapping[cmd]) { cmd_name = cmd_name_mapping[cmd]; } - DBG("Message Received \"%s\", Handle \"%s\" (%d)", cmd_name, + DBG("Message Received \"%s\" (%d), Handle \"%s\" (%d)", + cmd_name, cmd, lttng_ust_obj_get_name(handle), handle); } @@ -223,7 +257,7 @@ int setup_local_apps(void) assert(local_apps.allowed == 0); return 0; } - home_dir = (const char *) getenv("HOME"); + home_dir = get_lttng_home_dir(); if (!home_dir) { WARN("HOME environment variable not set. Disabling LTTng-UST per-user tracing."); assert(local_apps.allowed == 0); @@ -240,6 +274,66 @@ int setup_local_apps(void) return 0; } +/* + * Get notify_sock timeout, in ms. + * -1: don't wait. 0: wait forever. >0: timeout, in ms. + */ +static +long get_timeout(void) +{ + long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS; + + if (!got_timeout_env) { + str_timeout = getenv("LTTNG_UST_REGISTER_TIMEOUT"); + got_timeout_env = 1; + } + if (str_timeout) + constructor_delay_ms = strtol(str_timeout, NULL, 10); + return constructor_delay_ms; +} + +static +long get_notify_sock_timeout(void) +{ + return get_timeout(); +} + +/* + * Return values: -1: don't wait. 0: wait forever. 1: timeout wait. + */ +static +int get_constructor_timeout(struct timespec *constructor_timeout) +{ + long constructor_delay_ms; + int ret; + + constructor_delay_ms = get_timeout(); + + switch (constructor_delay_ms) { + case -1:/* fall-through */ + case 0: + return constructor_delay_ms; + default: + break; + } + + /* + * If we are unable to find the current time, don't wait. + */ + ret = clock_gettime(CLOCK_REALTIME, constructor_timeout); + if (ret) { + return -1; + } + constructor_timeout->tv_sec += constructor_delay_ms / 1000UL; + constructor_timeout->tv_nsec += + (constructor_delay_ms % 1000UL) * 1000000UL; + if (constructor_timeout->tv_nsec >= 1000000000UL) { + constructor_timeout->tv_sec++; + constructor_timeout->tv_nsec -= 1000000000UL; + } + return 1; +} + static int register_to_sessiond(int socket, enum ustctl_socket_type type) { @@ -294,6 +388,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) @@ -330,7 +446,7 @@ int handle_message(struct sock_info *sock_info, if (lum->handle == LTTNG_UST_ROOT_HANDLE) ret = -EPERM; else - ret = lttng_ust_objd_unref(lum->handle); + ret = lttng_ust_objd_unref(lum->handle, 1); break; case LTTNG_UST_FILTER: { @@ -376,6 +492,7 @@ int handle_message(struct sock_info *sock_info, goto error; } ret = len; + free(bytecode); goto end; } else { DBG("incorrect filter data message size: %zd", len); @@ -401,12 +518,76 @@ int handle_message(struct sock_info *sock_info, } break; } + case LTTNG_UST_EXCLUSION: + { + /* Receive exclusion names */ + struct lttng_ust_excluder_node *node; + unsigned int count; + + count = lum->u.exclusion.count; + if (count == 0) { + /* There are no names to read */ + ret = 0; + goto error; + } + node = zmalloc(sizeof(*node) + + count * LTTNG_UST_SYM_NAME_LEN); + if (!node) { + ret = -ENOMEM; + goto error; + } + node->excluder.count = count; + len = ustcomm_recv_unix_sock(sock, node->excluder.names, + count * LTTNG_UST_SYM_NAME_LEN); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + free(node); + goto error; + default: + if (len == count * LTTNG_UST_SYM_NAME_LEN) { + DBG("Exclusion 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; + free(node); + goto error; + } + ret = len; + free(node); + goto end; + } else { + DBG("Incorrect exclusion data message size: %zd", len); + ret = -EINVAL; + free(node); + goto end; + } + } + if (ops->cmd) { + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) node, + &args, sock_info); + if (ret) { + free(node); + } + /* Don't free exclusion data if everything went fine. */ + } else { + ret = -ENOSYS; + free(node); + } + break; + } case LTTNG_UST_CHANNEL: { void *chan_data; + int wakeup_fd; len = ustcomm_recv_channel_from_sessiond(sock, - &chan_data, lum->u.channel.len); + &chan_data, lum->u.channel.len, + &wakeup_fd); switch (len) { case 0: /* orderly shutdown */ ret = 0; @@ -431,6 +612,7 @@ int handle_message(struct sock_info *sock_info, } } args.channel.chan_data = chan_data; + args.channel.wakeup_fd = wakeup_fd; if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, (unsigned long) &lum->u, @@ -546,6 +728,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; } @@ -554,6 +744,25 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) { int ret; + if (sock_info->root_handle != -1) { + ret = lttng_ust_objd_unref(sock_info->root_handle, 1); + if (ret) { + ERR("Error unref root handle"); + } + sock_info->root_handle = -1; + } + sock_info->constructor_sem_posted = 0; + + /* + * wait_shm_mmap, socket and notify socket are used by listener + * threads outside of the ust lock, so we cannot tear them down + * ourselves, because we cannot join on these threads. Leave + * responsibility of cleaning up these resources to the OS + * process exit. + */ + if (exiting) + return; + if (sock_info->socket != -1) { ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { @@ -568,21 +777,7 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) } sock_info->notify_socket = -1; } - if (sock_info->root_handle != -1) { - ret = lttng_ust_objd_unref(sock_info->root_handle); - if (ret) { - ERR("Error unref root handle"); - } - sock_info->root_handle = -1; - } - sock_info->constructor_sem_posted = 0; - /* - * 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) { + if (sock_info->wait_shm_mmap) { ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE)); if (ret) { ERR("Error unmapping wait shm"); @@ -611,6 +806,30 @@ int get_wait_shm(struct sock_info *sock_info, size_t mmap_size) */ wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0); if (wait_shm_fd >= 0) { + int32_t tmp_read; + ssize_t len; + size_t bytes_read = 0; + + /* + * Try to read the fd. If unable to do so, try opening + * it in write mode. + */ + do { + len = read(wait_shm_fd, + &((char *) &tmp_read)[bytes_read], + sizeof(tmp_read) - bytes_read); + if (len > 0) { + bytes_read += len; + } + } while ((len < 0 && errno == EINTR) + || (len > 0 && bytes_read < sizeof(tmp_read))); + if (bytes_read != sizeof(tmp_read)) { + ret = close(wait_shm_fd); + if (ret) { + ERR("close wait_shm_fd"); + } + goto open_write; + } goto end; } else if (wait_shm_fd < 0 && errno != ENOENT) { /* @@ -621,9 +840,11 @@ int get_wait_shm(struct sock_info *sock_info, size_t mmap_size) ERR("Error opening shm %s", sock_info->wait_shm_path); goto end; } + +open_write: /* - * If the open failed because the file did not exist, try - * creating it ourself. + * If the open failed because the file did not exist, or because + * the file was not truncated yet, try creating it ourself. */ URCU_TLS(lttng_ust_nest_count)++; pid = fork(); @@ -818,8 +1039,7 @@ void *ust_listener_thread(void *arg) { struct sock_info *sock_info = arg; int sock, ret, prev_connect_failed = 0, has_waited = 0; - int open_sock[2]; - int i; + long timeout; /* Restart trying to connect to the session daemon */ restart: @@ -838,11 +1058,6 @@ restart: has_waited = 1; prev_connect_failed = 0; } - ust_lock(); - - if (lttng_ust_comm_should_quit) { - goto quit; - } if (sock_info->socket != -1) { ret = ustcomm_close_unix_sock(sock_info->socket); @@ -861,26 +1076,41 @@ restart: sock_info->notify_socket = -1; } - /* Register */ - for (i = 0; i < 2; i++) { - ret = ustcomm_connect_unix_sock(sock_info->sock_path); - if (ret < 0) { - DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); - prev_connect_failed = 1; - /* - * If we cannot find the sessiond daemon, don't delay - * constructor execution. - */ - ret = handle_register_done(sock_info); - assert(!ret); - ust_unlock(); - goto restart; + /* + * Register. We need to perform both connect and sending + * registration message before doing the next connect otherwise + * we may reach unix socket connect queue max limits and block + * on the 2nd connect while the session daemon is awaiting the + * first connect registration message. + */ + /* Connect cmd socket */ + ret = ustcomm_connect_unix_sock(sock_info->sock_path); + if (ret < 0) { + 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) { + goto quit; } - open_sock[i] = ret; + + /* + * If we cannot find the sessiond daemon, don't delay + * constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; } + sock_info->socket = ret; + + ust_lock(); - sock_info->socket = open_sock[0]; - sock_info->notify_socket = open_sock[1]; + if (lttng_ust_comm_should_quit) { + goto quit; + } /* * Create only one root handle per listener thread for the whole @@ -910,6 +1140,60 @@ restart: ust_unlock(); goto restart; } + + ust_unlock(); + + /* Connect notify socket */ + ret = ustcomm_connect_unix_sock(sock_info->sock_path); + if (ret < 0) { + 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) { + goto quit; + } + + /* + * If we cannot find the sessiond daemon, don't delay + * constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; + } + sock_info->notify_socket = ret; + + timeout = get_notify_sock_timeout(); + if (timeout >= 0) { + /* + * Give at least 10ms to sessiond to reply to + * notifications. + */ + if (timeout < 10) + timeout = 10; + ret = ustcomm_setsockopt_rcv_timeout(sock_info->notify_socket, + timeout); + if (ret < 0) { + WARN("Error setting socket receive timeout"); + } + ret = ustcomm_setsockopt_snd_timeout(sock_info->notify_socket, + timeout); + if (ret < 0) { + WARN("Error setting socket send timeout"); + } + } else if (timeout < -1) { + WARN("Unsupported timeout value %ld", timeout); + } + + ust_lock(); + + if (lttng_ust_comm_should_quit) { + goto quit; + } + ret = register_to_sessiond(sock_info->notify_socket, USTCTL_SOCKET_NOTIFY); if (ret < 0) { @@ -992,46 +1276,6 @@ quit: return NULL; } -/* - * Return values: -1: don't wait. 0: wait forever. 1: timeout wait. - */ -static -int get_timeout(struct timespec *constructor_timeout) -{ - long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS; - char *str_delay; - int ret; - - str_delay = getenv("LTTNG_UST_REGISTER_TIMEOUT"); - if (str_delay) { - constructor_delay_ms = strtol(str_delay, NULL, 10); - } - - switch (constructor_delay_ms) { - case -1:/* fall-through */ - case 0: - return constructor_delay_ms; - default: - break; - } - - /* - * If we are unable to find the current time, don't wait. - */ - ret = clock_gettime(CLOCK_REALTIME, constructor_timeout); - if (ret) { - return -1; - } - constructor_timeout->tv_sec += constructor_delay_ms / 1000UL; - constructor_timeout->tv_nsec += - (constructor_delay_ms % 1000UL) * 1000000UL; - if (constructor_timeout->tv_nsec >= 1000000000UL) { - constructor_timeout->tv_sec++; - constructor_timeout->tv_nsec -= 1000000000UL; - } - return 1; -} - /* * sessiond monitoring thread: monitor presence of global and per-user * sessiond by polling the application common named pipe. @@ -1067,9 +1311,12 @@ void __attribute__((constructor)) lttng_ust_init(void) init_tracepoint(); 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(); - timeout_mode = get_timeout(&constructor_timeout); + timeout_mode = get_constructor_timeout(&constructor_timeout); ret = sem_init(&constructor_wait, 0, 0); assert(!ret); @@ -1170,7 +1417,10 @@ void lttng_ust_cleanup(int exiting) */ lttng_ust_abi_exit(); lttng_ust_events_exit(); + lttng_context_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(); exit_tracepoint(); @@ -1307,3 +1557,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; +}