trigger: implement trigger naming
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Mon, 23 Mar 2020 22:27:59 +0000 (18:27 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 11 Nov 2020 23:16:52 +0000 (18:16 -0500)
A trigger can now have an optional name on the client side.

If no name is provided the sessiond will generate a name and return a
trigger object to populate the client side object.

For now, the name generation code generate the following pattern: TN

Where `N` is incremented each time a name has to be generated. If a
collision occurs, we increment `N` as needed.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I5f303610713c049177e53937bfc9824cd61501e4

include/lttng/trigger/trigger-internal.h
include/lttng/trigger/trigger.h
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/notification-thread-commands.c
src/bin/lttng-sessiond/notification-thread-events.c
src/bin/lttng-sessiond/notification-thread.c
src/bin/lttng-sessiond/notification-thread.h
src/common/trigger.c
src/lib/lttng-ctl/lttng-ctl.c

index 6d05b6d1d3ed38b2f789e30f731d6ec6d6a18276..20b1ff33aab687b499c8e92f68ef4a2e929e9934 100644 (file)
@@ -26,19 +26,25 @@ struct lttng_trigger {
 
        struct lttng_condition *condition;
        struct lttng_action *action;
 
        struct lttng_condition *condition;
        struct lttng_action *action;
+       char *name;
        /* For now only the uid portion of the credentials is used. */
        struct lttng_credentials creds;
 };
 
 struct lttng_trigger_comm {
        /* For now only the uid portion of the credentials is used. */
        struct lttng_credentials creds;
 };
 
 struct lttng_trigger_comm {
-       /* length excludes its own length. */
-       uint32_t length;
        /*
         * Credentials, only the uid portion is used for now.
         * Used as an override when desired by the root user.
         */
        uint64_t uid;
        /*
         * Credentials, only the uid portion is used for now.
         * Used as an override when desired by the root user.
         */
        uint64_t uid;
-       /* A condition and action object follow. */
+       /*
+        * Length of the variable length payload (name, condition, and
+        * an action).
+        */
+       uint32_t length;
+       /* Includes '\0' terminator. */
+       uint32_t name_length;
+       /* A null-terminated name, a condition, and an action follow. */
        char payload[];
 } LTTNG_PACKED;
 
        char payload[];
 } LTTNG_PACKED;
 
@@ -61,6 +67,14 @@ const struct lttng_action *lttng_trigger_get_const_action(
 LTTNG_HIDDEN
 bool lttng_trigger_validate(struct lttng_trigger *trigger);
 
 LTTNG_HIDDEN
 bool lttng_trigger_validate(struct lttng_trigger *trigger);
 
+LTTNG_HIDDEN
+int lttng_trigger_assign_name(
+               struct lttng_trigger *dst, const struct lttng_trigger *src);
+
+LTTNG_HIDDEN
+int lttng_trigger_generate_name(struct lttng_trigger *trigger,
+               uint64_t unique_id);
+
 LTTNG_HIDDEN
 bool lttng_trigger_is_equal(
                const struct lttng_trigger *a, const struct lttng_trigger *b);
 LTTNG_HIDDEN
 bool lttng_trigger_is_equal(
                const struct lttng_trigger *a, const struct lttng_trigger *b);
index e92897fd541e79accfeac412393dd780e1014a4d..96e018f248d536eecc6c08e3c0d06f2f5a212dbc 100644 (file)
@@ -96,6 +96,35 @@ extern struct lttng_condition *lttng_trigger_get_condition(
 extern struct lttng_action *lttng_trigger_get_action(
                struct lttng_trigger *trigger);
 
 extern struct lttng_action *lttng_trigger_get_action(
                struct lttng_trigger *trigger);
 
+
+/*
+ * Get the name of a trigger.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the trigger's
+ * lifetime, or until a different name is set.
+ *
+ * Returns LTTNG_TRIGGER_STATUS_OK and a pointer to the trigger's name on
+ * success, LTTNG_TRIGGER_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_TRIGGER_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_trigger_status lttng_trigger_get_name(
+               const struct lttng_trigger *trigger, const char **name);
+
+/*
+ * Set the trigger name.
+ *
+ * A name is optional.
+ * A name will be assigned on trigger registration if no name is set.
+ *
+ * The name is copied.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success, LTTNG_TRIGGER_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_set_name(
+               struct lttng_trigger *trigger, const char *name);
+
 /*
  * Destroy (frees) a trigger object.
  */
 /*
  * Destroy (frees) a trigger object.
  */
index d7db03fa76981f38ac60b3eb9e78579c9512fa4b..04846abf57f0ffcea7d119898197163ac998774e 100644 (file)
@@ -2033,8 +2033,41 @@ error_add_context:
        }
        case LTTNG_REGISTER_TRIGGER:
        {
        }
        case LTTNG_REGISTER_TRIGGER:
        {
+               struct lttng_trigger *return_trigger;
+               size_t original_payload_size;
+               size_t payload_size;
+
+               ret = setup_empty_lttng_msg(cmd_ctx);
+               if (ret) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto setup_error;
+               }
+
+               original_payload_size = cmd_ctx->reply_payload.buffer.size;
+
                ret = cmd_register_trigger(cmd_ctx, *sock,
                ret = cmd_register_trigger(cmd_ctx, *sock,
-                               notification_thread_handle);
+                               notification_thread_handle, &return_trigger);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               ret = lttng_trigger_serialize(return_trigger, &cmd_ctx->reply_payload);
+               if (ret) {
+                       ERR("Failed to serialize trigger in reply to \"register trigger\" command");
+                       ret = LTTNG_ERR_NOMEM;
+                       lttng_trigger_destroy(return_trigger);
+                       goto error;
+               }
+
+               lttng_trigger_destroy(return_trigger);
+               return_trigger = NULL;
+
+               payload_size = cmd_ctx->reply_payload.buffer.size -
+                       original_payload_size;
+
+               update_lttng_msg(cmd_ctx, 0, payload_size);
+
+               ret = LTTNG_OK;
                break;
        }
        case LTTNG_UNREGISTER_TRIGGER:
                break;
        }
        case LTTNG_UNREGISTER_TRIGGER:
