From c6962c968f7467ce8f7e880e7de3797139314f9f Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 13 Aug 2019 23:21:46 -0400 Subject: [PATCH] lib: add user attributes property to metadata, stream, and trace objects This patch adds an optional user attributes property to the following trace IR objects: * Clock class * Event class * Field class * Structure field class member * Variant field class option * Stream class * Stream * Trace class * Trace A user attributes object is a map value object which adds custom information to any of the objects above. It is entirely up to the user to set user attributes. At creation time, all the objects above contain an initial, empty map value. CTF 2 will very likely have such user attributes for metadata objects, so Babeltrace 2.0 will be ready. For CTF 2, it is intended that user attributes will be namespaced to reduce or eliminate clashes, for example using URLs or domain names, which are also typically used for Java packages and XML namespaces: { "https://lttng.org": { "some-attribute": true } } CTF 2 will only have user attributes for metadata objects, but I decided to also have user attributes for long-lived data objects: streams and traces. This is not enforced in Babeltrace however: the user is free to put whatever she needs into this map value. There's a bt_*_set_user_attributes() function to set the user attributes of an object and bt_*_borrow_user_attributes()/bt_*_borrow_user_attributes_const() functions to borrow them from the object. This patch changes when structure field class members and variant field class options are frozen: Before this patch: When you append to a structure/variant field class, the member/option is frozen, including its field class. With this patch: When you append to a structure/variant field class, the member/option itself is not frozen, but its field class is. The member/option is frozen when its containing structure/variant field class is frozen. This makes it possible to append a member/option to a structure/variant field class, borrow that member/option, and then set its user attributes before the whole structure/variant field class is frozen. Signed-off-by: Philippe Proulx Change-Id: Ibb12de23fb2c4d752b13381769d2ac1841eb5dc9 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1922 Tested-by: jenkins --- .../babeltrace2/trace-ir/clock-class-const.h | 3 + include/babeltrace2/trace-ir/clock-class.h | 6 + .../babeltrace2/trace-ir/event-class-const.h | 3 + include/babeltrace2/trace-ir/event-class.h | 6 + .../babeltrace2/trace-ir/field-class-const.h | 9 + include/babeltrace2/trace-ir/field-class.h | 20 ++ .../babeltrace2/trace-ir/stream-class-const.h | 3 + include/babeltrace2/trace-ir/stream-class.h | 6 + include/babeltrace2/trace-ir/stream-const.h | 3 + include/babeltrace2/trace-ir/stream.h | 5 + .../babeltrace2/trace-ir/trace-class-const.h | 3 + include/babeltrace2/trace-ir/trace-class.h | 6 + include/babeltrace2/trace-ir/trace-const.h | 3 + include/babeltrace2/trace-ir/trace.h | 5 + src/lib/trace-ir/clock-class.c | 41 +++ src/lib/trace-ir/clock-class.h | 3 + src/lib/trace-ir/event-class.c | 45 ++- src/lib/trace-ir/event-class.h | 3 + src/lib/trace-ir/field-class.c | 258 ++++++++++++++++-- src/lib/trace-ir/field-class.h | 6 + src/lib/trace-ir/stream-class.c | 42 ++- src/lib/trace-ir/stream-class.h | 3 + src/lib/trace-ir/stream.c | 37 +++ src/lib/trace-ir/stream.h | 3 + src/lib/trace-ir/trace-class.c | 36 +++ src/lib/trace-ir/trace-class.h | 3 + src/lib/trace-ir/trace.c | 38 +++ src/lib/trace-ir/trace.h | 3 + 28 files changed, 570 insertions(+), 32 deletions(-) diff --git a/include/babeltrace2/trace-ir/clock-class-const.h b/include/babeltrace2/trace-ir/clock-class-const.h index b4affd53..6316f83f 100644 --- a/include/babeltrace2/trace-ir/clock-class-const.h +++ b/include/babeltrace2/trace-ir/clock-class-const.h @@ -35,6 +35,9 @@ extern "C" { #endif +extern const bt_value *bt_clock_class_borrow_user_attributes_const( + const bt_clock_class *clock_class); + extern const char *bt_clock_class_get_name( const bt_clock_class *clock_class); diff --git a/include/babeltrace2/trace-ir/clock-class.h b/include/babeltrace2/trace-ir/clock-class.h index f3cb1d93..5d0c5987 100644 --- a/include/babeltrace2/trace-ir/clock-class.h +++ b/include/babeltrace2/trace-ir/clock-class.h @@ -37,6 +37,12 @@ extern "C" { extern bt_clock_class *bt_clock_class_create(bt_self_component *self_comp); +extern bt_value *bt_clock_class_borrow_user_attributes( + bt_clock_class *clock_class); + +extern void bt_clock_class_set_user_attributes( + bt_clock_class *clock_class, const bt_value *user_attributes); + typedef enum bt_clock_class_set_name_status { BT_CLOCK_CLASS_SET_NAME_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, BT_CLOCK_CLASS_SET_NAME_STATUS_OK = __BT_FUNC_STATUS_OK, diff --git a/include/babeltrace2/trace-ir/event-class-const.h b/include/babeltrace2/trace-ir/event-class-const.h index 80f33ead..5b686dc6 100644 --- a/include/babeltrace2/trace-ir/event-class-const.h +++ b/include/babeltrace2/trace-ir/event-class-const.h @@ -55,6 +55,9 @@ typedef enum bt_event_class_log_level { BT_EVENT_CLASS_LOG_LEVEL_DEBUG, } bt_event_class_log_level; +extern const bt_value *bt_event_class_borrow_user_attributes_const( + const bt_event_class *event_class); + extern const bt_stream_class *bt_event_class_borrow_stream_class_const( const bt_event_class *event_class); diff --git a/include/babeltrace2/trace-ir/event-class.h b/include/babeltrace2/trace-ir/event-class.h index fa225019..e435d387 100644 --- a/include/babeltrace2/trace-ir/event-class.h +++ b/include/babeltrace2/trace-ir/event-class.h @@ -42,6 +42,12 @@ extern bt_event_class *bt_event_class_create( extern bt_event_class *bt_event_class_create_with_id( bt_stream_class *stream_class, uint64_t id); +extern bt_value *bt_event_class_borrow_user_attributes( + bt_event_class *event_class); + +extern void bt_event_class_set_user_attributes( + bt_event_class *event_class, const bt_value *user_attributes); + extern bt_stream_class *bt_event_class_borrow_stream_class( bt_event_class *event_class); diff --git a/include/babeltrace2/trace-ir/field-class-const.h b/include/babeltrace2/trace-ir/field-class-const.h index 27f22c17..bc9b823b 100644 --- a/include/babeltrace2/trace-ir/field-class-const.h +++ b/include/babeltrace2/trace-ir/field-class-const.h @@ -64,6 +64,9 @@ typedef enum bt_field_class_integer_preferred_display_base { extern bt_field_class_type bt_field_class_get_type( const bt_field_class *field_class); +extern const bt_value *bt_field_class_borrow_user_attributes_const( + const bt_field_class *field_class); + extern uint64_t bt_field_class_bit_array_get_length( const bt_field_class *field_class); @@ -158,6 +161,9 @@ extern const bt_field_class * bt_field_class_structure_member_borrow_field_class_const( const bt_field_class_structure_member *member); +extern const bt_value *bt_field_class_structure_member_borrow_user_attributes_const( + const bt_field_class_structure_member *member); + extern const bt_field_class * bt_field_class_array_borrow_element_field_class_const( const bt_field_class *field_class); @@ -211,6 +217,9 @@ extern const bt_field_class * bt_field_class_variant_option_borrow_field_class_const( const bt_field_class_variant_option *option); +extern const bt_value *bt_field_class_variant_option_borrow_user_attributes_const( + const bt_field_class_variant_option *option); + extern const bt_field_path * bt_field_class_variant_with_selector_borrow_selector_field_path_const( const bt_field_class *field_class); diff --git a/include/babeltrace2/trace-ir/field-class.h b/include/babeltrace2/trace-ir/field-class.h index 083facbe..847064b9 100644 --- a/include/babeltrace2/trace-ir/field-class.h +++ b/include/babeltrace2/trace-ir/field-class.h @@ -37,6 +37,12 @@ extern "C" { #endif +extern void bt_field_class_set_user_attributes( + bt_field_class *field_class, const bt_value *user_attributes); + +extern bt_value *bt_field_class_borrow_user_attributes( + bt_field_class *field_class); + extern bt_field_class *bt_field_class_bool_create( bt_trace_class *trace_class); @@ -107,6 +113,13 @@ extern bt_field_class_structure_member * bt_field_class_structure_borrow_member_by_name( bt_field_class *field_class, const char *name); +extern bt_value *bt_field_class_structure_member_borrow_user_attributes( + bt_field_class_structure_member *member); + +extern void bt_field_class_structure_member_set_user_attributes( + bt_field_class_structure_member *member, + const bt_value *user_attributes); + extern bt_field_class *bt_field_class_array_static_create( bt_trace_class *trace_class, bt_field_class *elem_field_class, uint64_t length); @@ -163,6 +176,13 @@ extern bt_field_class_variant_option * bt_field_class_variant_borrow_option_by_name( bt_field_class *field_class, const char *name); +extern bt_value *bt_field_class_variant_option_borrow_user_attributes( + bt_field_class_variant_option *option); + +extern void bt_field_class_variant_option_set_user_attributes( + bt_field_class_variant_option *option, + const bt_value *user_attributes); + #ifdef __cplusplus } #endif diff --git a/include/babeltrace2/trace-ir/stream-class-const.h b/include/babeltrace2/trace-ir/stream-class-const.h index c21d0e75..7a7077b9 100644 --- a/include/babeltrace2/trace-ir/stream-class-const.h +++ b/include/babeltrace2/trace-ir/stream-class-const.h @@ -35,6 +35,9 @@ extern "C" { #endif +extern const bt_value *bt_stream_class_borrow_user_attributes_const( + const bt_stream_class *stream_class); + extern const bt_trace_class *bt_stream_class_borrow_trace_class_const( const bt_stream_class *stream_class); diff --git a/include/babeltrace2/trace-ir/stream-class.h b/include/babeltrace2/trace-ir/stream-class.h index 469fe019..58bdbdc4 100644 --- a/include/babeltrace2/trace-ir/stream-class.h +++ b/include/babeltrace2/trace-ir/stream-class.h @@ -41,6 +41,12 @@ extern bt_stream_class *bt_stream_class_create( extern bt_stream_class *bt_stream_class_create_with_id( bt_trace_class *trace_class, uint64_t id); +extern bt_value *bt_stream_class_borrow_user_attributes( + bt_stream_class *stream_class); + +extern void bt_stream_class_set_user_attributes( + bt_stream_class *stream_class, const bt_value *user_attributes); + extern bt_trace_class *bt_stream_class_borrow_trace_class( bt_stream_class *stream_class); diff --git a/include/babeltrace2/trace-ir/stream-const.h b/include/babeltrace2/trace-ir/stream-const.h index 2465343c..bf809830 100644 --- a/include/babeltrace2/trace-ir/stream-const.h +++ b/include/babeltrace2/trace-ir/stream-const.h @@ -35,6 +35,9 @@ extern "C" { #endif +extern const bt_value *bt_stream_borrow_user_attributes_const( + const bt_stream *stream); + extern const bt_stream_class *bt_stream_borrow_class_const( const bt_stream *stream); diff --git a/include/babeltrace2/trace-ir/stream.h b/include/babeltrace2/trace-ir/stream.h index 0ef1b84d..416e42ce 100644 --- a/include/babeltrace2/trace-ir/stream.h +++ b/include/babeltrace2/trace-ir/stream.h @@ -42,6 +42,11 @@ extern bt_stream *bt_stream_create_with_id( bt_stream_class *stream_class, bt_trace *trace, uint64_t id); +extern bt_value *bt_stream_borrow_user_attributes(bt_stream *stream); + +extern void bt_stream_set_user_attributes( + bt_stream *stream, const bt_value *user_attributes); + extern bt_trace *bt_stream_borrow_trace(bt_stream *stream); extern bt_stream_class *bt_stream_borrow_class(bt_stream *stream); diff --git a/include/babeltrace2/trace-ir/trace-class-const.h b/include/babeltrace2/trace-ir/trace-class-const.h index 023ce650..6ad9a9d7 100644 --- a/include/babeltrace2/trace-ir/trace-class-const.h +++ b/include/babeltrace2/trace-ir/trace-class-const.h @@ -38,6 +38,9 @@ extern "C" { typedef void (* bt_trace_class_destruction_listener_func)( const bt_trace_class *trace_class, void *data); +extern const bt_value *bt_trace_class_borrow_user_attributes_const( + const bt_trace_class *trace_class); + extern bt_bool bt_trace_class_assigns_automatic_stream_class_id( const bt_trace_class *trace_class); diff --git a/include/babeltrace2/trace-ir/trace-class.h b/include/babeltrace2/trace-ir/trace-class.h index 52d34c67..d90ba2c9 100644 --- a/include/babeltrace2/trace-ir/trace-class.h +++ b/include/babeltrace2/trace-ir/trace-class.h @@ -37,6 +37,12 @@ extern "C" { extern bt_trace_class *bt_trace_class_create(bt_self_component *self_comp); +extern bt_value *bt_trace_class_borrow_user_attributes( + bt_trace_class *trace_class); + +extern void bt_trace_class_set_user_attributes( + bt_trace_class *trace_class, const bt_value *user_attributes); + extern void bt_trace_class_set_assigns_automatic_stream_class_id( bt_trace_class *trace_class, bt_bool value); diff --git a/include/babeltrace2/trace-ir/trace-const.h b/include/babeltrace2/trace-ir/trace-const.h index f437aec0..d4410a2d 100644 --- a/include/babeltrace2/trace-ir/trace-const.h +++ b/include/babeltrace2/trace-ir/trace-const.h @@ -38,6 +38,9 @@ extern "C" { typedef void (* bt_trace_destruction_listener_func)( const bt_trace *trace, void *data); +extern const bt_value *bt_trace_borrow_user_attributes_const( + const bt_trace *trace); + extern const bt_trace_class *bt_trace_borrow_class_const( const bt_trace *trace); diff --git a/include/babeltrace2/trace-ir/trace.h b/include/babeltrace2/trace-ir/trace.h index 7cd5f3ff..4d17c484 100644 --- a/include/babeltrace2/trace-ir/trace.h +++ b/include/babeltrace2/trace-ir/trace.h @@ -39,6 +39,11 @@ extern bt_trace_class *bt_trace_borrow_class(bt_trace *trace); extern bt_trace *bt_trace_create(bt_trace_class *trace_class); +extern bt_value *bt_trace_borrow_user_attributes(bt_trace *trace); + +extern void bt_trace_set_user_attributes( + bt_trace *trace, const bt_value *user_attributes); + typedef enum bt_trace_set_name_status { BT_TRACE_SET_NAME_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, BT_TRACE_SET_NAME_STATUS_OK = __BT_FUNC_STATUS_OK, diff --git a/src/lib/trace-ir/clock-class.c b/src/lib/trace-ir/clock-class.c index 34e3a87b..e982ad7f 100644 --- a/src/lib/trace-ir/clock-class.c +++ b/src/lib/trace-ir/clock-class.c @@ -38,6 +38,7 @@ #include "lib/object.h" #include "common/assert.h" #include "lib/func-status.h" +#include "lib/value.h" #define BT_ASSERT_PRE_DEV_CLOCK_CLASS_HOT(_cc) \ BT_ASSERT_PRE_DEV_HOT((_cc), "Clock class", ": %!+K", (_cc)) @@ -48,6 +49,7 @@ void destroy_clock_class(struct bt_object *obj) struct bt_clock_class *clock_class = (void *) obj; BT_LIB_LOGD("Destroying clock class: %!+K", clock_class); + BT_OBJECT_PUT_REF_AND_RESET(clock_class->user_attributes); if (clock_class->name.str) { g_string_free(clock_class->name.str, TRUE); @@ -95,6 +97,14 @@ struct bt_clock_class *bt_clock_class_create(bt_self_component *self_comp) } bt_object_init_shared(&clock_class->base, destroy_clock_class); + + clock_class->user_attributes = bt_value_map_create(); + if (!clock_class->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } + clock_class->name.str = g_string_new(NULL); if (!clock_class->name.str) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); @@ -276,6 +286,9 @@ void _bt_clock_class_freeze(const struct bt_clock_class *clock_class) return; } + BT_LIB_LOGD("Freezing clock class's user attributes: %!+v", + clock_class->user_attributes); + bt_value_freeze(clock_class->user_attributes); BT_LIB_LOGD("Freezing clock class: %!+K", clock_class); ((struct bt_clock_class *) clock_class)->frozen = 1; } @@ -302,6 +315,34 @@ bt_clock_class_cycles_to_ns_from_origin( return ret; } +const struct bt_value *bt_clock_class_borrow_user_attributes_const( + const struct bt_clock_class *clock_class) +{ + BT_ASSERT_PRE_DEV_NON_NULL(clock_class, "Clock class"); + return clock_class->user_attributes; +} + +struct bt_value *bt_clock_class_borrow_user_attributes( + struct bt_clock_class *clock_class) +{ + return (void *) bt_clock_class_borrow_user_attributes_const( + (void *) clock_class); +} + +void bt_clock_class_set_user_attributes( + struct bt_clock_class *clock_class, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_CLOCK_CLASS_HOT(clock_class); + bt_object_put_no_null_check(clock_class->user_attributes); + clock_class->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(clock_class->user_attributes); +} + void bt_clock_class_get_ref(const struct bt_clock_class *clock_class) { bt_object_get_ref(clock_class); diff --git a/src/lib/trace-ir/clock-class.h b/src/lib/trace-ir/clock-class.h index b39183c2..b3eb14ff 100644 --- a/src/lib/trace-ir/clock-class.h +++ b/src/lib/trace-ir/clock-class.h @@ -42,6 +42,9 @@ struct bt_clock_class { struct bt_object base; + /* Owned by this */ + struct bt_value *user_attributes; + struct { GString *str; diff --git a/src/lib/trace-ir/event-class.c b/src/lib/trace-ir/event-class.c index c5e5230e..ae7653e9 100644 --- a/src/lib/trace-ir/event-class.c +++ b/src/lib/trace-ir/event-class.c @@ -59,6 +59,7 @@ void destroy_event_class(struct bt_object *obj) struct bt_event_class *event_class = (void *) obj; BT_LIB_LOGD("Destroying event class: %!+E", event_class); + BT_OBJECT_PUT_REF_AND_RESET(event_class->user_attributes); if (event_class->name.str) { g_string_free(event_class->name.str, TRUE); @@ -127,21 +128,26 @@ struct bt_event_class *create_event_class_with_id( bt_object_init_shared_with_parent(&event_class->base, destroy_event_class); + event_class->user_attributes = bt_value_map_create(); + if (!event_class->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } + event_class->id = id; bt_property_uint_init(&event_class->log_level, BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0); event_class->name.str = g_string_new(NULL); if (!event_class->name.str) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - ret = -1; - goto end; + goto error; } event_class->emf_uri.str = g_string_new(NULL); if (!event_class->emf_uri.str) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - ret = -1; - goto end; + goto error; } ret = bt_object_pool_initialize(&event_class->event_pool, @@ -402,10 +408,41 @@ void _bt_event_class_freeze(const struct bt_event_class *event_class) { /* The field classes are already frozen */ BT_ASSERT(event_class); + BT_LIB_LOGD("Freezing event class's user attributes: %!+v", + event_class->user_attributes); + bt_value_freeze(event_class->user_attributes); BT_LIB_LOGD("Freezing event class: %!+E", event_class); ((struct bt_event_class *) event_class)->frozen = true; } +const struct bt_value *bt_event_class_borrow_user_attributes_const( + const struct bt_event_class *event_class) +{ + BT_ASSERT_PRE_DEV_NON_NULL(event_class, "Event class"); + return event_class->user_attributes; +} + +struct bt_value *bt_event_class_borrow_user_attributes( + struct bt_event_class *event_class) +{ + return (void *) bt_event_class_borrow_user_attributes_const( + (void *) event_class); +} + +void bt_event_class_set_user_attributes( + struct bt_event_class *event_class, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_EVENT_CLASS_HOT(event_class); + bt_object_put_no_null_check(event_class->user_attributes); + event_class->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(event_class->user_attributes); +} + void bt_event_class_get_ref(const struct bt_event_class *event_class) { bt_object_get_ref(event_class); diff --git a/src/lib/trace-ir/event-class.h b/src/lib/trace-ir/event-class.h index 66d53670..83734eed 100644 --- a/src/lib/trace-ir/event-class.h +++ b/src/lib/trace-ir/event-class.h @@ -46,6 +46,9 @@ struct bt_event_class { struct bt_field_class *specific_context_fc; struct bt_field_class *payload_fc; + /* Owned by this */ + struct bt_value *user_attributes; + struct { GString *str; diff --git a/src/lib/trace-ir/field-class.c b/src/lib/trace-ir/field-class.c index 78e30f4d..97409dc9 100644 --- a/src/lib/trace-ir/field-class.c +++ b/src/lib/trace-ir/field-class.c @@ -46,6 +46,7 @@ #include "utils.h" #include "lib/func-status.h" #include "lib/integer-range-set.h" +#include "lib/value.h" enum bt_field_class_type bt_field_class_get_type( const struct bt_field_class *fc) @@ -55,13 +56,31 @@ enum bt_field_class_type bt_field_class_get_type( } static -void init_field_class(struct bt_field_class *fc, enum bt_field_class_type type, +int init_field_class(struct bt_field_class *fc, enum bt_field_class_type type, bt_object_release_func release_func) { + int ret = 0; + BT_ASSERT(fc); BT_ASSERT(release_func); bt_object_init_shared(&fc->base, release_func); fc->type = type; + fc->user_attributes = bt_value_map_create(); + if (!fc->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + ret = -1; + goto end; + } + +end: + return ret; +} + +static +void finalize_field_class(struct bt_field_class *fc) +{ + BT_OBJECT_PUT_REF_AND_RESET(fc->user_attributes); } static @@ -69,6 +88,7 @@ void destroy_bit_array_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying bit array field class object: %!+F", obj); + finalize_field_class((void *) obj); g_free(obj); } @@ -89,8 +109,11 @@ struct bt_field_class *bt_field_class_bit_array_create( goto error; } - init_field_class((void *) ba_fc, BT_FIELD_CLASS_TYPE_BIT_ARRAY, - destroy_bit_array_field_class); + if (init_field_class((void *) ba_fc, BT_FIELD_CLASS_TYPE_BIT_ARRAY, + destroy_bit_array_field_class)) { + goto error; + } + ba_fc->length = length; BT_LIB_LOGD("Created bit array field class object: %!+F", ba_fc); goto end; @@ -117,6 +140,7 @@ void destroy_bool_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying boolean field class object: %!+F", obj); + finalize_field_class((void *) obj); g_free(obj); } @@ -134,8 +158,11 @@ struct bt_field_class *bt_field_class_bool_create( goto error; } - init_field_class((void *) bool_fc, BT_FIELD_CLASS_TYPE_BOOL, - destroy_bool_field_class); + if (init_field_class((void *) bool_fc, BT_FIELD_CLASS_TYPE_BOOL, + destroy_bool_field_class)) { + goto error; + } + BT_LIB_LOGD("Created boolean field class object: %!+F", bool_fc); goto end; @@ -147,13 +174,22 @@ end: } static -void init_integer_field_class(struct bt_field_class_integer *fc, +int init_integer_field_class(struct bt_field_class_integer *fc, enum bt_field_class_type type, bt_object_release_func release_func) { - init_field_class((void *) fc, type, release_func); + int ret; + + ret = init_field_class((void *) fc, type, release_func); + if (ret) { + goto end; + } + fc->range = 64; fc->base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; + +end: + return ret; } static @@ -161,6 +197,7 @@ void destroy_integer_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying integer field class object: %!+F", obj); + finalize_field_class((void *) obj); g_free(obj); } @@ -180,7 +217,11 @@ struct bt_field_class *create_integer_field_class(bt_trace_class *trace_class, goto error; } - init_integer_field_class(int_fc, type, destroy_integer_field_class); + if (init_integer_field_class(int_fc, type, + destroy_integer_field_class)) { + goto error; + } + BT_LIB_LOGD("Created integer field class object: %!+F", int_fc); goto end; @@ -289,6 +330,7 @@ void destroy_enumeration_field_class(struct bt_object *obj) BT_ASSERT(fc); BT_LIB_LOGD("Destroying enumeration field class object: %!+F", fc); + finalize_field_class((void *) obj); if (fc->mappings) { uint64_t i; @@ -326,8 +368,11 @@ struct bt_field_class *create_enumeration_field_class( goto error; } - init_integer_field_class((void *) enum_fc, type, - destroy_enumeration_field_class); + if (init_integer_field_class((void *) enum_fc, type, + destroy_enumeration_field_class)) { + goto error; + } + enum_fc->mappings = g_array_new(FALSE, TRUE, sizeof(struct bt_field_class_enumeration_mapping)); if (!enum_fc->mappings) { @@ -645,6 +690,7 @@ void destroy_real_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying real field class object: %!+F", obj); + finalize_field_class((void *) obj); g_free(obj); } @@ -660,8 +706,11 @@ struct bt_field_class *bt_field_class_real_create(bt_trace_class *trace_class) goto error; } - init_field_class((void *) real_fc, BT_FIELD_CLASS_TYPE_REAL, - destroy_real_field_class); + if (init_field_class((void *) real_fc, BT_FIELD_CLASS_TYPE_REAL, + destroy_real_field_class)) { + goto error; + } + BT_LIB_LOGD("Created real field class object: %!+F", real_fc); goto end; @@ -703,7 +752,11 @@ int init_named_field_classes_container( { int ret = 0; - init_field_class((void *) fc, type, fc_release_func); + ret = init_field_class((void *) fc, type, fc_release_func); + if (ret) { + goto end; + } + fc->named_fcs = g_ptr_array_new_with_free_func(named_fc_destroy_func); if (!fc->named_fcs) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray."); @@ -730,6 +783,7 @@ void finalize_named_field_class(struct bt_named_field_class *named_fc) "addr=%p, name=\"%s\", %![fc-]+F", named_fc, named_fc->name ? named_fc->name->str : NULL, named_fc->fc); + BT_OBJECT_PUT_REF_AND_RESET(named_fc->user_attributes); if (named_fc->name) { g_string_free(named_fc->name, TRUE); @@ -743,6 +797,10 @@ void finalize_named_field_class(struct bt_named_field_class *named_fc) static void destroy_named_field_class(gpointer ptr) { + struct bt_named_field_class *named_fc = ptr; + + BT_OBJECT_PUT_REF_AND_RESET(named_fc->user_attributes); + if (ptr) { finalize_named_field_class(ptr); g_free(ptr); @@ -784,6 +842,7 @@ void destroy_structure_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying structure field class object: %!+F", obj); + finalize_field_class((void *) obj); finalize_named_field_classes_container((void *) obj); g_free(obj); } @@ -837,9 +896,16 @@ int init_named_field_class(struct bt_named_field_class *named_fc, goto end; } + named_fc->user_attributes = bt_value_map_create(); + if (!named_fc->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + named_fc->fc = fc; bt_object_get_no_null_check(named_fc->fc); - bt_named_field_class_freeze(named_fc); end: return status; @@ -920,6 +986,13 @@ int append_named_field_class_to_container_field_class( "Duplicate member/option name in structure/variant field class: " "%![container-fc-]+F, name=\"%s\"", container_fc, named_fc->name->str); + + /* + * Freeze the contained field class, but not the named field + * class itself, as it's still possible afterwards to modify + * properties of the member/option object. + */ + bt_field_class_freeze(named_fc->fc); g_ptr_array_add(container_fc->named_fcs, named_fc); g_hash_table_insert(container_fc->name_to_index, named_fc->name->str, GUINT_TO_POINTER(container_fc->named_fcs->len - 1)); @@ -1074,6 +1147,7 @@ void destroy_option_field_class(struct bt_object *obj) BT_ASSERT(fc); BT_LIB_LOGD("Destroying option field class object: %!+F", fc); + finalize_field_class((void *) obj); BT_LOGD_STR("Putting content field class."); BT_OBJECT_PUT_REF_AND_RESET(fc->content_fc); BT_LOGD_STR("Putting selector field path."); @@ -1099,8 +1173,11 @@ struct bt_field_class *bt_field_class_option_create(bt_trace_class *trace_class, goto error; } - init_field_class((void *) opt_fc, BT_FIELD_CLASS_TYPE_OPTION, - destroy_option_field_class); + if (init_field_class((void *) opt_fc, BT_FIELD_CLASS_TYPE_OPTION, + destroy_option_field_class)) { + goto error; + } + opt_fc->content_fc = content_fc; bt_object_get_no_null_check(opt_fc->content_fc); bt_field_class_freeze(opt_fc->content_fc); @@ -1152,6 +1229,7 @@ void finalize_variant_field_class(struct bt_field_class_variant *var_fc) { BT_ASSERT(var_fc); BT_LIB_LOGD("Finalizing variant field class object: %!+F", var_fc); + finalize_field_class((void *) var_fc); finalize_named_field_classes_container((void *) var_fc); } @@ -1606,15 +1684,24 @@ bt_field_class_variant_with_selector_borrow_selector_field_path_const( } static -void init_array_field_class(struct bt_field_class_array *fc, +int init_array_field_class(struct bt_field_class_array *fc, enum bt_field_class_type type, bt_object_release_func release_func, struct bt_field_class *element_fc) { + int ret; + BT_ASSERT(element_fc); - init_field_class((void *) fc, type, release_func); + ret = init_field_class((void *) fc, type, release_func); + if (ret) { + goto end; + } + fc->element_fc = element_fc; bt_object_get_no_null_check(fc->element_fc); bt_field_class_freeze(element_fc); + +end: + return ret; } static @@ -1622,6 +1709,7 @@ void finalize_array_field_class(struct bt_field_class_array *array_fc) { BT_ASSERT(array_fc); BT_LOGD_STR("Putting element field class."); + finalize_field_class((void *) array_fc); BT_OBJECT_PUT_REF_AND_RESET(array_fc->element_fc); } @@ -1650,8 +1738,12 @@ bt_field_class_array_static_create(bt_trace_class *trace_class, goto error; } - init_array_field_class((void *) array_fc, BT_FIELD_CLASS_TYPE_STATIC_ARRAY, - destroy_static_array_field_class, element_fc); + if (init_array_field_class((void *) array_fc, + BT_FIELD_CLASS_TYPE_STATIC_ARRAY, + destroy_static_array_field_class, element_fc)) { + goto error; + } + array_fc->length = length; BT_LIB_LOGD("Created static array field class object: %!+F", array_fc); goto end; @@ -1726,9 +1818,11 @@ struct bt_field_class *bt_field_class_array_dynamic_create( goto error; } - init_array_field_class((void *) array_fc, - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, - destroy_dynamic_array_field_class, element_fc); + if (init_array_field_class((void *) array_fc, + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, + destroy_dynamic_array_field_class, element_fc)) { + goto error; + } if (length_fc) { BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(length_fc, @@ -1765,6 +1859,7 @@ void destroy_string_field_class(struct bt_object *obj) { BT_ASSERT(obj); BT_LIB_LOGD("Destroying string field class object: %!+F", obj); + finalize_field_class((void *) obj); g_free(obj); } @@ -1781,8 +1876,11 @@ struct bt_field_class *bt_field_class_string_create(bt_trace_class *trace_class) goto error; } - init_field_class((void *) string_fc, BT_FIELD_CLASS_TYPE_STRING, - destroy_string_field_class); + if (init_field_class((void *) string_fc, BT_FIELD_CLASS_TYPE_STRING, + destroy_string_field_class)) { + goto error; + } + BT_LIB_LOGD("Created string field class object: %!+F", string_fc); goto end; @@ -1803,6 +1901,7 @@ void _bt_field_class_freeze(const struct bt_field_class *c_fc) * their owner. */ BT_ASSERT(fc); + bt_value_freeze(fc->user_attributes); fc->frozen = true; switch (fc->type) { @@ -1831,8 +1930,11 @@ BT_HIDDEN void _bt_named_field_class_freeze(const struct bt_named_field_class *named_fc) { BT_ASSERT(named_fc); + BT_ASSERT(named_fc->fc->frozen); + BT_LIB_LOGD("Freezing named field class's user attributes: %!+v", + named_fc->user_attributes); + bt_value_freeze(named_fc->user_attributes); ((struct bt_named_field_class *) named_fc)->frozen = true; - bt_field_class_freeze(named_fc->fc); } BT_HIDDEN @@ -1877,6 +1979,110 @@ void bt_field_class_make_part_of_trace_class(const struct bt_field_class *c_fc) } } +const struct bt_value *bt_field_class_borrow_user_attributes_const( + const struct bt_field_class *fc) +{ + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + return fc->user_attributes; +} + +struct bt_value *bt_field_class_borrow_user_attributes( + struct bt_field_class *field_class) +{ + return (void *) bt_field_class_borrow_user_attributes_const( + (void *) field_class); +} + + +void bt_field_class_set_user_attributes( + struct bt_field_class *fc, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_FC_HOT(fc, "Field class"); + bt_object_put_no_null_check(fc->user_attributes); + fc->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(fc->user_attributes); +} + +static +const struct bt_value *bt_named_field_class_borrow_user_attributes_const( + const struct bt_named_field_class *named_fc) +{ + return named_fc->user_attributes; +} + +static +void bt_named_field_class_set_user_attributes( + struct bt_named_field_class *named_fc, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_HOT(named_fc, + "Structure field class member or variant field class option", + "."); + bt_object_put_no_null_check(named_fc->user_attributes); + named_fc->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(named_fc->user_attributes); +} + +const struct bt_value * +bt_field_class_structure_member_borrow_user_attributes_const( + const struct bt_field_class_structure_member *member) +{ + BT_ASSERT_PRE_NON_NULL(member, "Structure field class member"); + return bt_named_field_class_borrow_user_attributes_const( + (const void *) member); +} + +struct bt_value * +bt_field_class_structure_member_borrow_user_attributes( + struct bt_field_class_structure_member *member) +{ + BT_ASSERT_PRE_NON_NULL(member, "Structure field class member"); + return (void *) bt_named_field_class_borrow_user_attributes_const( + (void *) member); +} + +void bt_field_class_structure_member_set_user_attributes( + struct bt_field_class_structure_member *member, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(member, "Structure field class member"); + bt_named_field_class_set_user_attributes((void *) member, + user_attributes); +} + +const struct bt_value *bt_field_class_variant_option_borrow_user_attributes_const( + const struct bt_field_class_variant_option *option) +{ + BT_ASSERT_PRE_NON_NULL(option, "Variant field class option"); + return bt_named_field_class_borrow_user_attributes_const( + (const void *) option); +} + +struct bt_value *bt_field_class_variant_option_borrow_user_attributes( + struct bt_field_class_variant_option *option) +{ + BT_ASSERT_PRE_NON_NULL(option, "Variant field class option"); + return (void *) bt_named_field_class_borrow_user_attributes_const( + (void *) option); +} + +void bt_field_class_variant_option_set_user_attributes( + struct bt_field_class_variant_option *option, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(option, "Variant field class option"); + bt_named_field_class_set_user_attributes((void *) option, + user_attributes); +} + void bt_field_class_get_ref(const struct bt_field_class *field_class) { bt_object_get_ref(field_class); diff --git a/src/lib/trace-ir/field-class.h b/src/lib/trace-ir/field-class.h index 77eece7b..e7eff691 100644 --- a/src/lib/trace-ir/field-class.h +++ b/src/lib/trace-ir/field-class.h @@ -179,6 +179,9 @@ struct bt_field_class { enum bt_field_class_type type; bool frozen; + /* Owned by this */ + struct bt_value *user_attributes; + /* * This flag indicates whether or not this field class is part * of a trace class. @@ -252,6 +255,9 @@ struct bt_field_class_string { struct bt_named_field_class { GString *name; + /* Owned by this */ + struct bt_value *user_attributes; + /* Owned by this */ struct bt_field_class *fc; diff --git a/src/lib/trace-ir/stream-class.c b/src/lib/trace-ir/stream-class.c index c26cc31c..1afd6e8b 100644 --- a/src/lib/trace-ir/stream-class.c +++ b/src/lib/trace-ir/stream-class.c @@ -44,6 +44,7 @@ #include "stream-class.h" #include "trace.h" #include "utils.h" +#include "lib/value.h" #include "lib/func-status.h" #define BT_ASSERT_PRE_DEV_STREAM_CLASS_HOT(_sc) \ @@ -56,6 +57,7 @@ void destroy_stream_class(struct bt_object *obj) BT_LIB_LOGD("Destroying stream class: %!+S", stream_class); BT_LOGD_STR("Putting default clock class."); + BT_OBJECT_PUT_REF_AND_RESET(stream_class->user_attributes); BT_OBJECT_PUT_REF_AND_RESET(stream_class->default_clock_class); if (stream_class->event_classes) { @@ -126,12 +128,17 @@ struct bt_stream_class *create_stream_class_with_id( bt_object_init_shared_with_parent(&stream_class->base, destroy_stream_class); + stream_class->user_attributes = bt_value_map_create(); + if (!stream_class->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } stream_class->name.str = g_string_new(NULL); if (!stream_class->name.str) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - ret = -1; - goto end; + goto error; } stream_class->id = id; @@ -406,6 +413,9 @@ void _bt_stream_class_freeze(const struct bt_stream_class *stream_class) { /* The field classes and default clock class are already frozen */ BT_ASSERT(stream_class); + BT_LIB_LOGD("Freezing stream class's user attributes: %!+v", + stream_class->user_attributes); + bt_value_freeze(stream_class->user_attributes); BT_LIB_LOGD("Freezing stream class: %!+S", stream_class); ((struct bt_stream_class *) stream_class)->frozen = true; } @@ -608,6 +618,34 @@ void bt_stream_class_set_assigns_automatic_stream_id( "assignment property: %!+S", stream_class); } +const struct bt_value *bt_stream_class_borrow_user_attributes_const( + const struct bt_stream_class *stream_class) +{ + BT_ASSERT_PRE_DEV_NON_NULL(stream_class, "Stream class"); + return stream_class->user_attributes; +} + +struct bt_value *bt_stream_class_borrow_user_attributes( + struct bt_stream_class *stream_class) +{ + return (void *) bt_stream_class_borrow_user_attributes_const( + (void *) stream_class); +} + +void bt_stream_class_set_user_attributes( + struct bt_stream_class *stream_class, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_STREAM_CLASS_HOT(stream_class); + bt_object_put_no_null_check(stream_class->user_attributes); + stream_class->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(stream_class->user_attributes); +} + void bt_stream_class_get_ref(const struct bt_stream_class *stream_class) { bt_object_get_ref(stream_class); diff --git a/src/lib/trace-ir/stream-class.h b/src/lib/trace-ir/stream-class.h index fe423d76..60bd5719 100644 --- a/src/lib/trace-ir/stream-class.h +++ b/src/lib/trace-ir/stream-class.h @@ -39,6 +39,9 @@ struct bt_stream_class { struct bt_object base; + /* Owned by this */ + struct bt_value *user_attributes; + struct { GString *str; diff --git a/src/lib/trace-ir/stream.c b/src/lib/trace-ir/stream.c index 23692399..c567768f 100644 --- a/src/lib/trace-ir/stream.c +++ b/src/lib/trace-ir/stream.c @@ -40,6 +40,7 @@ #include "stream-class.h" #include "stream.h" #include "trace.h" +#include "lib/value.h" #include "lib/func-status.h" #define BT_ASSERT_PRE_DEV_STREAM_HOT(_stream) \ @@ -51,6 +52,7 @@ void destroy_stream(struct bt_object *obj) struct bt_stream *stream = (void *) obj; BT_LIB_LOGD("Destroying stream object: %!+s", stream); + BT_OBJECT_PUT_REF_AND_RESET(stream->user_attributes); if (stream->name.str) { g_string_free(stream->name.str, TRUE); @@ -118,6 +120,13 @@ struct bt_stream *create_stream_with_id(struct bt_stream_class *stream_class, } bt_object_init_shared_with_parent(&stream->base, destroy_stream); + stream->user_attributes = bt_value_map_create(); + if (!stream->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } + stream->name.str = g_string_new(NULL); if (!stream->name.str) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); @@ -229,10 +238,38 @@ BT_HIDDEN void _bt_stream_freeze(const struct bt_stream *stream) { BT_ASSERT(stream); + BT_LIB_LOGD("Freezing stream's user attributes: %!+v", + stream->user_attributes); + bt_value_freeze(stream->user_attributes); BT_LIB_LOGD("Freezing stream: %!+s", stream); ((struct bt_stream *) stream)->frozen = true; } +const struct bt_value *bt_stream_borrow_user_attributes_const( + const struct bt_stream *stream) +{ + BT_ASSERT_PRE_DEV_NON_NULL(stream, "Stream"); + return stream->user_attributes; +} + +struct bt_value *bt_stream_borrow_user_attributes(struct bt_stream *stream) +{ + return (void *) bt_stream_borrow_user_attributes_const((void *) stream); +} + +void bt_stream_set_user_attributes(struct bt_stream *stream, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(stream, "Stream"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_STREAM_HOT(stream); + bt_object_put_no_null_check(stream->user_attributes); + stream->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(stream->user_attributes); +} + void bt_stream_get_ref(const struct bt_stream *stream) { bt_object_get_ref(stream); diff --git a/src/lib/trace-ir/stream.h b/src/lib/trace-ir/stream.h index cd320ca1..23f69c27 100644 --- a/src/lib/trace-ir/stream.h +++ b/src/lib/trace-ir/stream.h @@ -38,6 +38,9 @@ struct bt_stream; struct bt_stream { struct bt_object base; + /* Owned by this */ + struct bt_value *user_attributes; + /* Owned by this */ struct bt_stream_class *class; diff --git a/src/lib/trace-ir/trace-class.c b/src/lib/trace-ir/trace-class.c index 78265b41..cd5d6f82 100644 --- a/src/lib/trace-ir/trace-class.c +++ b/src/lib/trace-ir/trace-class.c @@ -53,6 +53,7 @@ #include "stream.h" #include "trace.h" #include "utils.h" +#include "lib/value.h" #include "lib/func-status.h" struct bt_trace_class_destruction_listener_elem { @@ -69,6 +70,8 @@ void destroy_trace_class(struct bt_object *obj) struct bt_trace_class *tc = (void *) obj; BT_LIB_LOGD("Destroying trace class object: %!+T", tc); + BT_OBJECT_PUT_REF_AND_RESET(tc->user_attributes); + /* * Call destruction listener functions so that everything else * still exists in the trace class. @@ -131,6 +134,12 @@ struct bt_trace_class *bt_trace_class_create(bt_self_component *self_comp) } bt_object_init_shared_with_parent(&tc->base, destroy_trace_class); + tc->user_attributes = bt_value_map_create(); + if (!tc->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } tc->stream_classes = g_ptr_array_new_with_free_func( (GDestroyNotify) bt_object_try_spec_release); @@ -305,6 +314,33 @@ void bt_trace_class_set_assigns_automatic_stream_class_id(struct bt_trace_class "assignment property: %!+T", tc); } +const struct bt_value *bt_trace_class_borrow_user_attributes_const( + const struct bt_trace_class *trace_class) +{ + BT_ASSERT_PRE_DEV_NON_NULL(trace_class, "Trace class"); + return trace_class->user_attributes; +} + +struct bt_value *bt_trace_class_borrow_user_attributes( + struct bt_trace_class *trace_class) +{ + return (void *) bt_trace_class_borrow_user_attributes_const( + (void *) trace_class); +} + +void bt_trace_class_set_user_attributes(struct bt_trace_class *trace_class, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_TRACE_CLASS_HOT(trace_class); + bt_object_put_no_null_check(trace_class->user_attributes); + trace_class->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(trace_class->user_attributes); +} + void bt_trace_class_get_ref(const struct bt_trace_class *trace_class) { bt_object_get_ref(trace_class); diff --git a/src/lib/trace-ir/trace-class.h b/src/lib/trace-ir/trace-class.h index 0b06bf32..28123a91 100644 --- a/src/lib/trace-ir/trace-class.h +++ b/src/lib/trace-ir/trace-class.h @@ -43,6 +43,9 @@ struct bt_trace_class { struct bt_object base; + /* Owned by this */ + struct bt_value *user_attributes; + /* Array of `struct bt_stream_class *` */ GPtrArray *stream_classes; diff --git a/src/lib/trace-ir/trace.c b/src/lib/trace-ir/trace.c index 7b1749eb..9891d12b 100644 --- a/src/lib/trace-ir/trace.c +++ b/src/lib/trace-ir/trace.c @@ -55,6 +55,7 @@ #include "trace-class.h" #include "trace.h" #include "utils.h" +#include "lib/value.h" #include "lib/func-status.h" struct bt_trace_destruction_listener_elem { @@ -71,6 +72,7 @@ void destroy_trace(struct bt_object *obj) struct bt_trace *trace = (void *) obj; BT_LIB_LOGD("Destroying trace object: %!+t", trace); + BT_OBJECT_PUT_REF_AND_RESET(trace->user_attributes); /* * Call destruction listener functions so that everything else @@ -153,6 +155,13 @@ struct bt_trace *bt_trace_create(struct bt_trace_class *tc) } bt_object_init_shared(&trace->base, destroy_trace); + trace->user_attributes = bt_value_map_create(); + if (!trace->user_attributes) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to create a map value object."); + goto error; + } + trace->streams = g_ptr_array_new_with_free_func( (GDestroyNotify) bt_object_try_spec_release); if (!trace->streams) { @@ -482,6 +491,9 @@ void _bt_trace_freeze(const struct bt_trace *trace) BT_ASSERT(trace); BT_LIB_LOGD("Freezing trace's class: %!+T", trace->class); bt_trace_class_freeze(trace->class); + BT_LIB_LOGD("Freezing trace's user attributes: %!+v", + trace->user_attributes); + bt_value_freeze(trace->user_attributes); BT_LIB_LOGD("Freezing trace: %!+t", trace); ((struct bt_trace *) trace)->frozen = true; } @@ -535,6 +547,32 @@ const struct bt_trace_class *bt_trace_borrow_class_const( return bt_trace_borrow_class((void *) trace); } +const struct bt_value *bt_trace_borrow_user_attributes_const( + const struct bt_trace *trace) +{ + BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace"); + return trace->user_attributes; +} + +struct bt_value *bt_trace_borrow_user_attributes(struct bt_trace *trace) +{ + return (void *) bt_trace_borrow_user_attributes_const((void *) trace); +} + +void bt_trace_set_user_attributes( + struct bt_trace *trace, + const struct bt_value *user_attributes) +{ + BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes"); + BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP, + "User attributes object is not a map value object."); + BT_ASSERT_PRE_DEV_TRACE_HOT(trace); + bt_object_put_no_null_check(trace->user_attributes); + trace->user_attributes = (void *) user_attributes; + bt_object_get_no_null_check(trace->user_attributes); +} + void bt_trace_get_ref(const struct bt_trace *trace) { bt_object_get_ref(trace); diff --git a/src/lib/trace-ir/trace.h b/src/lib/trace-ir/trace.h index 288bfa36..2978e995 100644 --- a/src/lib/trace-ir/trace.h +++ b/src/lib/trace-ir/trace.h @@ -45,6 +45,9 @@ struct bt_trace { struct bt_object base; + /* Owned by this */ + struct bt_value *user_attributes; + /* Owned by this */ struct bt_trace_class *class; -- 2.34.1