#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 !!lttng_trigger_is_equal(trigger_key, trigger_ht_element->trigger);
}
+static
+int match_trigger_token(struct cds_lfht_node *node, const void *key)
+{
+ const uint64_t *_key = key;
+ struct notification_trigger_tokens_ht_element *element;
+
+ element = caa_container_of(node,
+ struct notification_trigger_tokens_ht_element, node);
+ return *_key == element->token;
+}
+
static
int match_client_list_condition(struct cds_lfht_node *node, const void *key)
{
&evaluation, &object_uid, &object_gid);
break;
case LTTNG_OBJECT_TYPE_NONE:
+ DBG("[notification-thread] Newly subscribed-to condition not bound to object, nothing to evaluate");
ret = 0;
goto end;
case LTTNG_OBJECT_TYPE_UNKNOWN:
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;
+ }
+
+ 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;
+ bool found = false;
+ 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);
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ /*
+ * This is temporarily allowed since the poll activity set is
+ * not properly cleaned-up for the moment. This is adressed in
+ * an upcoming fix.
+ */
+ source_element = NULL;
+ goto end;
+ }
+
+ 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;
+ }
+
+ source_element->is_fd_in_poll_set = false;
+
+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,
struct notification_client_list *client_list = NULL;
struct lttng_trigger_ht_element *trigger_ht_element = NULL;
struct notification_client_list_element *client_list_element;
+ struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element = NULL;
struct cds_lfht_node *node;
struct cds_lfht_iter iter;
const char* trigger_name;
goto error_free_ht_element;
}
+ if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+ trigger_tokens_ht_element = zmalloc(sizeof(*trigger_tokens_ht_element));
+ if (!trigger_tokens_ht_element) {
+ /* Fatal error. */
+ ret = -1;
+ cds_lfht_del(state->triggers_ht,
+ &trigger_ht_element->node);
+ cds_lfht_del(state->triggers_by_name_uid_ht,
+ &trigger_ht_element->node_by_name_uid);
+ goto error_free_ht_element;
+ }
+
+ /* Add trigger token to the trigger_tokens_ht. */
+ cds_lfht_node_init(&trigger_tokens_ht_element->node);
+ trigger_tokens_ht_element->token =
+ LTTNG_OPTIONAL_GET(trigger->tracer_token);
+ trigger_tokens_ht_element->trigger = trigger;
+
+ node = cds_lfht_add_unique(state->trigger_tokens_ht,
+ hash_key_u64(&trigger_tokens_ht_element->token,
+ lttng_ht_seed),
+ match_trigger_token,
+ &trigger_tokens_ht_element->token,
+ &trigger_tokens_ht_element->node);
+ if (node != &trigger_tokens_ht_element->node) {
+ /* Internal corruption, fatal error. */
+ ret = -1;
+ *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+ cds_lfht_del(state->triggers_ht,
+ &trigger_ht_element->node);
+ cds_lfht_del(state->triggers_by_name_uid_ht,
+ &trigger_ht_element->node_by_name_uid);
+ goto error_free_ht_element;
+ }
+ }
+
/*
* Ownership of the trigger and of its wrapper was transfered to
- * the triggers_ht.
+ * the triggers_ht. Same for token ht element if necessary.
*/
+ trigger_tokens_ht_element = NULL;
trigger_ht_element = NULL;
free_trigger = false;
free_lttng_trigger_ht_element_rcu);
}
+ free(trigger_tokens_ht_element);
error:
if (free_trigger) {
lttng_trigger_destroy(trigger);
rcu_node));
}
+static
+void free_notification_trigger_tokens_ht_element_rcu(struct rcu_head *node)
+{
+ free(caa_container_of(node, struct notification_trigger_tokens_ht_element,
+ rcu_node));
+}
+
static
int handle_notification_thread_command_unregister_trigger(
struct notification_thread_state *state,
- struct lttng_trigger *trigger,
+ const struct lttng_trigger *trigger,
enum lttng_error_code *_cmd_reply)
{
struct cds_lfht_iter iter;
struct lttng_channel_trigger_list *trigger_list;
struct notification_client_list *client_list;
struct lttng_trigger_ht_element *trigger_ht_element = NULL;
- struct lttng_condition *condition = lttng_trigger_get_condition(
+ const struct lttng_condition *condition = lttng_trigger_get_const_condition(
trigger);
enum lttng_error_code cmd_reply;
}
}
+ if (lttng_condition_get_type(condition) ==
+ LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+ struct notification_trigger_tokens_ht_element
+ *trigger_tokens_ht_element;
+
+ cds_lfht_for_each_entry (state->trigger_tokens_ht, &iter,
+ trigger_tokens_ht_element, node) {
+ if (!lttng_trigger_is_equal(trigger,
+ trigger_tokens_ht_element->trigger)) {
+ continue;
+ }
+
+ DBG("[notification-thread] Removed trigger from tokens_ht");
+ cds_lfht_del(state->trigger_tokens_ht,
+ &trigger_tokens_ht_element->node);
+ call_rcu(&trigger_tokens_ht_element->rcu_node,
+ free_notification_trigger_tokens_ht_element_rcu);
+
+ break;
+ }
+ }
+
if (is_trigger_action_notify(trigger)) {
/*
* Remove and release the client list from
switch (cmd->type) {
case NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER:
DBG("[notification-thread] Received register trigger command");
- ret = handle_notification_thread_command_register_trigger(
- state, cmd->parameters.trigger,
+ ret = handle_notification_thread_command_register_trigger(state,
+ cmd->parameters.register_trigger.trigger,
&cmd->reply_code);
break;
case NOTIFICATION_COMMAND_TYPE_UNREGISTER_TRIGGER:
DBG("[notification-thread] Received unregister trigger command");
ret = handle_notification_thread_command_unregister_trigger(
- state, cmd->parameters.trigger,
+ state,
+ cmd->parameters.unregister_trigger.trigger,
&cmd->reply_code);
break;
case NOTIFICATION_COMMAND_TYPE_ADD_CHANNEL:
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;