index d8d17b59cba2b07956ff7e08bf13c685dfca37da..86a162baf1f6ddfcefdaf729a286eec7ff8d20e1 100644 (file)
@@ -4257,7 +4257,8 @@ end:
 }
 
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
 }
 
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
-               struct notification_thread_handle *notification_thread)
+               struct notification_thread_handle *notification_thread,
+               struct lttng_trigger **return_trigger)
 {
        int ret;
        size_t trigger_len;
 {
        int ret;
        size_t trigger_len;
@@ -4314,7 +4315,6 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
                }
        }
 
                }
        }
 
-
        /*
         * Validate the trigger credentials against the command credentials.
         * Only the root user can register a trigger with non-matching
        /*
         * Validate the trigger credentials against the command credentials.
         * Only the root user can register a trigger with non-matching
@@ -4330,9 +4330,26 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
                }
        }
 
                }
        }
 
-       /* Inform the notification thread */
+       /*
+        * A reference to the trigger is acquired by the notification thread.
+        * It is safe to return the same trigger to the caller since it the
+        * other user holds a reference.
+        *
+        * The trigger is modified during the execution of the
+        * "register trigger" command. However, by the time the command returns,
+        * it is safe to use without any locking as its properties are
+        * immutable.
+        */
        ret = notification_thread_command_register_trigger(notification_thread,
                        trigger);
        ret = notification_thread_command_register_trigger(notification_thread,
                        trigger);
+       if (ret != LTTNG_OK) {
+               goto end_notification_thread;
+       }
+
+       /* Return an updated trigger to the client. */
+       *return_trigger = trigger;
+
+end_notification_thread:
        /* Ownership of trigger was transferred. */
        trigger = NULL;
 end:
        /* Ownership of trigger was transferred. */
        trigger = NULL;
 end:
index 76c53ea333da17c0fd09de321f435476183728c4..eebb5a317c78038e52692f00362faff89a93515b 100644 (file)
@@ -142,7 +142,8 @@ int cmd_regenerate_metadata(struct ltt_session *session);
 int cmd_regenerate_statedump(struct ltt_session *session);
 
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
 int cmd_regenerate_statedump(struct ltt_session *session);
 
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
-               struct notification_thread_handle *notification_thread_handle);
+               struct notification_thread_handle *notification_thread_handle,
+               struct lttng_trigger **return_trigger);
 int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                struct notification_thread_handle *notification_thread_handle);
 
 int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                struct notification_thread_handle *notification_thread_handle);
 
