Bind newly registered triggers to session or channel objects
[lttng-tools.git] / src / bin / lttng-sessiond / notification-thread-events.c
index 9d006845fb93a362c5289065e8398fd3412bdaf1..4904a54575e512c1ed4297a98eed17e7abc95dea 100644 (file)
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/macros.h>
 #include <lttng/condition/condition.h>
-#include <lttng/action/action.h>
+#include <lttng/action/action-internal.h>
 #include <lttng/notification/notification-internal.h>
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
+#include <lttng/condition/session-rotation-internal.h>
 #include <lttng/notification/channel-internal.h>
 
 #include <time.h>
 #define CLIENT_POLL_MASK_IN (LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP)
 #define CLIENT_POLL_MASK_IN_OUT (CLIENT_POLL_MASK_IN | LPOLLOUT)
 
+enum lttng_object_type {
+       LTTNG_OBJECT_TYPE_UNKNOWN,
+       LTTNG_OBJECT_TYPE_NONE,
+       LTTNG_OBJECT_TYPE_CHANNEL,
+       LTTNG_OBJECT_TYPE_SESSION,
+};
+
 struct lttng_trigger_list_element {
-       struct lttng_trigger *trigger;
+       /* No ownership of the trigger object is assumed. */
+       const struct lttng_trigger *trigger;
        struct cds_list_head node;
 };
 
 struct lttng_channel_trigger_list {
        struct channel_key channel_key;
+       /* List of struct lttng_trigger_list_element. */
        struct cds_list_head list;
+       /* Node in the channel_triggers_ht */
        struct cds_lfht_node channel_triggers_ht_node;
 };
 
+/*
+ * List of triggers applying to a given session.
+ *
+ * See:
+ *   - lttng_session_trigger_list_create()
+ *   - lttng_session_trigger_list_build()
+ *   - lttng_session_trigger_list_destroy()
+ *   - lttng_session_trigger_list_add()
+ */
+struct lttng_session_trigger_list {
+       /*
+        * Not owned by this; points to the session_info structure's
+        * session name.
+        */
+       const char *session_name;
+       /* List of struct lttng_trigger_list_element. */
+       struct cds_list_head list;
+       /* Node in the session_triggers_ht */
+       struct cds_lfht_node session_triggers_ht_node;
+       /*
+        * Weak reference to the notification system's session triggers
+        * hashtable.
+        *
+        * The session trigger list structure structure is owned by
+        * the session's session_info.
+        *
+        * The session_info is kept alive the the channel_infos holding a
+        * reference to it (reference counting). When those channels are
+        * destroyed (at runtime or on teardown), the reference they hold
+        * to the session_info are released. On destruction of session_info,
+        * session_info_destroy() will remove the list of triggers applying
+        * to this session from the notification system's state.
+        *
+        * This implies that the session_triggers_ht must be destroyed
+        * after the channels.
+        */
+       struct cds_lfht *session_triggers_ht;
+       /* Used for delayed RCU reclaim. */
+       struct rcu_head rcu_node;
+};
+
 struct lttng_trigger_ht_element {
        struct lttng_trigger *trigger;
        struct cds_lfht_node node;
@@ -166,13 +218,14 @@ static int evaluate_condition(const struct lttng_condition *condition,
                uint64_t latest_session_consumed_total,
                struct channel_info *channel_info);
 static
-int send_evaluation_to_clients(struct lttng_trigger *trigger,
-               struct lttng_evaluation *evaluation,
+int send_evaluation_to_clients(const struct lttng_trigger *trigger,
+               const struct lttng_evaluation *evaluation,
                struct notification_client_list *client_list,
                struct notification_thread_state *state,
                uid_t channel_uid, gid_t channel_gid);
 
 
+/* session_info API */
 static
 void session_info_destroy(void *_data);
 static
@@ -181,7 +234,8 @@ static
 void session_info_put(struct session_info *session_info);
 static
 struct session_info *session_info_create(const char *name,
-               uid_t uid, gid_t gid);
+               uid_t uid, gid_t gid,
+               struct lttng_session_trigger_list *trigger_list);
 static
 void session_info_add_channel(struct session_info *session_info,
                struct channel_info *channel_info);
@@ -189,6 +243,23 @@ static
 void session_info_remove_channel(struct session_info *session_info,
                struct channel_info *channel_info);
 
+/* lttng_session_trigger_list API */
+static
+struct lttng_session_trigger_list *lttng_session_trigger_list_create(
+               const char *session_name,
+               struct cds_lfht *session_triggers_ht);
+static
+struct lttng_session_trigger_list *lttng_session_trigger_list_build(
+               const struct notification_thread_state *state,
+               const char *session_name);
+static
+void lttng_session_trigger_list_destroy(
+               struct lttng_session_trigger_list *list);
+static
+int lttng_session_trigger_list_add(struct lttng_session_trigger_list *list,
+               const struct lttng_trigger *trigger);
+
+
 static
 int match_client(struct cds_lfht_node *node, const void *key)
 {
@@ -215,6 +286,18 @@ int match_channel_trigger_list(struct cds_lfht_node *node, const void *key)
                        (channel_key->domain == trigger_list->channel_key.domain));
 }
 
