struct cds_list_head node;
};
-/*
- * Facilities to carry the different notifications type in the action processing
- * code path.
- */
-struct lttng_event_notifier_notification {
- union {
- struct lttng_ust_event_notifier_notification *ust;
- struct lttng_kernel_event_notifier_notification *kernel;
- } notification;
- uint64_t token;
- enum lttng_domain_type type;
-};
-
struct channel_state_sample {
struct channel_key key;
struct cds_lfht_node channel_state_ht_node;
enum client_transmission_status transmission_status,
struct notification_thread_state *state);
+static
+int handle_one_event_notifier_notification(
+ struct notification_thread_state *state,
+ int pipe, enum lttng_domain_type domain);
+
static
void free_lttng_trigger_ht_element_rcu(struct rcu_head *node);
return ret;
}
+static
+int drain_event_notifier_notification_pipe(
+ struct notification_thread_state *state,
+ int pipe, enum lttng_domain_type domain)
+{
+ struct lttng_poll_event events = {0};
+ int ret;
+
+ ret = lttng_poll_create(&events, 1, LTTNG_CLOEXEC);
+ if (ret < 0) {
+ ERR("[notification-thread] Error creating lttng_poll_event");
+ goto end;
+ }
+
+ ret = lttng_poll_add(&events, pipe, LPOLLIN);
+ if (ret < 0) {
+ ERR("[notification-thread] Error adding fd event notifier notification pipe to lttng_poll_event: fd = %d",
+ pipe);
+ goto end;
+ }
+
+ while (true) {
+ /*
+ * Continue to consume notifications as long as there are new
+ * ones coming in. The tracer has been asked to stop producing
+ * them.
+ *
+ * LPOLLIN is explicitly checked since LPOLLHUP is implicitly
+ * monitored (on Linux, at least) and will be returned when
+ * the pipe is closed but empty.
+ */
+ ret = lttng_poll_wait_interruptible(&events, 0);
+ if (ret == 0 || (LTTNG_POLL_GETEV(&events, 0) & LPOLLIN) == 0) {
+ /* No more notification to be read on this pipe. */
+ ret = 0;
+ goto end;
+ } else if (ret < 0) {
+ PERROR("Failed on lttng_poll_wait_interruptible() call");
+ ret = -1;
+ goto end;
+ }
+
+ ret = handle_one_event_notifier_notification(state, pipe, domain);
+ if (ret) {
+ ERR("[notification-thread] Error consuming an event notifier notification from pipe: fd = %d",
+ pipe);
+ }
+ }
+end:
+ lttng_poll_clean(&events);
+ return ret;
+}
+
static
int handle_notification_thread_command_remove_tracer_event_source(
struct notification_thread_state *state,
source_element->is_fd_in_poll_set = false;
+ ret = drain_event_notifier_notification_pipe(state, tracer_event_source_fd,
+ source_element->domain);
+ if (ret) {
+ ERR("[notification-thread] Error draining event notifier notification: 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;
+ }
+
+ /*
+ * The drain_event_notifier_notification_pipe() call might have read
+ * data from an fd that we received in event in the latest _poll_wait()
+ * call. Make sure the thread call poll_wait() again to ensure we have
+ * a clean state.
+ */
+ state->restart_poll = true;
+
end:
free(source_element);
*_cmd_result = cmd_result;
return ret;
}
-int handle_notification_thread_event_notification(struct notification_thread_state *state,
- int notification_pipe_read_fd,
- enum lttng_domain_type domain)
+static
+struct lttng_event_notifier_notification *recv_one_event_notifier_notification(
+ int notification_pipe_read_fd, enum lttng_domain_type domain)
{
int ret;
- struct lttng_ust_event_notifier_notification ust_notification;
- struct lttng_kernel_event_notifier_notification kernel_notification;
- struct lttng_evaluation *evaluation = NULL;
- struct cds_lfht_node *node;
- struct cds_lfht_iter iter;
- struct notification_trigger_tokens_ht_element *element;
- enum lttng_trigger_status status;
- struct lttng_event_notifier_notification notification;
+ uint64_t token;
+ struct lttng_event_notifier_notification *notification = NULL;
void *reception_buffer;
size_t reception_size;
- enum action_executor_status executor_status;
- struct notification_client_list *client_list = NULL;
- const char *trigger_name;
- notification.type = domain;
+ struct lttng_ust_event_notifier_notification ust_notification;
+ struct lttng_kernel_event_notifier_notification kernel_notification;
+ /* Init lttng_event_notifier_notification */
switch(domain) {
case LTTNG_DOMAIN_UST:
reception_buffer = (void *) &ust_notification;
reception_size = sizeof(ust_notification);
- notification.notification.ust = &ust_notification;
break;
case LTTNG_DOMAIN_KERNEL:
reception_buffer = (void *) &kernel_notification;
reception_size = sizeof(kernel_notification);
- notification.notification.kernel = &kernel_notification;
break;
default:
abort();
switch(domain) {
case LTTNG_DOMAIN_UST:
- notification.token = ust_notification.token;
+ token = ust_notification.token;
break;
case LTTNG_DOMAIN_KERNEL:
- notification.token = kernel_notification.token;
+ token = kernel_notification.token;
break;
default:
abort();
}
+ notification = lttng_event_notifier_notification_create(
+ token, domain);
+end:
+ return notification;
+}
+
+static
+int dispatch_one_event_notifier_notification(struct notification_thread_state *state,
+ struct lttng_event_notifier_notification *notification)
+{
+ struct cds_lfht_node *node;
+ struct cds_lfht_iter iter;
+ struct notification_trigger_tokens_ht_element *element;
+ enum lttng_trigger_status trigger_status;
+ struct lttng_evaluation *evaluation = NULL;
+ enum action_executor_status executor_status;
+ struct notification_client_list *client_list = NULL;
+ const char *trigger_name;
+ int ret;
+
/* Find triggers associated with this token. */
rcu_read_lock();
cds_lfht_lookup(state->trigger_tokens_ht,
- hash_key_u64(¬ification.token, lttng_ht_seed),
- match_trigger_token, ¬ification.token, &iter);
+ hash_key_u64(¬ification->tracer_token, lttng_ht_seed),
+ match_trigger_token, ¬ification->tracer_token, &iter);
node = cds_lfht_iter_get_node(&iter);
if (caa_unlikely(!node)) {
/*
lttng_trigger_fire(element->trigger);
- status = lttng_trigger_get_name(element->trigger, &trigger_name);
- assert(status == LTTNG_TRIGGER_STATUS_OK);
- evaluation = lttng_evaluation_event_rule_create(trigger_name);
+ trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name);
+ assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+ evaluation = lttng_evaluation_event_rule_create(
+ trigger_name);
if (evaluation == NULL) {
- ERR("Failed to create event rule evaluation while creating and enqueuing action executor job");
+ ERR("[notification-thread] Failed to create event rule hit evaluation while creating and enqueuing action executor job");
ret = -1;
goto end_unlock;
}
end_unlock:
notification_client_list_put(client_list);
rcu_read_unlock();
+ return ret;
+}
+
+static
+int handle_one_event_notifier_notification(
+ struct notification_thread_state *state,
+ int pipe, enum lttng_domain_type domain)
+{
+ int ret;
+ struct lttng_event_notifier_notification *notification = NULL;
+
+ notification = recv_one_event_notifier_notification(pipe, domain);
+ if (notification == NULL) {
+ ERR("[notification-thread] Error receiving an event notifier notification from tracer: fd = %i, domain = %s",
+ pipe, lttng_domain_type_str(domain));
+ ret = -1;
+ goto end;
+ }
+
+ ret = dispatch_one_event_notifier_notification(state, notification);
+ if (ret) {
+ ERR("[notification-thread] Error dispatching an event notifier notification from tracer: fd = %i, domain = %s",
+ pipe, lttng_domain_type_str(domain));
+ goto end;
+ }
+
end:
+ lttng_event_notifier_notification_destroy(notification);
return ret;
}
+int handle_notification_thread_event_notification(struct notification_thread_state *state,
+ int pipe, enum lttng_domain_type domain)
+{
+ return handle_one_event_notifier_notification(state, pipe, domain);
+}
+
int handle_notification_thread_channel_sample(
struct notification_thread_state *state, int pipe,
enum lttng_domain_type domain)