index dc03e6a2df2fd9e7eab8634b5ece6ebb557c91de..28ed0b339d16c07e9d65763ff572a39a6e830945 100644 (file)
@@ -117,9 +117,11 @@ enum lttng_error_code notification_thread_command_register_trigger(
        enum lttng_error_code ret_code;
        struct notification_thread_command cmd = {};
 
        enum lttng_error_code ret_code;
        struct notification_thread_command cmd = {};
 
+       assert(trigger);
        init_notification_thread_command(&cmd);
 
        cmd.type = NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER;
        init_notification_thread_command(&cmd);
 
        cmd.type = NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER;
+       lttng_trigger_get(trigger);
        cmd.parameters.trigger = trigger;
 
        ret = run_command_wait(handle, &cmd);
        cmd.parameters.trigger = trigger;
 
        ret = run_command_wait(handle, &cmd);
index e52e4bd979cbe9108a599522a1eca74e848e541d..b47a79528c329026870ed9afe4815b72da2be3fe 100644 (file)
@@ -111,6 +111,7 @@ struct lttng_session_trigger_list {
 struct lttng_trigger_ht_element {
        struct lttng_trigger *trigger;
        struct cds_lfht_node node;
 struct lttng_trigger_ht_element {
        struct lttng_trigger *trigger;
        struct cds_lfht_node node;
+       struct cds_lfht_node node_by_name_uid;
        /* call_rcu delayed reclaim. */
        struct rcu_head rcu_node;
 };
        /* call_rcu delayed reclaim. */
        struct rcu_head rcu_node;
 };
@@ -188,6 +189,9 @@ int client_handle_transmission_status(
                enum client_transmission_status transmission_status,
                struct notification_thread_state *state);
 
                enum client_transmission_status transmission_status,
                struct notification_thread_state *state);
 
+static
+void free_lttng_trigger_ht_element_rcu(struct rcu_head *node);
+
 static
 int match_client_socket(struct cds_lfht_node *node, const void *key)
 {
 static
 int match_client_socket(struct cds_lfht_node *node, const void *key)
 {
@@ -262,18 +266,15 @@ int match_channel_info(struct cds_lfht_node *node, const void *key)
 }
 
 static
 }
 
 static
-int match_condition(struct cds_lfht_node *node, const void *key)
+int match_trigger(struct cds_lfht_node *node, const void *key)
 {
 {
-       struct lttng_condition *condition_key = (struct lttng_condition *) key;
-       struct lttng_trigger_ht_element *trigger;
-       struct lttng_condition *condition;
+       struct lttng_trigger *trigger_key = (struct lttng_trigger *) key;
+       struct lttng_trigger_ht_element *trigger_ht_element;
 
 
-       trigger = caa_container_of(node, struct lttng_trigger_ht_element,
+       trigger_ht_element = caa_container_of(node, struct lttng_trigger_ht_element,
                        node);
                        node);
-       condition = lttng_trigger_get_condition(trigger->trigger);
-       assert(condition);
 
 
-       return !!lttng_condition_is_equal(condition_key, condition);
+       return !!lttng_trigger_is_equal(trigger_key, trigger_ht_element->trigger);
 }
 
 static
 }
 
 static
@@ -302,6 +303,71 @@ int match_session(struct cds_lfht_node *node, const void *key)
        return !strcmp(session_info->name, name);
 }
 
        return !strcmp(session_info->name, name);
 }
 
+/*
+ * Match trigger based on name and credentials only.
+ * Name duplication is NOT allowed for the same uid.
+ */
+static
+int match_trigger_by_name_uid(struct cds_lfht_node *node,
+               const void *key)
+{
+       bool match = false;
+       const char *name;
+       const char *key_name;
+       enum lttng_trigger_status status;
+       const struct lttng_credentials *key_creds;
+       const struct lttng_credentials *node_creds;
+       const struct lttng_trigger *trigger_key =
+                       (const struct lttng_trigger *) key;
+       const struct lttng_trigger_ht_element *trigger_ht_element =
+                       caa_container_of(node,
+                               struct lttng_trigger_ht_element,
+                               node_by_name_uid);
+
+       status = lttng_trigger_get_name(trigger_ht_element->trigger, &name);
+       assert(status == LTTNG_TRIGGER_STATUS_OK);
+
+       status = lttng_trigger_get_name(trigger_key, &key_name);
+       assert(status == LTTNG_TRIGGER_STATUS_OK);
+
+       /* Compare the names. */
+       if (strcmp(name, key_name) != 0) {
+               goto end;
+       }
+
+       /* Compare the owners' UIDs. */
+       key_creds = lttng_trigger_get_credentials(trigger_key);
+       node_creds = lttng_trigger_get_credentials(trigger_ht_element->trigger);
+
+       match = lttng_credentials_is_equal_uid(key_creds, node_creds);
+
+end:
+       return match;
+}
+
+/*
+ * Hash trigger based on name and credentials only.
+ */
+static
+unsigned long hash_trigger_by_name_uid(const struct lttng_trigger *trigger)
+{
+       unsigned long hash = 0;
+       const struct lttng_credentials *trigger_creds;
+       const char *trigger_name;
+       enum lttng_trigger_status status;
+
+       status = lttng_trigger_get_name(trigger, &trigger_name);
+       if (status == LTTNG_TRIGGER_STATUS_OK) {
+               hash = hash_key_str(trigger_name, lttng_ht_seed);
+       }
+
+       trigger_creds = lttng_trigger_get_credentials(trigger);
+       hash ^= hash_key_ulong((void *) (unsigned long) LTTNG_OPTIONAL_GET(trigger_creds->uid),
+                       lttng_ht_seed);
+
+       return hash;
+}
+
 static
 unsigned long lttng_condition_buffer_usage_hash(
        const struct lttng_condition *_condition)
 static
 unsigned long lttng_condition_buffer_usage_hash(
        const struct lttng_condition *_condition)
