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,
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,
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. */
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);
#include <lttng/condition/session-consumed-size-internal.h>
#include <lttng/condition/session-rotation-internal.h>
#include <lttng/condition/event-rule-internal.h>
+#include <lttng/domain-internal.h>
#include <lttng/notification/channel-internal.h>
#include <lttng/trigger/trigger-internal.h>
#include <lttng/event-rule/event-rule-internal.h>
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,
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;
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);
} else {
handle->channel_monitoring_pipes.kernel_consumer = -1;
}
+
end:
return handle;
error:
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);
}
goto error;
}
+ CDS_INIT_LIST_HEAD(&state->tracer_event_sources_list);
+
state->executor = action_executor_create(handle);
if (!state->executor) {
goto error;
#include <common/hashtable/hashtable.h>
#include <common/pipe.h>
#include <lttng/trigger/trigger.h>
+#include <lttng/domain.h>
#include <pthread.h>
#include <semaphore.h>
#include <urcu.h>
#include <urcu/list.h>
#include <urcu/rculfhash.h>
-
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.
* 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
*
* 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.
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;
};