+static
+int match_session_trigger_list(struct cds_lfht_node *node, const void *key)
+{
+       const char *session_name = (const char *) key;
+       struct lttng_session_trigger_list *trigger_list;
+
+       trigger_list = caa_container_of(node, struct lttng_session_trigger_list,
+                       session_triggers_ht_node);
+
+       return !!(strcmp(trigger_list->session_name, session_name) == 0);
+}
+
 static
 int match_channel_state_sample(struct cds_lfht_node *node, const void *key)
 {
@@ -292,14 +375,17 @@ int match_client_list_condition(struct cds_lfht_node *node, const void *key)
 
 static
 unsigned long lttng_condition_buffer_usage_hash(
-       struct lttng_condition *_condition)
+       const struct lttng_condition *_condition)
 {
-       unsigned long hash = 0;
+       unsigned long hash;
+       unsigned long condition_type;
        struct lttng_condition_buffer_usage *condition;
 
        condition = container_of(_condition,
                        struct lttng_condition_buffer_usage, parent);
 
+       condition_type = (unsigned long) condition->parent.type;
+       hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
        if (condition->session_name) {
                hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
        }
@@ -327,15 +413,18 @@ unsigned long lttng_condition_buffer_usage_hash(
 
 static
 unsigned long lttng_condition_session_consumed_size_hash(
-       struct lttng_condition *_condition)
+       const struct lttng_condition *_condition)
 {
-       unsigned long hash = 0;
+       unsigned long hash;
+       unsigned long condition_type =
+                       (unsigned long) LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE;
        struct lttng_condition_session_consumed_size *condition;
        uint64_t val;
 
        condition = container_of(_condition,
                        struct lttng_condition_session_consumed_size, parent);
 
+       hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
        if (condition->session_name) {
                hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
        }
@@ -344,13 +433,29 @@ unsigned long lttng_condition_session_consumed_size_hash(
        return hash;
 }
 
+static
+unsigned long lttng_condition_session_rotation_hash(
+       const struct lttng_condition *_condition)
+{
+       unsigned long hash, condition_type;
+       struct lttng_condition_session_rotation *condition;
+
+       condition = container_of(_condition,
+                       struct lttng_condition_session_rotation, parent);
+       condition_type = (unsigned long) condition->parent.type;
+       hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
+       assert(condition->session_name);
+       hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
+       return hash;
+}
+
 /*
  * The lttng_condition hashing code is kept in this file (rather than
  * condition.c) since it makes use of GPLv2 code (hashtable utils), which we
  * don't want to link in liblttng-ctl.
  */
 static
-unsigned long lttng_condition_hash(struct lttng_condition *condition)
+unsigned long lttng_condition_hash(const struct lttng_condition *condition)
 {
        switch (condition->type) {
        case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
@@ -358,6 +463,9 @@ unsigned long lttng_condition_hash(struct lttng_condition *condition)
                return lttng_condition_buffer_usage_hash(condition);
        case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
                return lttng_condition_session_consumed_size_hash(condition);
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               return lttng_condition_session_rotation_hash(condition);
        default:
                ERR("[notification-thread] Unexpected condition type caught");
                abort();
@@ -406,6 +514,7 @@ void session_info_destroy(void *_data)
                        ERR("[notification-thread] Failed to destroy channel information hash table");
                }
        }
+       lttng_session_trigger_list_destroy(session_info->trigger_list);
        free(session_info->name);
        free(session_info);
 }
@@ -429,7 +538,8 @@ void session_info_put(struct session_info *session_info)
 }
 
 static
-struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid)
+struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid,
+               struct lttng_session_trigger_list *trigger_list)
 {
        struct session_info *session_info;
 
@@ -454,6 +564,7 @@ struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid)
        }
        session_info->uid = uid;
        session_info->gid = gid;
+       session_info->trigger_list = trigger_list;
 end:
        return session_info;
 error:
@@ -547,8 +658,8 @@ int evaluate_condition_for_client(struct lttng_trigger *trigger,
                struct lttng_trigger_list_element *element;
 
                cds_list_for_each_entry(element, &channel_trigger_list->list, node) {
-                       struct lttng_condition *current_condition =
-                               lttng_trigger_get_condition(
+                       const struct lttng_condition *current_condition =
+                               lttng_trigger_get_const_condition(
                                                element->trigger);
 
                        assert(current_condition);
@@ -877,8 +988,8 @@ end:
 
 static
 bool buffer_usage_condition_applies_to_channel(
-               struct lttng_condition *condition,
-               struct channel_info *channel_info)
+               const struct lttng_condition *condition,
+               const struct channel_info *channel_info)
 {
        enum lttng_condition_status status;
        enum lttng_domain_type condition_domain;
@@ -914,8 +1025,8 @@ fail:
 
 static
 bool session_consumed_size_condition_applies_to_channel(
-               struct lttng_condition *condition,
-               struct channel_info *channel_info)
+               const struct lttng_condition *condition,
+               const struct channel_info *channel_info)
 {
        enum lttng_condition_status status;
        const char *condition_session_name = NULL;
@@ -933,14 +1044,42 @@ fail:
        return false;
 }
 
+/*
+ * Get the type of object to which a given trigger applies. Binding lets
+ * the notification system evaluate a trigger's condition when a given
+ * object's state is updated.
+ *
+ * For instance, a condition bound to a channel will be evaluated everytime
+ * the channel's state is changed by a channel monitoring sample.
+ */
 static
-bool trigger_applies_to_channel(struct lttng_trigger *trigger,
-               struct channel_info *channel_info)
+enum lttng_object_type get_trigger_binding_object(
+               const struct lttng_trigger *trigger)
 {
-       struct lttng_condition *condition;
+       const struct lttng_condition *condition;
+
+       condition = lttng_trigger_get_const_condition(trigger);
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+               return LTTNG_OBJECT_TYPE_CHANNEL;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               return LTTNG_OBJECT_TYPE_SESSION;
+       default:
+               return LTTNG_OBJECT_TYPE_UNKNOWN;
+       }
+}
+
+static
+bool trigger_applies_to_channel(const struct lttng_trigger *trigger,
+               const struct channel_info *channel_info)
+{
+       const struct lttng_condition *condition;
        bool trigger_applies;
 
-       condition = lttng_trigger_get_condition(trigger);
+       condition = lttng_trigger_get_const_condition(trigger);
        if (!condition) {
                goto fail;
        }
@@ -993,6 +1132,166 @@ int match_session(struct cds_lfht_node *node, const void *key)
        return !strcmp(session_info->name, name);
 }
 
+/*
+ * Allocate an empty lttng_session_trigger_list for the session named
+ * 'session_name'.
+ *
+ * No ownership of 'session_name' is assumed by the session trigger list.
+ * It is the caller's responsability to ensure the session name is alive
+ * for as long as this list is.
+ */
+static
+struct lttng_session_trigger_list *lttng_session_trigger_list_create(
+               const char *session_name,
+               struct cds_lfht *session_triggers_ht)
+{
+       struct lttng_session_trigger_list *list;
+
+       list = zmalloc(sizeof(*list));
+       if (!list) {
+               goto end;
+       }
+       list->session_name = session_name;
+       CDS_INIT_LIST_HEAD(&list->list);
+       cds_lfht_node_init(&list->session_triggers_ht_node);
+       list->session_triggers_ht = session_triggers_ht;
+
+       rcu_read_lock();
+       /* Publish the list through the session_triggers_ht. */
+       cds_lfht_add(session_triggers_ht,
+                       hash_key_str(session_name, lttng_ht_seed),
+                       &list->session_triggers_ht_node);
+       rcu_read_unlock();
+end:
+       return list;
+}
+
+static
+void free_session_trigger_list_rcu(struct rcu_head *node)
+{
+       free(caa_container_of(node, struct lttng_session_trigger_list,
+                       rcu_node));
+}
+
+static
+void lttng_session_trigger_list_destroy(struct lttng_session_trigger_list *list)
+{
+       struct lttng_trigger_list_element *trigger_list_element, *tmp;
+
+       /* Empty the list element by element, and then free the list itself. */
+       cds_list_for_each_entry_safe(trigger_list_element, tmp,
+                       &list->list, node) {
+               cds_list_del(&trigger_list_element->node);
+               free(trigger_list_element);
+       }
+       rcu_read_lock();
+       /* Unpublish the list from the session_triggers_ht. */
+       cds_lfht_del(list->session_triggers_ht,
+                       &list->session_triggers_ht_node);
+       rcu_read_unlock();
+       call_rcu(&list->rcu_node, free_session_trigger_list_rcu);
+}
+
+static
+int lttng_session_trigger_list_add(struct lttng_session_trigger_list *list,
+               const struct lttng_trigger *trigger)
+{
+       int ret = 0;
+       struct lttng_trigger_list_element *new_element =
+                       zmalloc(sizeof(*new_element));
+
+       if (!new_element) {
+               ret = -1;
+               goto end;
+       }
+       CDS_INIT_LIST_HEAD(&new_element->node);
+       new_element->trigger = trigger;
+       cds_list_add(&new_element->node, &list->list);
+end:
+       return ret;
+}
+
+static
+bool trigger_applies_to_session(const struct lttng_trigger *trigger,
+               const char *session_name)
+{
+       bool applies = false;
+       const struct lttng_condition *condition;
+
+       condition = lttng_trigger_get_const_condition(trigger);
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+       {
+               enum lttng_condition_status condition_status;
+               const char *condition_session_name;
+
+               condition_status = lttng_condition_session_rotation_get_session_name(
+                       condition, &condition_session_name);
+               if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                       ERR("[notification-thread] Failed to retrieve session rotation condition's session name");
+                       goto end;
+               }
+
+               assert(condition_session_name);
+               applies = !strcmp(condition_session_name, session_name);
+               break;
+       }
+       default:
+               goto end;
+       }
+end:
+       return applies;
+}
+
+/*
+ * Allocate and initialize an lttng_session_trigger_list which contains
+ * all triggers that apply to the session named 'session_name'.
+ *
+ * No ownership of 'session_name' is assumed by the session trigger list.
+ * It is the caller's responsability to ensure the session name is alive
+ * for as long as this list is.
+ */
+static
+struct lttng_session_trigger_list *lttng_session_trigger_list_build(
+               const struct notification_thread_state *state,
+               const char *session_name)
+{
+       int trigger_count = 0;
+       struct lttng_session_trigger_list *session_trigger_list = NULL;
+       struct lttng_trigger_ht_element *trigger_ht_element = NULL;
+       struct cds_lfht_iter iter;
+
+       session_trigger_list = lttng_session_trigger_list_create(session_name,
+                       state->session_triggers_ht);
+
+       /* Add all triggers applying to the session named 'session_name'. */
+       cds_lfht_for_each_entry(state->triggers_ht, &iter, trigger_ht_element,
+                       node) {
+               int ret;
+
+               if (!trigger_applies_to_session(trigger_ht_element->trigger,
+                               session_name)) {
+                       continue;
+               }
+
+               ret = lttng_session_trigger_list_add(session_trigger_list,
+                               trigger_ht_element->trigger);
+               if (ret) {
+                       goto error;
+               }
+
+               trigger_count++;
+       }
+
+       DBG("[notification-thread] Found %i triggers that apply to newly created session",
+                       trigger_count);
+       return session_trigger_list;
+error:
+       lttng_session_trigger_list_destroy(session_trigger_list);
+       return NULL;
+}
+
 static
 struct session_info *find_or_create_session_info(
                struct notification_thread_state *state,
@@ -1001,6 +1300,7 @@ struct session_info *find_or_create_session_info(
        struct session_info *session = NULL;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
+       struct lttng_session_trigger_list *trigger_list;
 
        rcu_read_lock();
        cds_lfht_lookup(state->sessions_ht,
@@ -1016,18 +1316,30 @@ struct session_info *find_or_create_session_info(
                                sessions_ht_node);
                assert(session->uid == uid);
                assert(session->gid == gid);
-               goto end;
+               goto error;
        }
 
-       session = session_info_create(name, uid, gid);
+       trigger_list = lttng_session_trigger_list_build(state, name);
+       if (!trigger_list) {
+               goto error;
+       }
+
+       session = session_info_create(name, uid, gid, trigger_list);
        if (!session) {
                ERR("[notification-thread] Failed to allocation session info for session \"%s\" (uid = %i, gid = %i)",
                                name, uid, gid);
-               goto end;
+               goto error;
        }
-end:
+       trigger_list = NULL;
+
+       cds_lfht_add(state->sessions_ht, hash_key_str(name, lttng_ht_seed),
+                       &session->sessions_ht_node);
        rcu_read_unlock();
        return session;
+error:
+       rcu_read_unlock();
+       session_info_put(session);
+       return NULL;
 }
 
 static
@@ -1242,13 +1554,118 @@ end:
        return ret;
 }
 