@@ -2086,6 +2152,50 @@ end:
        return is_notify;
 }
 
        return is_notify;
 }
 
+static bool trigger_name_taken(struct notification_thread_state *state,
+               const struct lttng_trigger *trigger)
+{
+       struct cds_lfht_iter iter;
+
+       /*
+        * No duplicata is allowed in the triggers_by_name_uid_ht.
+        * The match is done against the trigger name and uid.
+        */
+       cds_lfht_lookup(state->triggers_by_name_uid_ht,
+                       hash_trigger_by_name_uid(trigger),
+                       match_trigger_by_name_uid,
+                       trigger,
+                       &iter);
+       return !!cds_lfht_iter_get_node(&iter);
+}
+
+static
+enum lttng_error_code generate_trigger_name(
+               struct notification_thread_state *state,
+               struct lttng_trigger *trigger, const char **name)
+{
+       enum lttng_error_code ret_code = LTTNG_OK;
+       bool taken = false;
+       enum lttng_trigger_status status;
+
+       do {
+               const int ret = lttng_trigger_generate_name(trigger,
+                               state->trigger_id.name_offset++);
+               if (ret) {
+                       /* The only reason this can fail right now. */
+                       ret_code = LTTNG_ERR_NOMEM;
+                       break;
+               }
+
+               status = lttng_trigger_get_name(trigger, name);
+               assert(status == LTTNG_TRIGGER_STATUS_OK);
+
+               taken = trigger_name_taken(state, trigger);
+       } while (taken || state->trigger_id.name_offset == UINT64_MAX);
+
+       return ret_code;
+}
+
 /*
  * FIXME A client's credentials are not checked when registering a trigger.
  *
 /*
  * FIXME A client's credentials are not checked when registering a trigger.
  *
@@ -2115,6 +2225,7 @@ int handle_notification_thread_command_register_trigger(
        struct notification_client_list_element *client_list_element;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
        struct notification_client_list_element *client_list_element;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
+       const char* trigger_name;
        bool free_trigger = true;
        struct lttng_evaluation *evaluation = NULL;
        struct lttng_credentials object_creds;
        bool free_trigger = true;
        struct lttng_evaluation *evaluation = NULL;
        struct lttng_credentials object_creds;
@@ -2124,6 +2235,24 @@ int handle_notification_thread_command_register_trigger(
 
        rcu_read_lock();
 
 
        rcu_read_lock();
 
+       if (lttng_trigger_get_name(trigger, &trigger_name) ==
+                       LTTNG_TRIGGER_STATUS_UNSET) {
+               const enum lttng_error_code ret_code = generate_trigger_name(
+                               state, trigger, &trigger_name);
+
+               if (ret_code != LTTNG_OK) {
+                       /* Fatal error. */
+                       ret = -1;
+                       *cmd_result = ret_code;
+                       goto error;
+               }
+       } else if (trigger_name_taken(state, trigger)) {
+               /* Not a fatal error. */
+               *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+               ret = 0;
+               goto error;
+       }
+
        condition = lttng_trigger_get_condition(trigger);
        assert(condition);
 
        condition = lttng_trigger_get_condition(trigger);
        assert(condition);
 
