From a02903c0743cebd1f51227905ee89e571b84acbc Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 21 Jan 2020 14:22:37 -0500 Subject: [PATCH] trigger: lttng_triggers: implement a container for multiple triggers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This container is exposed for the listing of triggers. We also plan on using it internally in the sessiond for inter-thread communication. The current implementation is backed by a lttng_dynamic_pointer_array. Caller of lttng_triggers_add is responsible for managing ownership via ref-counting of the lttng_trigger object. Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: Ib541027a6d7d856daa746de5aa49f0002bbe036f --- include/lttng/trigger/trigger-internal.h | 57 ++++++- include/lttng/trigger/trigger.h | 29 ++++ src/common/trigger.c | 207 ++++++++++++++++++++++- 3 files changed, 291 insertions(+), 2 deletions(-) diff --git a/include/lttng/trigger/trigger-internal.h b/include/lttng/trigger/trigger-internal.h index df69f3d11..6942ece78 100644 --- a/include/lttng/trigger/trigger-internal.h +++ b/include/lttng/trigger/trigger-internal.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,10 @@ struct lttng_trigger { LTTNG_OPTIONAL(uint64_t) tracer_token; }; +struct lttng_triggers { + struct lttng_dynamic_pointer_array array; +}; + struct lttng_trigger_comm { /* * Credentials, only the uid portion is used for now. @@ -54,12 +59,19 @@ struct lttng_trigger_comm { char payload[]; } LTTNG_PACKED; +struct lttng_triggers_comm { + uint32_t count; + uint32_t length; + /* Count * lttng_trigger_comm structure */ + char payload[]; +}; + LTTNG_HIDDEN ssize_t lttng_trigger_create_from_payload(struct lttng_payload_view *view, struct lttng_trigger **trigger); LTTNG_HIDDEN -int lttng_trigger_serialize(struct lttng_trigger *trigger, +int lttng_trigger_serialize(const struct lttng_trigger *trigger, struct lttng_payload *payload); LTTNG_HIDDEN @@ -98,6 +110,49 @@ void lttng_trigger_get(struct lttng_trigger *trigger); LTTNG_HIDDEN void lttng_trigger_put(struct lttng_trigger *trigger); +/* + * Allocate a new set of triggers. + * The returned object must be freed via lttng_triggers_destroy. + */ +LTTNG_HIDDEN +struct lttng_triggers *lttng_triggers_create(void); + +/* + * Return the a pointer to a mutable element at index "index" of an + * lttng_triggers set. + * + * This differs from the public `lttng_triggers_get_at_index` in that + * the returned pointer to a mutable trigger. + * + * The ownership of the trigger set element is NOT transfered. + * The returned object can NOT be freed via lttng_trigger_destroy. + */ +LTTNG_HIDDEN +struct lttng_trigger *lttng_triggers_borrow_mutable_at_index( + const struct lttng_triggers *triggers, unsigned int index); + +/* + * Add a trigger to the triggers set. + * + * A reference to the added trigger is acquired on behalf of the trigger set + * on success. + */ +LTTNG_HIDDEN +int lttng_triggers_add( + struct lttng_triggers *triggers, struct lttng_trigger *trigger); + +/* + * Serialize a trigger set to an lttng_payload object. + * Return LTTNG_OK on success, negative lttng error code on error. + */ +LTTNG_HIDDEN +int lttng_triggers_serialize(const struct lttng_triggers *triggers, + struct lttng_payload *payload); + +LTTNG_HIDDEN +ssize_t lttng_triggers_create_from_payload(struct lttng_payload_view *view, + struct lttng_triggers **triggers); + LTTNG_HIDDEN const struct lttng_credentials *lttng_trigger_get_credentials( const struct lttng_trigger *trigger); diff --git a/include/lttng/trigger/trigger.h b/include/lttng/trigger/trigger.h index 96e018f24..b8e6080d9 100644 --- a/include/lttng/trigger/trigger.h +++ b/include/lttng/trigger/trigger.h @@ -13,6 +13,8 @@ struct lttng_action; struct lttng_condition; struct lttng_trigger; +/* A set of triggers. */ +struct lttng_triggers; #ifdef __cplusplus extern "C" { @@ -148,6 +150,33 @@ extern int lttng_register_trigger(struct lttng_trigger *trigger); */ extern int lttng_unregister_trigger(struct lttng_trigger *trigger); +/* + * Get a trigger from the set at a given index. + * + * Note that the trigger set maintains the ownership of the returned trigger. + * It must not be destroyed by the user, nor should a reference to it be held + * beyond the lifetime of the trigger set. + * + * Returns a trigger, or NULL on error. + */ +extern const struct lttng_trigger *lttng_triggers_get_at_index( + const struct lttng_triggers *triggers, unsigned int index); + +/* + * Get the number of triggers in a trigger set. + * + * Return LTTNG_TRIGGER_STATUS_OK on success, + * LTTNG_TRIGGER_STATUS_INVALID when invalid parameters are passed. + */ +extern enum lttng_trigger_status lttng_triggers_get_count( + const struct lttng_triggers *triggers, unsigned int *count); + +/* + * Destroy a trigger set. + */ +extern void lttng_triggers_destroy(struct lttng_triggers *triggers); + + #ifdef __cplusplus } #endif diff --git a/src/common/trigger.c b/src/common/trigger.c index f77a32129..26997fd1f 100644 --- a/src/common/trigger.c +++ b/src/common/trigger.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -255,7 +256,7 @@ end: * for the detailed format. */ LTTNG_HIDDEN -int lttng_trigger_serialize(struct lttng_trigger *trigger, +int lttng_trigger_serialize(const struct lttng_trigger *trigger, struct lttng_payload *payload) { int ret; @@ -448,6 +449,210 @@ void lttng_trigger_put(struct lttng_trigger *trigger) urcu_ref_put(&trigger->ref , trigger_destroy_ref); } +static void delete_trigger_array_element(void *ptr) +{ + struct lttng_trigger *trigger = ptr; + + lttng_trigger_put(trigger); +} + +LTTNG_HIDDEN +struct lttng_triggers *lttng_triggers_create(void) +{ + struct lttng_triggers *triggers = NULL; + + triggers = zmalloc(sizeof(*triggers)); + if (!triggers) { + goto end; + } + + lttng_dynamic_pointer_array_init(&triggers->array, delete_trigger_array_element); + +end: + return triggers; +} + +LTTNG_HIDDEN +struct lttng_trigger *lttng_triggers_borrow_mutable_at_index( + const struct lttng_triggers *triggers, unsigned int index) +{ + struct lttng_trigger *trigger = NULL; + + assert(triggers); + if (index >= lttng_dynamic_pointer_array_get_count(&triggers->array)) { + goto end; + } + + trigger = (struct lttng_trigger *) + lttng_dynamic_pointer_array_get_pointer( + &triggers->array, index); +end: + return trigger; +} + +LTTNG_HIDDEN +int lttng_triggers_add( + struct lttng_triggers *triggers, struct lttng_trigger *trigger) +{ + int ret; + + assert(triggers); + assert(trigger); + + lttng_trigger_get(trigger); + + ret = lttng_dynamic_pointer_array_add_pointer(&triggers->array, trigger); + if (ret) { + lttng_trigger_put(trigger); + } + + return ret; +} + +const struct lttng_trigger *lttng_triggers_get_at_index( + const struct lttng_triggers *triggers, unsigned int index) +{ + return lttng_triggers_borrow_mutable_at_index(triggers, index); +} + +enum lttng_trigger_status lttng_triggers_get_count(const struct lttng_triggers *triggers, unsigned int *count) +{ + enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK; + + if (!triggers || !count) { + status = LTTNG_TRIGGER_STATUS_INVALID; + goto end; + } + + *count = lttng_dynamic_pointer_array_get_count(&triggers->array); +end: + return status; +} + +void lttng_triggers_destroy(struct lttng_triggers *triggers) +{ + if (!triggers) { + return; + } + + lttng_dynamic_pointer_array_reset(&triggers->array); + free(triggers); +} + +int lttng_triggers_serialize(const struct lttng_triggers *triggers, + struct lttng_payload *payload) +{ + int ret; + unsigned int i, count; + size_t size_before_payload; + struct lttng_triggers_comm triggers_comm = {}; + struct lttng_triggers_comm *header; + enum lttng_trigger_status status; + const size_t header_offset = payload->buffer.size; + + status = lttng_triggers_get_count(triggers, &count); + if (status != LTTNG_TRIGGER_STATUS_OK) { + ret = LTTNG_ERR_INVALID; + goto end; + } + + triggers_comm.count = count; + + /* Placeholder header; updated at the end. */ + ret = lttng_dynamic_buffer_append(&payload->buffer, &triggers_comm, + sizeof(triggers_comm)); + if (ret) { + goto end; + } + + size_before_payload = payload->buffer.size; + + for (i = 0; i < count; i++) { + const struct lttng_trigger *trigger = + lttng_triggers_get_at_index(triggers, i); + + assert(trigger); + + ret = lttng_trigger_serialize(trigger, payload); + if (ret) { + goto end; + } + } + + /* Update payload size. */ + header = (struct lttng_triggers_comm *) ((char *) payload->buffer.data + header_offset); + header->length = payload->buffer.size - size_before_payload; +end: + return ret; +} + +LTTNG_HIDDEN +ssize_t lttng_triggers_create_from_payload( + struct lttng_payload_view *src_view, + struct lttng_triggers **triggers) +{ + ssize_t ret, offset = 0, triggers_size = 0; + unsigned int i; + const struct lttng_triggers_comm *triggers_comm; + struct lttng_triggers *local_triggers = NULL; + + if (!src_view || !triggers) { + ret = -1; + goto error; + } + + /* lttng_trigger_comms header */ + triggers_comm = (const struct lttng_triggers_comm *) src_view->buffer.data; + offset += sizeof(*triggers_comm); + + local_triggers = lttng_triggers_create(); + if (!local_triggers) { + ret = -1; + goto error; + } + + for (i = 0; i < triggers_comm->count; i++) { + struct lttng_trigger *trigger = NULL; + struct lttng_payload_view trigger_view = + lttng_payload_view_from_view(src_view, offset, -1); + ssize_t trigger_size; + + trigger_size = lttng_trigger_create_from_payload( + &trigger_view, &trigger); + if (trigger_size < 0) { + ret = trigger_size; + goto error; + } + + /* Transfer ownership of the trigger to the collection. */ + ret = lttng_triggers_add(local_triggers, trigger); + lttng_trigger_put(trigger); + if (ret < 0) { + ret = -1; + goto error; + } + + offset += trigger_size; + triggers_size += trigger_size; + } + + /* Unexpected size of inner-elements; the buffer is corrupted. */ + if ((ssize_t) triggers_comm->length != triggers_size) { + ret = -1; + goto error; + } + + /* Pass ownership to caller. */ + *triggers = local_triggers; + local_triggers = NULL; + + ret = offset; +error: + + lttng_triggers_destroy(local_triggers); + return ret; +} + LTTNG_HIDDEN const struct lttng_credentials *lttng_trigger_get_credentials( const struct lttng_trigger *trigger) -- 2.34.1