lib: add user attributes property to metadata, stream, and trace objects
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 14 Aug 2019 03:21:46 +0000 (23:21 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 15 Aug 2019 15:41:44 +0000 (11:41 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: Ibb12de23fb2c4d752b13381769d2ac1841eb5dc9
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1922
Tested-by: jenkins <jenkins@lttng.org>
28 files changed:
include/babeltrace2/trace-ir/clock-class-const.h
include/babeltrace2/trace-ir/clock-class.h
include/babeltrace2/trace-ir/event-class-const.h
include/babeltrace2/trace-ir/event-class.h
include/babeltrace2/trace-ir/field-class-const.h
include/babeltrace2/trace-ir/field-class.h
include/babeltrace2/trace-ir/stream-class-const.h
include/babeltrace2/trace-ir/stream-class.h
include/babeltrace2/trace-ir/stream-const.h
include/babeltrace2/trace-ir/stream.h
include/babeltrace2/trace-ir/trace-class-const.h
include/babeltrace2/trace-ir/trace-class.h
include/babeltrace2/trace-ir/trace-const.h
include/babeltrace2/trace-ir/trace.h
src/lib/trace-ir/clock-class.c
src/lib/trace-ir/clock-class.h
src/lib/trace-ir/event-class.c
src/lib/trace-ir/event-class.h
src/lib/trace-ir/field-class.c
src/lib/trace-ir/field-class.h
src/lib/trace-ir/stream-class.c
src/lib/trace-ir/stream-class.h
src/lib/trace-ir/stream.c
src/lib/trace-ir/stream.h
src/lib/trace-ir/trace-class.c
src/lib/trace-ir/trace-class.h
src/lib/trace-ir/trace.c
src/lib/trace-ir/trace.h

index b4affd536a19d6f0cece9012da00fe524fa6078b..6316f83f4e2e3d28ad2089a596560ce8ddfb399a 100644 (file)
@@ -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);
 
index f3cb1d936361794986cbb304128ccf047ee41ee3..5d0c5987c5fbe64ebfefe9d0727bb9532a0bbf02 100644 (file)
@@ -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,
index 80f33eade31898b87ba052263d54a120cff242ca..5b686dc6c405dc773b8d7e06196a2fff94d2149c 100644 (file)
@@ -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);
 
index fa225019d6371caa7c83bf851e1e70393bb11049..e435d3876608665443f6f1fecba14c12bca11bd3 100644 (file)
@@ -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);
 
index 27f22c17af52f3e51ef8644b62c488c70c4536c2..bc9b823bd1c57042f7ccbcdd37118ea9cb093bb3 100644 (file)
@@ -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);
index 083facbe7b3d6fa79313bb2e6b4d428a6ce224a4..847064b924b046769c1cf453d928ab36f458bb23 100644 (file)
 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
index c21d0e7554605ed56a38d01b55902c8f5312bd9b..7a7077b946d3acdc8a6e504c656ab48daf7b3c1e 100644 (file)
@@ -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);
 
index 469fe0196123f7b136fa6cf2ae49d3993f417824..58bdbdc49cfd3e631715845d1b0bc6cffc2b4fee 100644 (file)
@@ -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);
 
index 2465343cd8c8ff32bdf2d67709219def5dac6b6f..bf8098303815e591dacad30909f7cb013790cc82 100644 (file)
@@ -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);
 
index 0ef1b84d6c58bde0fc7195a401737648d9ac1174..416e42cec15c4c128d09a97622f80846b579fdb1 100644 (file)
@@ -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);
index 023ce6506a4ed14b393634f61bbfa2a37b972c8c..6ad9a9d7d3114b2b895e130a3d0fecd60a51654e 100644 (file)
@@ -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);
 
index 52d34c6787db5973fa85746a231ca487ac23e99c..d90ba2c9c825ce5c1308b29592f8b91b1185c008 100644 (file)
@@ -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);
 
index f437aec0428dd1fbde87756cdc502a87da40c59f..d4410a2dd1db59977c7ed5e98b9a94fbbe0009e6 100644 (file)
@@ -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);
 
index 7cd5f3ff6ae2896ffcc67607d19263707fec7994..4d17c48406ef9c9449643075d86745a6a612b015 100644 (file)
@@ -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,
index 34e3a87b26d4d480bafc7963db8b03b6e821388c..e982ad7f0fafc74e48ba733db4635508f15c1d4e 100644 (file)
@@ -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);
index b39183c2c94db206160cc61b6e022e846aa45700..b3eb14ff83a57dbac34c15e2472474296fa43c08 100644 (file)
@@ -42,6 +42,9 @@
 struct bt_clock_class {
        struct bt_object base;
 
+       /* Owned by this */
+       struct bt_value *user_attributes;
+
        struct {
                GString *str;
 
index c5e5230e160d049b46f80da2445716de274762bb..ae7653e93a7679e662fe4e4c08b0dff69d6c7fcd 100644 (file)
@@ -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);
index 66d536706072a7171f014d9431d224f4c7842d69..83734eed1c7b9c313475fc7a36ca5d3586506d10 100644 (file)
@@ -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;
 
index 78e30f4dc0109e916a921b5f24e07e2832418c2e..97409dc98222e21d68a673395a7b1d7d71dc8d5e 100644 (file)
@@ -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);
index 77eece7bbe8fa2a12ece112178fde1c87f36484e..e7eff691ed746619fd377e934d0ea4fda51c24e6 100644 (file)
@@ -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;
 
index c26cc31cde6c679434f30277122092a9f2a6d172..1afd6e8b7a2702bb6e1618b914346a32007c125a 100644 (file)
@@ -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);
index fe423d7683d99e66855f5fd5503e4c1e1e1651ee..60bd571949b80b593952b97e1138cde08b0f53be 100644 (file)
@@ -39,6 +39,9 @@
 struct bt_stream_class {
        struct bt_object base;
 
+       /* Owned by this */
+       struct bt_value *user_attributes;
+
        struct {
                GString *str;
 
index 23692399f6b35cc0dca4279295c4eba19fa441fd..c567768fe03f47669ba15781e251f5cf9752cc14 100644 (file)
@@ -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);
index cd320ca16dc62ba282cf6b22023f33fd4a85a427..23f69c274d742e5329b51348eb8a5636dc47e1c4 100644 (file)
@@ -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;
 
index 78265b415d8099a51dd5d23dd3e6f897e6c552bc..cd5d6f829563a77dfe947950afe5e90b7aabe680 100644 (file)
@@ -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);
index 0b06bf32fda0a8fa27fa3e645922591e50053c89..28123a91d244998468613f527d298b71810f034f 100644 (file)
@@ -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;
 
index 7b1749ebf847730aa02cf1bf584c2f1ac436a2a5..9891d12b224dc53131fc94f0f863b11e0802dd11 100644 (file)
@@ -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);
index 288bfa36cdca207d6ab3683d81fdbeeabeee0062..2978e9953c986549213a922faf635349eeda8444 100644 (file)
@@ -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;
 
This page took 0.043799 seconds and 4 git commands to generate.