@@ -2146,12 +2275,13 @@ int handle_notification_thread_command_register_trigger(
 
        /* Add trigger to the trigger_ht. */
        cds_lfht_node_init(&trigger_ht_element->node);
 
        /* Add trigger to the trigger_ht. */
        cds_lfht_node_init(&trigger_ht_element->node);
+       cds_lfht_node_init(&trigger_ht_element->node_by_name_uid);
        trigger_ht_element->trigger = trigger;
 
        node = cds_lfht_add_unique(state->triggers_ht,
                        lttng_condition_hash(condition),
        trigger_ht_element->trigger = trigger;
 
        node = cds_lfht_add_unique(state->triggers_ht,
                        lttng_condition_hash(condition),
-                       match_condition,
-                       condition,
+                       match_trigger,
+                       trigger,
                        &trigger_ht_element->node);
        if (node != &trigger_ht_element->node) {
                /* Not a fatal error, simply report it to the client. */
                        &trigger_ht_element->node);
        if (node != &trigger_ht_element->node) {
                /* Not a fatal error, simply report it to the client. */
@@ -2159,6 +2289,18 @@ int handle_notification_thread_command_register_trigger(
                goto error_free_ht_element;
        }
 
                goto error_free_ht_element;
        }
 
+       node = cds_lfht_add_unique(state->triggers_by_name_uid_ht,
+                       hash_trigger_by_name_uid(trigger),
+                       match_trigger_by_name_uid,
+                       trigger,
+                       &trigger_ht_element->node_by_name_uid);
+       if (node != &trigger_ht_element->node_by_name_uid) {
+               /* Not a fatal error, simply report it to the client. */
+               cds_lfht_del(state->triggers_ht, &trigger_ht_element->node);
+               *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+               goto error_free_ht_element;
+       }
+
        /*
         * Ownership of the trigger and of its wrapper was transfered to
         * the triggers_ht.
        /*
         * Ownership of the trigger and of its wrapper was transfered to
         * the triggers_ht.
@@ -2273,11 +2415,11 @@ int handle_notification_thread_command_register_trigger(
                break;
        case LTTNG_OBJECT_TYPE_NONE:
                ret = 0;
                break;
        case LTTNG_OBJECT_TYPE_NONE:
                ret = 0;
-               goto error_put_client_list;
+               break;
        case LTTNG_OBJECT_TYPE_UNKNOWN:
        default:
                ret = -1;
        case LTTNG_OBJECT_TYPE_UNKNOWN:
        default:
                ret = -1;
-               goto error_put_client_list;
+               break;
        }
 
        if (ret) {
        }
 
        if (ret) {
@@ -2293,7 +2435,7 @@ int handle_notification_thread_command_register_trigger(
        if (!evaluation) {
                /* Evaluation yielded nothing. Normal exit. */
                ret = 0;
        if (!evaluation) {
                /* Evaluation yielded nothing. Normal exit. */
                ret = 0;
-               goto error_put_client_list;
+               goto end;
        }
 
        /*
        }
 
        /*
@@ -2324,18 +2466,24 @@ int handle_notification_thread_command_register_trigger(
                 */
                WARN("No space left when enqueuing action associated to newly registered trigger");
                ret = 0;
                 */
                WARN("No space left when enqueuing action associated to newly registered trigger");
                ret = 0;
-               goto error_put_client_list;
+               goto end;
        default:
                abort();
        }
 
        default:
                abort();
        }
 
+end:
        *cmd_result = LTTNG_OK;
 
 error_put_client_list:
        notification_client_list_put(client_list);
 
 error_free_ht_element:
        *cmd_result = LTTNG_OK;
 
 error_put_client_list:
        notification_client_list_put(client_list);
 
 error_free_ht_element:
-       free(trigger_ht_element);
+       if (trigger_ht_element) {
+               /* Delayed removal due to RCU constraint on delete. */
+               call_rcu(&trigger_ht_element->rcu_node,
+                               free_lttng_trigger_ht_element_rcu);
+       }
+
 error:
        if (free_trigger) {
                lttng_trigger_destroy(trigger);
 error:
        if (free_trigger) {
                lttng_trigger_destroy(trigger);
@@ -2370,8 +2518,8 @@ int handle_notification_thread_command_unregister_trigger(
 
        cds_lfht_lookup(state->triggers_ht,
                        lttng_condition_hash(condition),
 
        cds_lfht_lookup(state->triggers_ht,
                        lttng_condition_hash(condition),
-                       match_condition,
-                       condition,
+                       match_trigger,
+                       trigger,
                        &iter);
        triggers_ht_node = cds_lfht_iter_get_node(&iter);
        if (!triggers_ht_node) {
                        &iter);
        triggers_ht_node = cds_lfht_iter_get_node(&iter);
        if (!triggers_ht_node) {
@@ -2420,6 +2568,7 @@ int handle_notification_thread_command_unregister_trigger(
        /* Remove trigger from triggers_ht. */
        trigger_ht_element = caa_container_of(triggers_ht_node,
                        struct lttng_trigger_ht_element, node);
        /* Remove trigger from triggers_ht. */
        trigger_ht_element = caa_container_of(triggers_ht_node,
                        struct lttng_trigger_ht_element, node);
+       cds_lfht_del(state->triggers_by_name_uid_ht, &trigger_ht_element->node_by_name_uid);
        cds_lfht_del(state->triggers_ht, triggers_ht_node);
 
        /* Release the ownership of the trigger. */
        cds_lfht_del(state->triggers_ht, triggers_ht_node);
 
        /* Release the ownership of the trigger. */
index ba308bc831d7e26802f6995ae4fa433f89e1ced1..0c2d0d294628e2aea442498592ec1f379b15727a 100644 (file)
@@ -362,6 +362,10 @@ void fini_thread_state(struct notification_thread_state *state)
                ret = cds_lfht_destroy(state->sessions_ht, NULL);
                assert(!ret);
        }
                ret = cds_lfht_destroy(state->sessions_ht, NULL);
                assert(!ret);
        }
+       if (state->triggers_by_name_uid_ht) {
+               ret = cds_lfht_destroy(state->triggers_by_name_uid_ht, NULL);
+               assert(!ret);
+       }
        /*
         * Must be destroyed after all channels have been destroyed.
         * See comment in struct lttng_session_trigger_list.
        /*
         * Must be destroyed after all channels have been destroyed.
         * See comment in struct lttng_session_trigger_list.
@@ -475,6 +479,11 @@ int init_thread_state(struct notification_thread_handle *handle,
        if (!state->triggers_ht) {
                goto error;
        }
        if (!state->triggers_ht) {
                goto error;
        }
+       state->triggers_by_name_uid_ht = cds_lfht_new(DEFAULT_HT_SIZE,
+                       1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
+       if (!state->triggers_by_name_uid_ht) {
+               goto error;
+       }
 
        state->executor = action_executor_create(handle);
        if (!state->executor) {
 
        state->executor = action_executor_create(handle);
        if (!state->executor) {
index 134804f9d0718a76415e898f556e612921c95f9f..4e1ca4b8011fc3392394a09dc4f3f5303e07ee2c 100644 (file)
@@ -108,9 +108,14 @@ struct notification_thread_handle {
  *             channels through their struct channel_info (ref-counting is used).
  *
  *   - triggers_ht:
  *             channels through their struct channel_info (ref-counting is used).
  *
  *   - triggers_ht:
- *             associates a condition to a struct lttng_trigger_ht_element.
+ *             associates a trigger to a struct lttng_trigger_ht_element.
  *             The hash table holds the ownership of the
  *             lttng_trigger_ht_elements along with the triggers themselves.
  *             The hash table holds the ownership of the
  *             lttng_trigger_ht_elements along with the triggers themselves.
+ *   - triggers_by_name_uid_ht:
+ *             associates a trigger (name, uid) tuple to
+ *             a struct lttng_trigger_ht_element.
+ *             The hash table does not hold any ownership and is used strictly
+ *             for lookup on registration.
  *
  * The thread reacts to the following internal events:
  *   1) creation of a tracing channel,
  *
  * The thread reacts to the following internal events:
  *   1) creation of a tracing channel,
@@ -154,6 +159,7 @@ struct notification_thread_handle {
  *          notification_trigger_clients_ht,
  *    - add trigger to channel_triggers_ht (if applicable),
  *    - add trigger to session_triggers_ht (if applicable),
  *          notification_trigger_clients_ht,
  *    - add trigger to channel_triggers_ht (if applicable),
  *    - add trigger to session_triggers_ht (if applicable),
+ *    - add trigger to triggers_by_name_uid_ht
  *    - add trigger to triggers_ht
  *    - evaluate the trigger's condition right away to react if that condition
  *      is true from the beginning.
  *    - add trigger to triggers_ht
  *    - evaluate the trigger's condition right away to react if that condition
  *      is true from the beginning.
@@ -163,6 +169,7 @@ struct notification_thread_handle {
  *      - remove the trigger from the notification_trigger_clients_ht,
  *    - remove trigger from channel_triggers_ht (if applicable),
  *    - remove trigger from session_triggers_ht (if applicable),
  *      - remove the trigger from the notification_trigger_clients_ht,
  *    - remove trigger from channel_triggers_ht (if applicable),
  *    - remove trigger from session_triggers_ht (if applicable),
+ *    - remove trigger from triggers_by_name_uid_ht
  *    - remove trigger from triggers_ht
  *
  * 5) Reception of a channel monitor sample from the consumer daemon
  *    - remove trigger from triggers_ht
  *
  * 5) Reception of a channel monitor sample from the consumer daemon
@@ -210,6 +217,10 @@ struct notification_thread_state {
        struct cds_lfht *channels_ht;
        struct cds_lfht *sessions_ht;
        struct cds_lfht *triggers_ht;
        struct cds_lfht *channels_ht;
        struct cds_lfht *sessions_ht;
        struct cds_lfht *triggers_ht;
+       struct cds_lfht *triggers_by_name_uid_ht;
+       struct {
+               uint64_t name_offset;
+       } trigger_id;
        notification_client_id next_notification_client_id;
        struct action_executor *executor;
 };
        notification_client_id next_notification_client_id;
        struct action_executor *executor;
 };
index e6849fccfa52789a022de29b4344f2ead73fbffd..af0c5fa348166b833c61331f19f2cc2dba69567d 100644 (file)
@@ -14,6 +14,7 @@
 #include <common/error.h>
 #include <common/optional.h>
 #include <assert.h>
 #include <common/error.h>
 #include <common/optional.h>
 #include <assert.h>
+#include <inttypes.h>
 
 LTTNG_HIDDEN
 bool lttng_trigger_validate(struct lttng_trigger *trigger)
 
 LTTNG_HIDDEN
 bool lttng_trigger_validate(struct lttng_trigger *trigger)
@@ -115,6 +116,7 @@ static void trigger_destroy_ref(struct urcu_ref *ref)
        lttng_action_put(action);
        lttng_condition_put(condition);
 
        lttng_action_put(action);
        lttng_condition_put(condition);
 
+       free(trigger->name);
        free(trigger);
 }
 
        free(trigger);
 }
 
@@ -128,10 +130,11 @@ ssize_t lttng_trigger_create_from_payload(
                struct lttng_payload_view *src_view,
                struct lttng_trigger **trigger)
 {
                struct lttng_payload_view *src_view,
                struct lttng_trigger **trigger)
 {
-       ssize_t ret, offset = 0, condition_size, action_size;
+       ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
        struct lttng_condition *condition = NULL;
        struct lttng_action *action = NULL;
        const struct lttng_trigger_comm *trigger_comm;
        struct lttng_condition *condition = NULL;
        struct lttng_action *action = NULL;
        const struct lttng_trigger_comm *trigger_comm;
+       const char *name = NULL;
        struct lttng_credentials creds = {
                .uid = LTTNG_OPTIONAL_INIT_UNSET,
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
        struct lttng_credentials creds = {
                .uid = LTTNG_OPTIONAL_INIT_UNSET,
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
@@ -155,6 +158,24 @@ ssize_t lttng_trigger_create_from_payload(
        LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
 
        offset += sizeof(*trigger_comm);
        LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
 
        offset += sizeof(*trigger_comm);
+
+       if (trigger_comm->name_length != 0) {
+               /* Name. */
+               const struct lttng_payload_view name_view =
+                               lttng_payload_view_from_view(
+                                               src_view, offset, trigger_comm->name_length);
+
+               name = name_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
+                                   trigger_comm->name_length)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += trigger_comm->name_length;
+               name_size = trigger_comm->name_length;
+       }
+
        {
                /* struct lttng_condition */
                struct lttng_payload_view condition_view =
        {
                /* struct lttng_condition */
                struct lttng_payload_view condition_view =
@@ -187,7 +208,7 @@ ssize_t lttng_trigger_create_from_payload(
        offset += action_size;
 
        /* Unexpected size of inner-elements; the buffer is corrupted. */
        offset += action_size;
 
        /* Unexpected size of inner-elements; the buffer is corrupted. */
-       if ((ssize_t) trigger_comm->length != condition_size + action_size) {
+       if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
                ret = -1;
                goto error;
        }
                ret = -1;
                goto error;
        }
@@ -210,6 +231,16 @@ ssize_t lttng_trigger_create_from_payload(
        lttng_action_put(action);
        action = NULL;
 
        lttng_action_put(action);
        action = NULL;
 
+       if (name) {
+               const enum lttng_trigger_status status =
+                               lttng_trigger_set_name(*trigger, name);
+
+               if (status != LTTNG_TRIGGER_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        ret = offset;
 
 error:
        ret = offset;
 
 error:
@@ -228,7 +259,7 @@ int lttng_trigger_serialize(struct lttng_trigger *trigger,
                struct lttng_payload *payload)
 {
        int ret;
                struct lttng_payload *payload)
 {
        int ret;
-       size_t header_offset, size_before_payload;
+       size_t header_offset, size_before_payload, size_name;
        struct lttng_trigger_comm trigger_comm = {};
        struct lttng_trigger_comm *header;
        const struct lttng_credentials *creds = NULL;
        struct lttng_trigger_comm trigger_comm = {};
        struct lttng_trigger_comm *header;
        const struct lttng_credentials *creds = NULL;
@@ -238,6 +269,14 @@ int lttng_trigger_serialize(struct lttng_trigger *trigger,
 
        trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
 
 
        trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
 
+       if (trigger->name != NULL) {
+               size_name = strlen(trigger->name) + 1;
+       } else {
+               size_name = 0;
+       }
+
+       trigger_comm.name_length = size_name;
+
        header_offset = payload->buffer.size;
        ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
                        sizeof(trigger_comm));
        header_offset = payload->buffer.size;
        ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
                        sizeof(trigger_comm));
@@ -246,6 +285,14 @@ int lttng_trigger_serialize(struct lttng_trigger *trigger,
        }
 
        size_before_payload = payload->buffer.size;
        }
 
        size_before_payload = payload->buffer.size;
+
+       /* Trigger name. */
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, trigger->name, size_name);
+       if (ret) {
+               goto end;
+       }
+
        ret = lttng_condition_serialize(trigger->condition, payload);
        if (ret) {
                goto end;
        ret = lttng_condition_serialize(trigger->condition, payload);
        if (ret) {
                goto end;
@@ -286,6 +333,89 @@ bool lttng_trigger_is_equal(
        return true;
 }
 
        return true;
 }
 
+enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
+               const char* name)
+{
+       char *name_copy = NULL;
+       enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
+
+       if (!trigger || !name ||
+                       strlen(name) == 0) {
+               status = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_TRIGGER_STATUS_ERROR;
+               goto end;
+       }
+
+       free(trigger->name);
+
+       trigger->name = name_copy;
+       name_copy = NULL;
+end:
+       return status;
+}
+
+enum lttng_trigger_status lttng_trigger_get_name(
+               const struct lttng_trigger *trigger, const char **name)
+{
+       enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
+
+       if (!trigger || !name) {
+               status = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!trigger->name) {
+               status = LTTNG_TRIGGER_STATUS_UNSET;
+       }
+
+       *name = trigger->name;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+int lttng_trigger_assign_name(struct lttng_trigger *dst,
+               const struct lttng_trigger *src)
+{
+       int ret = 0;
+       enum lttng_trigger_status status;
+
+       status = lttng_trigger_set_name(dst, src->name);
+       if (status != LTTNG_TRIGGER_STATUS_OK) {
+               ret = -1;
+               ERR("Failed to set name for trigger");
+               goto end;
+       }
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_trigger_generate_name(struct lttng_trigger *trigger,
+               uint64_t unique_id)
+{
+       int ret = 0;
+       char *generated_name = NULL;
+
+       ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
+       if (ret < 0) {
+               ERR("Failed to generate trigger name");
+               ret = -1;
+               goto end;
+       }
+
+       ret = 0;
+       free(trigger->name);
+       trigger->name = generated_name;
+end:
+       return ret;
+}
+
 LTTNG_HIDDEN
 void lttng_trigger_get(struct lttng_trigger *trigger)
 {
 LTTNG_HIDDEN
 void lttng_trigger_get(struct lttng_trigger *trigger)
 {
index 60dcdc7d33872cbf190e79b1dfe9e3385f72e545..784597e20ef3188373dc898fe9a45976381ccbbf 100644 (file)
@@ -2956,11 +2956,13 @@ int lttng_register_trigger(struct lttng_trigger *trigger)
        struct lttcomm_session_msg *message_lsm;
        struct lttng_payload message;
        struct lttng_payload reply;
        struct lttcomm_session_msg *message_lsm;
        struct lttng_payload message;
        struct lttng_payload reply;
+       struct lttng_trigger *reply_trigger = NULL;
        const struct lttng_credentials user_creds = {
                .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
        };
 
        const struct lttng_credentials user_creds = {
                .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
        };
 
+
        lttng_payload_init(&message);
        lttng_payload_init(&reply);
 
        lttng_payload_init(&message);
        lttng_payload_init(&reply);
 
@@ -3032,10 +3034,30 @@ int lttng_register_trigger(struct lttng_trigger *trigger)
                }
        }
 
                }
        }
 
+       {
+               struct lttng_payload_view reply_view =
+                               lttng_payload_view_from_payload(
+                                               &reply, 0, reply.buffer.size);
+
+               ret = lttng_trigger_create_from_payload(
+                               &reply_view, &reply_trigger);
+               if (ret < 0) {
+                       ret = -LTTNG_ERR_FATAL;
+                       goto end;
+               }
+       }
+
+       ret = lttng_trigger_assign_name(trigger, reply_trigger);
+       if (ret < 0) {
+               ret = -LTTNG_ERR_FATAL;
+               goto end;
+       }
+
        ret = 0;
 end:
        lttng_payload_reset(&message);
        lttng_payload_reset(&reply);
        ret = 0;
 end:
        lttng_payload_reset(&message);
        lttng_payload_reset(&reply);
+       lttng_trigger_destroy(reply_trigger);
        return ret;
 }
 
        return ret;
 }
 
This page took 0.038199 seconds and 4 git commands to generate.