+/* Must be called with RCU read lock held. */
+static
+int bind_trigger_to_matching_session(const struct lttng_trigger *trigger,
+               struct notification_thread_state *state)
+{
+       int ret = 0;
+       struct cds_lfht_node *node;
+       struct cds_lfht_iter iter;
+       const struct lttng_condition *condition;
+       const char *session_name;
+       struct lttng_session_trigger_list *trigger_list;
+
+       condition = lttng_trigger_get_const_condition(trigger);
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+       {
+               enum lttng_condition_status status;
+
+               status = lttng_condition_session_rotation_get_session_name(
+                               condition, &session_name);
+               if (status != LTTNG_CONDITION_STATUS_OK) {
+                       ERR("[notification-thread] Failed to bind trigger to session: unable to get 'session_rotation' condition's session name");
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       }
+       default:
+               ret = -1;
+               goto end;
+       }
+
+       cds_lfht_lookup(state->session_triggers_ht,
+                       hash_key_str(session_name, lttng_ht_seed),
+                       match_session_trigger_list,
+                       session_name,
+                       &iter);
+       node = cds_lfht_iter_get_node(&iter);
+       if (!node) {
+               /*
+                * Not an error, the list of triggers applying to that session
+                * will be initialized when the session is created.
+                */
+               DBG("[notification-thread] Unable to bind trigger applying to session \"%s\" as it is not yet known to the notification system",
+                               session_name);
+               goto end;
+       }
+
+       trigger_list = caa_container_of(node,
+                       struct lttng_session_trigger_list,
+                       session_triggers_ht_node);
+
+       DBG("[notification-thread] Newly registered trigger bound to session \"%s\"",
+                       session_name);
+       ret = lttng_session_trigger_list_add(trigger_list, trigger);
+end:
+       return ret;
+}
+
+/* Must be called with RCU read lock held. */
+static
+int bind_trigger_to_matching_channels(const struct lttng_trigger *trigger,
+               struct notification_thread_state *state)
+{
+       int ret = 0;
+       struct cds_lfht_node *node;
+       struct cds_lfht_iter iter;
+       struct channel_info *channel;
+
+       cds_lfht_for_each_entry(state->channels_ht, &iter, channel,
+                       channels_ht_node) {
+               struct lttng_trigger_list_element *trigger_list_element;
+               struct lttng_channel_trigger_list *trigger_list;
+
+               if (!trigger_applies_to_channel(trigger, channel)) {
+                       continue;
+               }
+
+               cds_lfht_lookup(state->channel_triggers_ht,
+                               hash_channel_key(&channel->key),
+                               match_channel_trigger_list,
+                               &channel->key,
+                               &iter);
+               node = cds_lfht_iter_get_node(&iter);
+               assert(node);
+               trigger_list = caa_container_of(node,
+                               struct lttng_channel_trigger_list,
+                               channel_triggers_ht_node);
+
+               trigger_list_element = zmalloc(sizeof(*trigger_list_element));
+               if (!trigger_list_element) {
+                       ret = -1;
+                       goto end;
+               }
+               CDS_INIT_LIST_HEAD(&trigger_list_element->node);
+               trigger_list_element->trigger = trigger;
+               cds_list_add(&trigger_list_element->node, &trigger_list->list);
+               DBG("[notification-thread] Newly registered trigger bound to channel \"%s\"",
+                               channel->name);
+       }
+end:
+       return ret;
+}
+
 /*
  * FIXME A client's credentials are not checked when registering a trigger, nor
  *       are they stored alongside with the trigger.
  *
  * The effects of this are benign since:
  *     - The client will succeed in registering the trigger, as it is valid,
- *     - The trigger will, internally, be bound to the channel,
+ *     - The trigger will, internally, be bound to the channel/session,
  *     - The notifications will not be sent since the client's credentials
  *       are checked against the channel at that moment.
  *
@@ -1272,7 +1689,6 @@ int handle_notification_thread_command_register_trigger(
        struct notification_client_list_element *client_list_element, *tmp;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
-       struct channel_info *channel;
        bool free_trigger = true;
 
        rcu_read_lock();
@@ -1354,38 +1770,29 @@ int handle_notification_thread_command_register_trigger(
                        lttng_condition_hash(condition),
                        &client_list->notification_trigger_ht_node);
 
-       /*
-        * Add the trigger to list of triggers bound to the channels currently
-        * known.
-        */
-       cds_lfht_for_each_entry(state->channels_ht, &iter, channel,
-                       channels_ht_node) {
-               struct lttng_trigger_list_element *trigger_list_element;
-               struct lttng_channel_trigger_list *trigger_list;
-
-               if (!trigger_applies_to_channel(trigger, channel)) {
-                       continue;
+       switch (get_trigger_binding_object(trigger)) {
+       case LTTNG_OBJECT_TYPE_SESSION:
+               /* Add the trigger to the list if it matches a known session. */
+               ret = bind_trigger_to_matching_session(trigger, state);
+               if (ret) {
+                       goto error_free_client_list;
                }
-
-               cds_lfht_lookup(state->channel_triggers_ht,
-                               hash_channel_key(&channel->key),
-                               match_channel_trigger_list,
-                               &channel->key,
-                               &iter);
-               node = cds_lfht_iter_get_node(&iter);
-               assert(node);
-               trigger_list = caa_container_of(node,
-                               struct lttng_channel_trigger_list,
-                               channel_triggers_ht_node);
-
-               trigger_list_element = zmalloc(sizeof(*trigger_list_element));
-               if (!trigger_list_element) {
-                       ret = -1;
+       case LTTNG_OBJECT_TYPE_CHANNEL:
+               /*
+                * Add the trigger to list of triggers bound to the channels
+                * currently known.
+                */
+               ret = bind_trigger_to_matching_channels(trigger, state);
+               if (ret) {
                        goto error_free_client_list;
                }
-               CDS_INIT_LIST_HEAD(&trigger_list_element->node);
-               trigger_list_element->trigger = trigger;
-               cds_list_add(&trigger_list_element->node, &trigger_list->list);
+               break;
+       case LTTNG_OBJECT_TYPE_NONE:
+               break;
+       default:
+               ERR("[notification-thread] Unknown object type on which to bind a newly registered trigger was encountered");
+               ret = -1;
+               goto error_free_client_list;
        }
 
        /*
@@ -1491,8 +1898,8 @@ int handle_notification_thread_command_unregister_trigger(
 
                cds_list_for_each_entry_safe(trigger_element, tmp,
                                &trigger_list->list, node) {
-                       struct lttng_condition *current_condition =
-                                       lttng_trigger_get_condition(
+                       const struct lttng_condition *current_condition =
+                                       lttng_trigger_get_const_condition(
                                                trigger_element->trigger);
 
                        assert(current_condition);
@@ -2344,7 +2751,6 @@ int evaluate_condition(const struct lttng_condition *condition,
                break;
        case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
                *evaluation = lttng_evaluation_session_consumed_size_create(
-                               condition_type,
                                latest_session_consumed_total);
                break;
        default:
@@ -2376,8 +2782,8 @@ int client_enqueue_dropped_notification(struct notification_client *client,
 }
 
 static
-int send_evaluation_to_clients(struct lttng_trigger *trigger,
-               struct lttng_evaluation *evaluation,
+int send_evaluation_to_clients(const struct lttng_trigger *trigger,
+               const struct lttng_evaluation *evaluation,
                struct notification_client_list* client_list,
                struct notification_thread_state *state,
                uid_t channel_uid, gid_t channel_gid)
@@ -2385,51 +2791,33 @@ int send_evaluation_to_clients(struct lttng_trigger *trigger,
        int ret = 0;
        struct lttng_dynamic_buffer msg_buffer;
        struct notification_client_list_element *client_list_element, *tmp;
-       struct lttng_notification *notification;
-       struct lttng_condition *condition;
-       ssize_t expected_notification_size, notification_size;
-       struct lttng_notification_channel_message msg;
+       const struct lttng_notification notification = {
+               .condition = (struct lttng_condition *) lttng_trigger_get_const_condition(trigger),
+               .evaluation = (struct lttng_evaluation *) evaluation,
+       };
+       struct lttng_notification_channel_message msg_header = {
+               .type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION,
+       };
 
        lttng_dynamic_buffer_init(&msg_buffer);
 
-       condition = lttng_trigger_get_condition(trigger);
-       assert(condition);
-
-       notification = lttng_notification_create(condition, evaluation);
-       if (!notification) {
-               ret = -1;
-               goto end;
-       }
-
-       expected_notification_size = lttng_notification_serialize(notification,
-                       NULL);
-       if (expected_notification_size < 0) {
-               ERR("[notification-thread] Failed to get size of serialized notification");
-               ret = -1;
-               goto end;
-       }
-
-       msg.type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION;
-       msg.size = (uint32_t) expected_notification_size;
-       ret = lttng_dynamic_buffer_append(&msg_buffer, &msg, sizeof(msg));
+       ret = lttng_dynamic_buffer_append(&msg_buffer, &msg_header,
+                       sizeof(msg_header));
        if (ret) {
                goto end;
        }
 
-       ret = lttng_dynamic_buffer_set_size(&msg_buffer,
-                       msg_buffer.size + expected_notification_size);
+       ret = lttng_notification_serialize(&notification, &msg_buffer);
        if (ret) {
-               goto end;
-       }
-
-       notification_size = lttng_notification_serialize(notification,
-                       msg_buffer.data + sizeof(msg));
-       if (notification_size != expected_notification_size) {
                ERR("[notification-thread] Failed to serialize notification");
                ret = -1;
                goto end;
        }
 
+       /* Update payload size. */
+       ((struct lttng_notification_channel_message * ) msg_buffer.data)->size =
+                       (uint32_t) (msg_buffer.size - sizeof(msg_header));
+
        cds_list_for_each_entry_safe(client_list_element, tmp,
                        &client_list->list, node) {
                struct notification_client *client =
@@ -2479,7 +2867,6 @@ int send_evaluation_to_clients(struct lttng_trigger *trigger,
        }
        ret = 0;
 end:
-       lttng_notification_destroy(notification);
        lttng_dynamic_buffer_reset(&msg_buffer);
        return ret;
 }
@@ -2620,19 +3007,19 @@ int handle_notification_thread_channel_sample(
                        channel_triggers_ht_node);
        cds_list_for_each_entry(trigger_list_element, &trigger_list->list,
                        node) {
-               struct lttng_condition *condition;
-               struct lttng_action *action;
-               struct lttng_trigger *trigger;
+               const struct lttng_condition *condition;
+               const struct lttng_action *action;
+               const struct lttng_trigger *trigger;
                struct notification_client_list *client_list;
                struct lttng_evaluation *evaluation = NULL;
 
                trigger = trigger_list_element->trigger;
-               condition = lttng_trigger_get_condition(trigger);
+               condition = lttng_trigger_get_const_condition(trigger);
                assert(condition);
-               action = lttng_trigger_get_action(trigger);
+               action = lttng_trigger_get_const_action(trigger);
 
                /* Notify actions are the only type currently supported. */
-               assert(lttng_action_get_type(action) ==
+               assert(lttng_action_get_type_const(action) ==
                                LTTNG_ACTION_TYPE_NOTIFY);
 
                /*
This page took 0.033616 seconds and 4 git commands to generate.