X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=ee50db21e38b2c29a400b1ccec0065f72f28900c;hp=0625c11939b958f8b9d88ed3ce48a88a3074d703;hb=87597c2c3bbaa1502ad2025cbf16704829f3b464;hpb=9cc1ba3b1f895beb3ef4b10009372f6a859068dd diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 0625c1193..ee50db21e 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -332,7 +334,8 @@ struct lttng_ht *agent_apps_ht_by_sock = NULL; * - rotation_thread * - health_thread */ -int lttng_sessiond_ready = 4; +#define NR_LTTNG_SESSIOND_SUPPORT_THREADS 4 +int lttng_sessiond_ready = NR_LTTNG_SESSIOND_SUPPORT_THREADS; int sessiond_check_thread_quit_pipe(int fd, uint32_t events) { @@ -365,10 +368,21 @@ LTTNG_HIDDEN void sessiond_notify_ready(void) { /* - * The _return variant is used since the implied memory barriers are - * required. + * This memory barrier is paired with the one performed by + * the client thread after it has seen that 'lttng_sessiond_ready' is 0. + * + * The purpose of these memory barriers is to ensure that all + * initialization operations of the various threads that call this + * function to signal that they are ready are commited/published + * before the client thread can see the 'lttng_sessiond_ready' counter + * reach 0. + * + * Note that this could be a 'write' memory barrier, but a full barrier + * is used in case the code using this utility changes. The performance + * implications of this choice are minimal since this is a slow path. */ - (void) uatomic_sub_return(<tng_sessiond_ready, 1); + cmm_smp_mb(); + uatomic_sub(<tng_sessiond_ready, 1); } static @@ -579,15 +593,9 @@ static void sessiond_cleanup(void) */ utils_close_pipe(thread_quit_pipe); - /* - * If config.pid_file_path.value is undefined, the default file will be - * wiped when removing the rundir. - */ - if (config.pid_file_path.value) { - ret = remove(config.pid_file_path.value); - if (ret < 0) { - PERROR("remove pidfile %s", config.pid_file_path.value); - } + ret = remove(config.pid_file_path.value); + if (ret < 0) { + PERROR("remove pidfile %s", config.pid_file_path.value); } DBG("Removing sessiond and consumerd content of directory %s", @@ -846,7 +854,7 @@ error: * * Useful for CPU hotplug feature. */ -static int update_kernel_stream(struct consumer_data *consumer_data, int fd) +static int update_kernel_stream(int fd) { int ret = 0; struct ltt_session *session; @@ -1080,7 +1088,7 @@ static void *thread_manage_kernel(void *data) * New CPU detected by the kernel. Adding kernel stream to * kernel session and updating the kernel consumer */ - ret = update_kernel_stream(&kconsumer_data, pollfd); + ret = update_kernel_stream(pollfd); if (ret < 0) { continue; } @@ -2924,6 +2932,112 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) return i; } +static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock, + int *sock_error, struct lttng_event *event) +{ + int fd, ret; + struct lttng_userspace_probe_location *probe_location; + const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + struct lttng_dynamic_buffer probe_location_buffer; + struct lttng_buffer_view buffer_view; + + /* + * Create a buffer to store the serialized version of the probe + * location. + */ + lttng_dynamic_buffer_init(&probe_location_buffer); + ret = lttng_dynamic_buffer_set_size(&probe_location_buffer, + cmd_ctx->lsm->u.enable.userspace_probe_location_len); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + + /* + * Receive the probe location. + */ + ret = lttcomm_recv_unix_sock(sock, probe_location_buffer.data, + probe_location_buffer.size); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + lttng_dynamic_buffer_reset(&probe_location_buffer); + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + buffer_view = lttng_buffer_view_from_dynamic_buffer( + &probe_location_buffer, 0, probe_location_buffer.size); + + /* + * Extract the probe location from the serialized version. + */ + ret = lttng_userspace_probe_location_create_from_buffer( + &buffer_view, &probe_location); + if (ret < 0) { + WARN("Failed to create a userspace probe location from the received buffer"); + lttng_dynamic_buffer_reset( &probe_location_buffer); + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * Receive the file descriptor to the target binary from the client. + */ + DBG("Receiving userspace probe target FD from client ..."); + ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1); + if (ret <= 0) { + DBG("Nothing recv() from client userspace probe fd... continuing"); + *sock_error = 1; + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * Set the file descriptor received from the client through the unix + * socket in the probe location. + */ + lookup = lttng_userspace_probe_location_get_lookup_method(probe_location); + if (!lookup) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From the kernel tracer's perspective, all userspace probe event types + * are all the same: a file and an offset. + */ + switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: + ret = lttng_userspace_probe_location_function_set_binary_fd( + probe_location, fd); + break; + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + ret = lttng_userspace_probe_location_tracepoint_set_binary_fd( + probe_location, fd); + break; + default: + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + if (ret) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* Attach the probe location to the event. */ + ret = lttng_event_set_userspace_probe_location(event, probe_location); + if (ret) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + lttng_dynamic_buffer_reset(&probe_location_buffer); +error: + return ret; +} + /* * Check if the current kernel tracer supports the session rotation feature. * Return 1 if it does, 0 otherwise. @@ -2988,8 +3102,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_ROTATION_GET_INFO: case LTTNG_SESSION_GET_CURRENT_OUTPUT: case LTTNG_ROTATION_SET_SCHEDULE: - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: need_domain = 0; break; default: @@ -3034,8 +3147,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_DATA_PENDING: case LTTNG_ROTATE_SESSION: case LTTNG_ROTATION_GET_INFO: - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: break; default: /* Setup lttng message with no payload */ @@ -3464,6 +3576,7 @@ error_add_context: } case LTTNG_ENABLE_EVENT: { + struct lttng_event *ev = NULL; struct lttng_event_exclusion *exclusion = NULL; struct lttng_filter_bytecode *bytecode = NULL; char *filter_expression = NULL; @@ -3515,7 +3628,7 @@ error_add_context: ret = lttcomm_recv_unix_sock(sock, filter_expression, expression_len); if (ret <= 0) { - DBG("Nothing recv() from client car len data... continuing"); + DBG("Nothing recv() from client var len data... continuing"); *sock_error = 1; free(filter_expression); free(exclusion); @@ -3547,7 +3660,7 @@ error_add_context: DBG("Receiving var len filter's bytecode from client ..."); ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len); if (ret <= 0) { - DBG("Nothing recv() from client car len data... continuing"); + DBG("Nothing recv() from client var len data... continuing"); *sock_error = 1; free(filter_expression); free(bytecode); @@ -3565,11 +3678,30 @@ error_add_context: } } + ev = lttng_event_copy(&cmd_ctx->lsm->u.enable.event); + if (!ev) { + DBG("Failed to copy event: %s", + cmd_ctx->lsm->u.enable.event.name); + ret = LTTNG_ERR_NOMEM; + goto error; + } + + + if (cmd_ctx->lsm->u.enable.userspace_probe_location_len > 0) { + /* Expect a userspace probe description. */ + ret = receive_userspace_probe(cmd_ctx, sock, sock_error, ev); + if (ret) { + lttng_event_destroy(ev); + goto error; + } + } + ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, + ev, filter_expression, bytecode, exclusion, kernel_poll_pipe[1]); + lttng_event_destroy(ev); break; } case LTTNG_LIST_TRACEPOINTS: @@ -4214,15 +4346,24 @@ error_add_context: } case LTTNG_ROTATION_SET_SCHEDULE: { + bool set_schedule; + enum lttng_rotation_schedule_type schedule_type; + uint64_t value; + if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { DBG("Kernel tracer version does not support session rotations"); ret = LTTNG_ERR_ROTATION_WRONG_VERSION; goto error; } + set_schedule = cmd_ctx->lsm->u.rotation_set_schedule.set == 1; + schedule_type = (enum lttng_rotation_schedule_type) cmd_ctx->lsm->u.rotation_set_schedule.type; + value = cmd_ctx->lsm->u.rotation_set_schedule.value; + ret = cmd_rotation_set_schedule(cmd_ctx->session, - cmd_ctx->lsm->u.rotate_setup.timer_us, - cmd_ctx->lsm->u.rotate_setup.size, + set_schedule, + schedule_type, + value, notification_thread_handle); if (ret != LTTNG_OK) { goto error; @@ -4230,42 +4371,17 @@ error_add_context: break; } - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: - { - struct lttng_rotation_schedule_get_timer_period *get_timer; - - get_timer = zmalloc(sizeof(struct lttng_rotation_schedule_get_timer_period)); - if (!get_timer) { - ret = ENOMEM; - goto error; - } - get_timer->rotate_timer = cmd_ctx->session->rotate_timer_period; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_timer, - sizeof(struct lttng_rotation_schedule_get_timer_period)); - free(get_timer); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: { - struct lttng_rotation_schedule_get_size *get_size; - - get_size = zmalloc(sizeof(struct lttng_rotation_schedule_get_size)); - if (!get_size) { - ret = ENOMEM; - goto error; - } - get_size->rotate_size = cmd_ctx->session->rotate_size; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_size, - sizeof(struct lttng_rotation_schedule_get_size)); - free(get_size); + struct lttng_session_list_schedules_return schedules = { + .periodic.set = !!cmd_ctx->session->rotate_timer_period, + .periodic.value = cmd_ctx->session->rotate_timer_period, + .size.set = !!cmd_ctx->session->rotate_size, + .size.value = cmd_ctx->session->rotate_size, + }; + + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &schedules, + sizeof(schedules)); if (ret < 0) { ret = -ret; goto error; @@ -4562,8 +4678,17 @@ static void *thread_manage_clients(void *data) if (ret > 0 || (ret < 0 && errno != EINTR)) { goto exit; } - cmm_smp_rmb(); } + /* + * This barrier is paired with the one in sessiond_notify_ready() to + * ensure that loads accessing data initialized by the other threads, + * on which this thread was waiting, are not performed before this point. + * + * Note that this could be a 'read' memory barrier, but a full barrier + * is used in case the code changes. The performance implications of + * this choice are minimal since this is a slow path. + */ + cmm_smp_mb(); /* This testpoint is after we signal readiness to the parent. */ if (testpoint(sessiond_thread_manage_clients)) { @@ -4577,6 +4702,8 @@ static void *thread_manage_clients(void *data) health_code_update(); while (1) { + const struct cmd_completion_handler *cmd_completion_handler; + DBG("Accepting client command ..."); /* Inifinite blocking call, waiting for transmission */ @@ -4719,6 +4846,18 @@ static void *thread_manage_clients(void *data) continue; } + cmd_completion_handler = cmd_pop_completion_handler(); + if (cmd_completion_handler) { + enum lttng_error_code completion_code; + + completion_code = cmd_completion_handler->run( + cmd_completion_handler->data); + if (completion_code != LTTNG_OK) { + clean_command_ctx(&cmd_ctx); + continue; + } + } + health_code_update(); DBG("Sending response (size: %d, retcode: %s (%d))", @@ -5809,6 +5948,12 @@ int main(int argc, char **argv) goto exit_set_signal_handler; } + /* + * Init config from environment variables. + * Command line option override env configuration per-doc. Do env first. + */ + sessiond_config_apply_env_config(&config); + /* * Parse arguments and load the daemon configuration file. * @@ -5823,9 +5968,6 @@ int main(int argc, char **argv) goto exit_options; } - /* Init config from environment variables. */ - sessiond_config_apply_env_config(&config); - /* * Resolve all paths received as arguments, configuration option, or * through environment variable as absolute paths. This is necessary