From: Jonathan Rajotte Date: Wed, 25 Mar 2020 22:49:32 +0000 (-0400) Subject: notification: add/remove tracer event source X-Git-Tag: v2.13.0-rc1~393 X-Git-Url: http://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=d02d7404fac685cd836b53e121afc64af71af140 notification: add/remove tracer event source The notification thread will be responsible of consuming the tracer notification event coming from the UST tracers and kernel tracer. On a 'add' operation, the tracer event source (i.e read side of a pipe) is added to the notification poll set. Book-keeping is also done via a list for later lookup. On 'remove', the event source is removed from the pollset and from the list. On cleanup (notification_thread_handle_destroy), it is expected that all added tracer event sources be removed by their respective "adder". No bulk cleanup is performed. Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: I23679922a58849c9bc86f30b2aae17b39fa2e222 --- diff --git a/src/bin/lttng-sessiond/notification-thread-commands.c b/src/bin/lttng-sessiond/notification-thread-commands.c index a434b08cf..7d47b7745 100644 --- a/src/bin/lttng-sessiond/notification-thread-commands.c +++ b/src/bin/lttng-sessiond/notification-thread-commands.c @@ -270,6 +270,60 @@ end: return ret_code; } +enum lttng_error_code notification_thread_command_add_tracer_event_source( + struct notification_thread_handle *handle, + int tracer_event_source_fd, + enum lttng_domain_type domain) +{ + int ret; + enum lttng_error_code ret_code; + struct notification_thread_command cmd = {}; + + assert(tracer_event_source_fd >= 0); + + init_notification_thread_command(&cmd); + + cmd.type = NOTIFICATION_COMMAND_TYPE_ADD_TRACER_EVENT_SOURCE; + cmd.parameters.tracer_event_source.tracer_event_source_fd = + tracer_event_source_fd; + cmd.parameters.tracer_event_source.domain = domain; + + ret = run_command_wait(handle, &cmd); + if (ret) { + ret_code = LTTNG_ERR_UNK; + goto end; + } + + ret_code = cmd.reply_code; +end: + return ret_code; +} + +enum lttng_error_code notification_thread_command_remove_tracer_event_source( + struct notification_thread_handle *handle, + int tracer_event_source_fd) +{ + int ret; + enum lttng_error_code ret_code; + struct notification_thread_command cmd = {}; + + init_notification_thread_command(&cmd); + + cmd.type = NOTIFICATION_COMMAND_TYPE_REMOVE_TRACER_EVENT_SOURCE; + cmd.parameters.tracer_event_source.tracer_event_source_fd = + tracer_event_source_fd; + + ret = run_command_wait(handle, &cmd); + if (ret) { + ret_code = LTTNG_ERR_UNK; + goto end; + } + + ret_code = cmd.reply_code; +end: + return ret_code; +} + enum lttng_error_code notification_thread_command_list_triggers( struct notification_thread_handle *handle, uid_t uid, diff --git a/src/bin/lttng-sessiond/notification-thread-commands.h b/src/bin/lttng-sessiond/notification-thread-commands.h index 3f883bf20..0f76ee5a6 100644 --- a/src/bin/lttng-sessiond/notification-thread-commands.h +++ b/src/bin/lttng-sessiond/notification-thread-commands.h @@ -27,6 +27,8 @@ enum notification_thread_command_type { NOTIFICATION_COMMAND_TYPE_REMOVE_CHANNEL, NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING, NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED, + NOTIFICATION_COMMAND_TYPE_ADD_TRACER_EVENT_SOURCE, + NOTIFICATION_COMMAND_TYPE_REMOVE_TRACER_EVENT_SOURCE, NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS, NOTIFICATION_COMMAND_TYPE_QUIT, NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE, @@ -65,6 +67,11 @@ struct notification_thread_command { uint64_t trace_archive_chunk_id; struct lttng_trace_archive_location *location; } session_rotation; + /* Add/Remove tracer event source fd. */ + struct { + int tracer_event_source_fd; + enum lttng_domain_type domain; + } tracer_event_source; /* List triggers. */ struct { /* Credentials of the requesting user. */ @@ -137,6 +144,19 @@ enum lttng_error_code notification_thread_command_list_triggers( uid_t client_uid, struct lttng_triggers **triggers); +/* + * The ownership of trigger_event_application_pipe is _not_ transferred to + * the notification thread. + */ +enum lttng_error_code notification_thread_command_add_tracer_event_source( + struct notification_thread_handle *handle, + int tracer_event_source_fd, + enum lttng_domain_type domain); + +enum lttng_error_code notification_thread_command_remove_tracer_event_source( + struct notification_thread_handle *handle, + int tracer_event_source_fd); + void notification_thread_command_quit( struct notification_thread_handle *handle); diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index bbf773291..9bf146d37 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1891,6 +1892,116 @@ end: return ret; } +static +int handle_notification_thread_command_add_tracer_event_source( + struct notification_thread_state *state, + int tracer_event_source_fd, + enum lttng_domain_type domain_type, + enum lttng_error_code *_cmd_result) +{ + int ret = 0; + enum lttng_error_code cmd_result = LTTNG_OK; + struct notification_event_tracer_event_source_element *element = NULL; + + element = zmalloc(sizeof(*element)); + if (!element) { + cmd_result = LTTNG_ERR_NOMEM; + ret = -1; + goto end; + } + + CDS_INIT_LIST_HEAD(&element->node); + element->fd = tracer_event_source_fd; + element->domain = domain_type; + + cds_list_add(&element->node, &state->tracer_event_sources_list); + + DBG3("[notification-thread] Adding tracer event source fd to poll set: tracer_event_source_fd = %d, domain = '%s'", + tracer_event_source_fd, + lttng_domain_type_str(domain_type)); + + /* Adding the read side pipe to the event poll. */ + ret = lttng_poll_add(&state->events, tracer_event_source_fd, LPOLLIN | LPOLLERR); + if (ret < 0) { + ERR("[notification-thread] Failed to add tracer event source to poll set: tracer_event_source_fd = %d, domain = '%s'", + tracer_event_source_fd, + lttng_domain_type_str(element->domain)); + cds_list_del(&element->node); + free(element); + goto end; + } + + element->is_fd_in_poll_set = true; + +end: + *_cmd_result = cmd_result; + return ret; +} + +static +int handle_notification_thread_command_remove_tracer_event_source( + struct notification_thread_state *state, + int tracer_event_source_fd, + enum lttng_error_code *_cmd_result) +{ + int ret = 0; + enum lttng_error_code cmd_result = LTTNG_OK; + struct notification_event_tracer_event_source_element *source_element = NULL, *tmp; + + cds_list_for_each_entry_safe(source_element, tmp, + &state->tracer_event_sources_list, node) { + if (source_element->fd != tracer_event_source_fd) { + continue; + } + + DBG("[notification-thread] Removed tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'", + tracer_event_source_fd, + lttng_domain_type_str(source_element->domain)); + cds_list_del(&source_element->node); + break; + } + + /* It should always be found. */ + assert(source_element); + + if (!source_element->is_fd_in_poll_set) { + /* Skip the poll set removal. */ + goto end; + } + + DBG3("[notification-thread] Removing tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'", + tracer_event_source_fd, + lttng_domain_type_str(source_element->domain)); + + /* Removing the fd from the event poll set. */ + ret = lttng_poll_del(&state->events, tracer_event_source_fd); + if (ret < 0) { + ERR("[notification-thread] Failed to remove tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'", + tracer_event_source_fd, + lttng_domain_type_str(source_element->domain)); + cmd_result = LTTNG_ERR_FATAL; + goto end; + } + +end: + free(source_element); + *_cmd_result = cmd_result; + return ret; +} + +int handle_notification_thread_remove_tracer_event_source_no_result( + struct notification_thread_state *state, + int tracer_event_source_fd) +{ + int ret; + enum lttng_error_code cmd_result; + + ret = handle_notification_thread_command_remove_tracer_event_source( + state, tracer_event_source_fd, &cmd_result); + (void) cmd_result; + return ret; +} + static int handle_notification_thread_command_list_triggers( struct notification_thread_handle *handle, struct notification_thread_state *state, @@ -2637,6 +2748,19 @@ int handle_notification_thread_command( cmd->parameters.session_rotation.location, &cmd->reply_code); break; + case NOTIFICATION_COMMAND_TYPE_ADD_TRACER_EVENT_SOURCE: + ret = handle_notification_thread_command_add_tracer_event_source( + state, + cmd->parameters.tracer_event_source.tracer_event_source_fd, + cmd->parameters.tracer_event_source.domain, + &cmd->reply_code); + break; + case NOTIFICATION_COMMAND_TYPE_REMOVE_TRACER_EVENT_SOURCE: + ret = handle_notification_thread_command_remove_tracer_event_source( + state, + cmd->parameters.tracer_event_source.tracer_event_source_fd, + &cmd->reply_code); + break; case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS: { struct lttng_triggers *triggers = NULL; diff --git a/src/bin/lttng-sessiond/notification-thread-events.h b/src/bin/lttng-sessiond/notification-thread-events.h index 2f699bf45..3602f8dca 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.h +++ b/src/bin/lttng-sessiond/notification-thread-events.h @@ -32,6 +32,10 @@ int handle_notification_thread_client_disconnect_all( int handle_notification_thread_trigger_unregister_all( struct notification_thread_state *state); +int handle_notification_thread_remove_tracer_event_source_no_result( + struct notification_thread_state *state, + int tracer_event_source_fd); + int handle_notification_thread_client_in( struct notification_thread_state *state, int socket); diff --git a/src/bin/lttng-sessiond/notification-thread.c b/src/bin/lttng-sessiond/notification-thread.c index 9b2cd5b96..917cec5a2 100644 --- a/src/bin/lttng-sessiond/notification-thread.c +++ b/src/bin/lttng-sessiond/notification-thread.c @@ -134,6 +134,7 @@ struct notification_thread_handle *notification_thread_handle_create( } else { handle->channel_monitoring_pipes.kernel_consumer = -1; } + end: return handle; error: @@ -378,6 +379,9 @@ void fini_thread_state(struct notification_thread_state *state) notification_channel_socket_destroy( state->notification_channel_socket); } + + assert(cds_list_empty(&state->tracer_event_sources_list)); + if (state->executor) { action_executor_destroy(state->executor); } @@ -486,6 +490,8 @@ int init_thread_state(struct notification_thread_handle *handle, goto error; } + CDS_INIT_LIST_HEAD(&state->tracer_event_sources_list); + state->executor = action_executor_create(handle); if (!state->executor) { goto error; diff --git a/src/bin/lttng-sessiond/notification-thread.h b/src/bin/lttng-sessiond/notification-thread.h index c80bb691d..bfce4cd3f 100644 --- a/src/bin/lttng-sessiond/notification-thread.h +++ b/src/bin/lttng-sessiond/notification-thread.h @@ -14,15 +14,39 @@ #include #include #include +#include #include #include #include #include #include - typedef uint64_t notification_client_id; +/* + * The notification thread holds no ownership of the tracer event source pipe + * file descriptor. The tracer management logic must remove the event source + * from the notification thread (see external commands) before releasing + * this file descriptor. + */ +struct notification_event_tracer_event_source_element { + int fd; + /* + * A tracer event source can be removed from the notification thread's + * poll set before the end of its lifetime (for instance, when an error + * or hang-up is detected on its file descriptor). This is done to + * allow the notification thread to ignore follow-up events on this + * file descriptors. + * + * Under such circumstances, the notification thread still expects + * the normal clean-up to occur through the 'REMOVE_TRACER_EVENT_SOURCE' + * command. + */ + bool is_fd_in_poll_set; + enum lttng_domain_type domain; + struct cds_list_head node; +}; + struct notification_thread_handle { /* * Queue of struct notification command. @@ -116,21 +140,27 @@ struct notification_thread_handle { * a struct lttng_trigger_ht_element. * The hash table does not hold any ownership and is used strictly * for lookup on registration. + * - tracer_event_sources_list: + * A list of tracer event source (read side fd) of type +* struct notification_event_tracer_event_source_element. +* * * The thread reacts to the following internal events: * 1) creation of a tracing channel, * 2) destruction of a tracing channel, * 3) registration of a trigger, * 4) unregistration of a trigger, - * 5) reception of a channel monitor sample from the consumer daemon. - * 6) Session rotation ongoing - * 7) Session rotation completed + * 5) reception of a channel monitor sample from the consumer daemon, + * 6) Session rotation ongoing, + * 7) Session rotation completed, + * 8) registration of a tracer event source, + * 9) unregistration of a tracer event source, * * Events specific to notification-emitting triggers: - * 8) connection of a notification client, - * 9) disconnection of a notification client, - * 10) subscription of a client to a conditions' notifications, - * 11) unsubscription of a client from a conditions' notifications, + * 9) connection of a notification client, + * 10) disconnection of a notification client, + * 11) subscription of a client to a conditions' notifications, + * 12) unsubscription of a client from a conditions' notifications, * * * 1) Creation of a tracing channel @@ -183,24 +213,34 @@ struct notification_thread_handle { * * 7) Session rotation completed * - * 8) Connection of a client + * 8) Registration of a tracer event source + * - Add the tracer event source of the application to + * tracer_event_sources_list, + * - Add the trace event source to the pollset. + * + * 8) Unregistration of a tracer event source + * - Remove the tracer event source of the application from + * tracer_event_sources_list, + * - Remove the trace event source from the pollset. + * + * 10) Connection of a client * - add client socket to the client_socket_ht, * - add client socket to the client_id_ht. * - * 9) Disconnection of a client + * 11) Disconnection of a client * - remove client socket from the client_id_ht, * - remove client socket from the client_socket_ht, * - traverse all conditions to which the client is subscribed and remove * the client from the notification_trigger_clients_ht. * - * 10) Subscription of a client to a condition's notifications + * 12) Subscription of a client to a condition's notifications * - Add the condition to the client's list of subscribed conditions, * - Look-up notification_trigger_clients_ht and add the client to * list of clients. * - Evaluate the condition for the client that subscribed if the trigger * was already registered. * - * 11) Unsubscription of a client to a condition's notifications + * 13) Unsubscription of a client to a condition's notifications * - Remove the condition from the client's list of subscribed conditions, * - Look-up notification_trigger_clients_ht and remove the client * from the list of clients. @@ -222,6 +262,17 @@ struct notification_thread_state { uint64_t next_tracer_token; uint64_t name_offset; } trigger_id; + /* + * Read side of the pipes used to receive tracer events. As their name + * implies, tracer event source activity originate from either + * registered applications (user space tracer) or from the kernel + * tracer. + * + * The list is not protected by a lock since add and remove operations + * are currently done only by the notification thread through in + * response to blocking commands. + */ + struct cds_list_head tracer_event_sources_list; notification_client_id next_notification_client_id; struct action_executor *executor; };