X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Ftrace-ir%2Ftrace.c;h=da8d7d75fcc14a89a5a052e7b15124e7408dda42;hb=3fadfbc0c91f82c46bd36e6e0657ea93570c9db1;hp=afc37d9cfbf43dbc08fd8b15f5d53ee9585dc44b;hpb=da91b29ad2964b85601e25843f1dca92f6c97406;p=babeltrace.git diff --git a/lib/trace-ir/trace.c b/lib/trace-ir/trace.c index afc37d9c..da8d7d75 100644 --- a/lib/trace-ir/trace.c +++ b/lib/trace-ir/trace.c @@ -1,12 +1,7 @@ /* - * trace.c - * - * Babeltrace trace IR - Trace - * + * Copyright 2017-2018 Philippe Proulx * Copyright 2014 Jérémie Galarneau * - * Author: Jérémie Galarneau - * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -27,40 +22,41 @@ */ #define BT_LOG_TAG "TRACE" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -struct bt_trace_is_static_listener_elem { - bt_trace_is_static_listener func; - bt_trace_listener_removed removed; +struct bt_trace_destruction_listener_elem { + bt_trace_destruction_listener_func func; void *data; }; @@ -75,75 +71,80 @@ void destroy_trace(struct bt_object *obj) BT_LIB_LOGD("Destroying trace object: %!+t", trace); /* - * Call remove listeners first so that everything else still - * exists in the trace. + * Call destruction listener functions so that everything else + * still exists in the trace. */ - if (trace->is_static_listeners) { - size_t i; - - for (i = 0; i < trace->is_static_listeners->len; i++) { - struct bt_trace_is_static_listener_elem elem = - g_array_index(trace->is_static_listeners, - struct bt_trace_is_static_listener_elem, i); - - if (elem.removed) { - elem.removed(trace, elem.data); + if (trace->destruction_listeners) { + uint64_t i; + BT_LIB_LOGV("Calling trace destruction listener(s): %!+t", trace); + + /* + * The trace's reference count is 0 if we're here. Increment + * it to avoid a double-destroy (possibly infinitely recursive). + * This could happen for example if a destruction listener did + * bt_object_get_ref() (or anything that causes + * bt_object_get_ref() to be called) on the trace (ref. + * count goes from 0 to 1), and then bt_object_put_ref(): the + * reference count would go from 1 to 0 again and this function + * would be called again. + */ + trace->base.ref_count++; + + /* Call all the trace destruction listeners */ + for (i = 0; i < trace->destruction_listeners->len; i++) { + struct bt_trace_destruction_listener_elem elem = + g_array_index(trace->destruction_listeners, + struct bt_trace_destruction_listener_elem, i); + + if (elem.func) { + elem.func(trace, elem.data); } - } - g_array_free(trace->is_static_listeners, TRUE); - } - - bt_object_pool_finalize(&trace->packet_header_field_pool); - - if (trace->environment) { - BT_LOGD_STR("Destroying environment attributes."); - bt_attributes_destroy(trace->environment); + /* + * The destruction listener should not have kept a + * reference to the trace. + */ + BT_ASSERT_PRE(trace->base.ref_count == 1, "Destruction listener kept a reference to the trace being destroyed: %![trace-]+t", trace); + } + g_array_free(trace->destruction_listeners, TRUE); + trace->destruction_listeners = NULL; } if (trace->name.str) { g_string_free(trace->name.str, TRUE); + trace->name.str = NULL; + trace->name.value = NULL; } if (trace->streams) { BT_LOGD_STR("Destroying streams."); g_ptr_array_free(trace->streams, TRUE); - } - - if (trace->stream_classes) { - BT_LOGD_STR("Destroying stream classes."); - g_ptr_array_free(trace->stream_classes, TRUE); + trace->streams = NULL; } if (trace->stream_classes_stream_count) { g_hash_table_destroy(trace->stream_classes_stream_count); + trace->stream_classes_stream_count = NULL; } - BT_LOGD_STR("Putting packet header field classe."); - bt_object_put_ref(trace->packet_header_fc); + BT_LOGD_STR("Putting trace's class."); + bt_object_put_ref(trace->class); + trace->class = NULL; g_free(trace); } -static -void free_packet_header_field(struct bt_field_wrapper *field_wrapper, - struct bt_trace *trace) -{ - bt_field_wrapper_destroy(field_wrapper); -} - -struct bt_trace *bt_trace_create(void) +struct bt_trace *bt_trace_create(struct bt_trace_class *tc) { struct bt_trace *trace = NULL; - int ret; - BT_LOGD_STR("Creating default trace object."); + BT_LIB_LOGD("Creating trace object: %![tc-]+T", tc); trace = g_new0(struct bt_trace, 1); if (!trace) { BT_LOGE_STR("Failed to allocate one trace."); goto error; } - bt_object_init_shared_with_parent(&trace->base, destroy_trace); + bt_object_init_shared(&trace->base, destroy_trace); trace->streams = g_ptr_array_new_with_free_func( (GDestroyNotify) bt_object_try_spec_release); if (!trace->streams) { @@ -151,13 +152,6 @@ struct bt_trace *bt_trace_create(void) goto error; } - trace->stream_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_object_try_spec_release); - if (!trace->stream_classes) { - BT_LOGE_STR("Failed to allocate one GPtrArray."); - goto error; - } - trace->stream_classes_stream_count = g_hash_table_new(g_direct_hash, g_direct_equal); if (!trace->stream_classes_stream_count) { @@ -171,30 +165,15 @@ struct bt_trace *bt_trace_create(void) goto error; } - trace->environment = bt_attributes_create(); - if (!trace->environment) { - BT_LOGE_STR("Cannot create empty attributes object."); - goto error; - } - - trace->is_static_listeners = g_array_new(FALSE, TRUE, - sizeof(struct bt_trace_is_static_listener_elem)); - if (!trace->is_static_listeners) { + trace->destruction_listeners = g_array_new(FALSE, TRUE, + sizeof(struct bt_trace_destruction_listener_elem)); + if (!trace->destruction_listeners) { BT_LOGE_STR("Failed to allocate one GArray."); goto error; } - trace->assigns_automatic_stream_class_id = true; - ret = bt_object_pool_initialize(&trace->packet_header_field_pool, - (bt_object_pool_new_object_func) bt_field_wrapper_new, - (bt_object_pool_destroy_object_func) free_packet_header_field, - trace); - if (ret) { - BT_LOGE("Failed to initialize packet header field pool: ret=%d", - ret); - goto error; - } - + trace->class = tc; + bt_object_get_no_null_check(trace->class); BT_LIB_LOGD("Created trace object: %!+t", trace); goto end; @@ -205,13 +184,13 @@ end: return trace; } -const char *bt_trace_get_name(struct bt_trace *trace) +const char *bt_trace_get_name(const struct bt_trace *trace) { BT_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->name.value; } -int bt_trace_set_name(struct bt_trace *trace, const char *name) +enum bt_trace_status bt_trace_set_name(struct bt_trace *trace, const char *name) { BT_ASSERT_PRE_NON_NULL(trace, "Trace"); BT_ASSERT_PRE_NON_NULL(name, "Name"); @@ -219,147 +198,10 @@ int bt_trace_set_name(struct bt_trace *trace, const char *name) g_string_assign(trace->name.str, name); trace->name.value = trace->name.str->str; BT_LIB_LOGV("Set trace's name: %!+t", trace); - return 0; -} - -bt_uuid bt_trace_get_uuid(struct bt_trace *trace) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - return trace->uuid.value; -} - -int bt_trace_set_uuid(struct bt_trace *trace, bt_uuid uuid) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(uuid, "UUID"); - BT_ASSERT_PRE_TRACE_HOT(trace); - memcpy(trace->uuid.uuid, uuid, BABELTRACE_UUID_LEN); - trace->uuid.value = trace->uuid.uuid; - BT_LIB_LOGV("Set trace's UUID: %!+t", trace); - return 0; -} - -BT_ASSERT_FUNC -static -bool trace_has_environment_entry(struct bt_trace *trace, const char *name) -{ - BT_ASSERT(trace); - - return bt_attributes_borrow_field_value_by_name( - trace->environment, name) != NULL; + return BT_TRACE_STATUS_OK; } -static -int set_environment_entry(struct bt_trace *trace, const char *name, - struct bt_private_value *value) -{ - int ret; - - BT_ASSERT(trace); - BT_ASSERT(name); - BT_ASSERT(value); - BT_ASSERT_PRE(!trace->frozen || - !trace_has_environment_entry(trace, name), - "Trace is frozen: cannot replace environment entry: " - "%![trace-]+t, entry-name=\"%s\"", trace, name); - ret = bt_attributes_set_field_value(trace->environment, name, - value); - bt_value_freeze(bt_value_borrow_from_private(value)); - if (ret) { - BT_LIB_LOGE("Cannot set trace's environment entry: " - "%![trace-]+t, entry-name=\"%s\"", trace, name); - } else { - BT_LIB_LOGV("Set trace's environment entry: " - "%![trace-]+t, entry-name=\"%s\"", trace, name); - } - - return ret; -} - -int bt_trace_set_environment_entry_string(struct bt_trace *trace, - const char *name, const char *value) -{ - int ret; - struct bt_private_value *value_obj; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - value_obj = bt_private_value_string_create_init(value); - if (!value_obj) { - BT_LOGE_STR("Cannot create a string value object."); - ret = -1; - goto end; - } - - /* set_environment_entry() logs errors */ - ret = set_environment_entry(trace, name, value_obj); - -end: - bt_object_put_ref(value_obj); - return ret; -} - -int bt_trace_set_environment_entry_integer( - struct bt_trace *trace, const char *name, int64_t value) -{ - int ret; - struct bt_private_value *value_obj; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - value_obj = bt_private_value_integer_create_init(value); - if (!value_obj) { - BT_LOGE_STR("Cannot create an integer value object."); - ret = -1; - goto end; - } - - /* set_environment_entry() logs errors */ - ret = set_environment_entry(trace, name, value_obj); - -end: - bt_object_put_ref(value_obj); - return ret; -} - -uint64_t bt_trace_get_environment_entry_count(struct bt_trace *trace) -{ - int64_t ret; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - ret = bt_attributes_get_count(trace->environment); - BT_ASSERT(ret >= 0); - return (uint64_t) ret; -} - -void bt_trace_borrow_environment_entry_by_index( - struct bt_trace *trace, uint64_t index, - const char **name, struct bt_value **value) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_VALID_INDEX(index, - bt_attributes_get_count(trace->environment)); - *value = bt_value_borrow_from_private( - bt_attributes_borrow_field_value(trace->environment, index)); - BT_ASSERT(*value); - *name = bt_attributes_get_field_name(trace->environment, index); - BT_ASSERT(*name); -} - -struct bt_value *bt_trace_borrow_environment_entry_value_by_name( - struct bt_trace *trace, const char *name) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - return bt_value_borrow_from_private( - bt_attributes_borrow_field_value_by_name(trace->environment, - name)); -} - -uint64_t bt_trace_get_stream_count(struct bt_trace *trace) +uint64_t bt_trace_get_stream_count(const struct bt_trace *trace) { BT_ASSERT_PRE_NON_NULL(trace, "Trace"); return (uint64_t) trace->streams->len; @@ -373,8 +215,14 @@ struct bt_stream *bt_trace_borrow_stream_by_index( return g_ptr_array_index(trace->streams, index); } -struct bt_stream *bt_trace_borrow_stream_by_id( - struct bt_trace *trace, uint64_t id) +const struct bt_stream *bt_trace_borrow_stream_by_index_const( + const struct bt_trace *trace, uint64_t index) +{ + return bt_trace_borrow_stream_by_index((void *) trace, index); +} + +struct bt_stream *bt_trace_borrow_stream_by_id(struct bt_trace *trace, + uint64_t id) { struct bt_stream *stream = NULL; uint64_t i; @@ -395,231 +243,94 @@ end: return stream; } -uint64_t bt_trace_get_stream_class_count(struct bt_trace *trace) +const struct bt_stream *bt_trace_borrow_stream_by_id_const( + const struct bt_trace *trace, uint64_t id) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - return (uint64_t) trace->stream_classes->len; + return bt_trace_borrow_stream_by_id((void *) trace, id); } -struct bt_stream_class *bt_trace_borrow_stream_class_by_index( - struct bt_trace *trace, uint64_t index) +enum bt_trace_status bt_trace_add_destruction_listener( + const struct bt_trace *c_trace, + bt_trace_destruction_listener_func listener, + void *data, uint64_t *listener_id) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_VALID_INDEX(index, trace->stream_classes->len); - return g_ptr_array_index(trace->stream_classes, index); -} - -struct bt_stream_class *bt_trace_borrow_stream_class_by_id( - struct bt_trace *trace, uint64_t id) -{ - struct bt_stream_class *stream_class = NULL; + struct bt_trace *trace = (void *) c_trace; uint64_t i; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - - for (i = 0; i < trace->stream_classes->len; i++) { - struct bt_stream_class *stream_class_candidate = - g_ptr_array_index(trace->stream_classes, i); - - if (stream_class_candidate->id == id) { - stream_class = stream_class_candidate; - goto end; - } - } - -end: - return stream_class; -} - -struct bt_field_class *bt_trace_borrow_packet_header_field_class( - struct bt_trace *trace) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - return trace->packet_header_fc; -} - -int bt_trace_set_packet_header_field_class(struct bt_trace *trace, - struct bt_field_class *field_class) -{ - int ret; - struct bt_resolve_field_path_context resolve_ctx = { - .packet_header = field_class, - .packet_context = NULL, - .event_header = NULL, - .event_common_context = NULL, - .event_specific_context = NULL, - .event_payload = NULL, - }; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(field_class, "Field class"); - BT_ASSERT_PRE_TRACE_HOT(trace); - BT_ASSERT_PRE(bt_field_class_get_type(field_class) == - BT_FIELD_CLASS_TYPE_STRUCTURE, - "Packet header field classe is not a structure field classe: %!+F", - field_class); - ret = bt_resolve_field_paths(field_class, &resolve_ctx); - if (ret) { - goto end; - } - - bt_field_class_make_part_of_trace(field_class); - bt_object_put_ref(trace->packet_header_fc); - trace->packet_header_fc = bt_object_get_ref(field_class); - bt_field_class_freeze(field_class); - BT_LIB_LOGV("Set trace's packet header field classe: %!+t", trace); - -end: - return ret; -} - -bt_bool bt_trace_is_static(struct bt_trace *trace) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - return (bt_bool) trace->is_static; -} - -int bt_trace_make_static(struct bt_trace *trace) -{ - uint64_t i; - - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - trace->is_static = true; - bt_trace_freeze(trace); - BT_LIB_LOGV("Trace is now static: %!+t", trace); - - /* Call all the "trace is static" listeners */ - for (i = 0; i < trace->is_static_listeners->len; i++) { - struct bt_trace_is_static_listener_elem elem = - g_array_index(trace->is_static_listeners, - struct bt_trace_is_static_listener_elem, i); - - if (elem.func) { - elem.func(trace, elem.data); - } - } - - return 0; -} - -int bt_trace_add_is_static_listener(struct bt_trace *trace, - bt_trace_is_static_listener listener, - bt_trace_listener_removed listener_removed, void *data, - uint64_t *listener_id) -{ - uint64_t i; - struct bt_trace_is_static_listener_elem new_elem = { + struct bt_trace_destruction_listener_elem new_elem = { .func = listener, - .removed = listener_removed, .data = data, }; BT_ASSERT_PRE_NON_NULL(trace, "Trace"); BT_ASSERT_PRE_NON_NULL(listener, "Listener"); - BT_ASSERT_PRE(!trace->is_static, - "Trace is already static: %!+t", trace); - BT_ASSERT_PRE(trace->in_remove_listener, - "Cannot call this function while executing a " - "remove listener: %!+t", trace); /* Find the next available spot */ - for (i = 0; i < trace->is_static_listeners->len; i++) { - struct bt_trace_is_static_listener_elem elem = - g_array_index(trace->is_static_listeners, - struct bt_trace_is_static_listener_elem, i); + for (i = 0; i < trace->destruction_listeners->len; i++) { + struct bt_trace_destruction_listener_elem elem = + g_array_index(trace->destruction_listeners, + struct bt_trace_destruction_listener_elem, i); if (!elem.func) { break; } } - if (i == trace->is_static_listeners->len) { - g_array_append_val(trace->is_static_listeners, new_elem); + if (i == trace->destruction_listeners->len) { + g_array_append_val(trace->destruction_listeners, new_elem); } else { - g_array_insert_val(trace->is_static_listeners, i, new_elem); + g_array_insert_val(trace->destruction_listeners, i, new_elem); } if (listener_id) { *listener_id = i; } - BT_LIB_LOGV("Added \"trace is static\" listener: " - "%![trace-]+t, listener-id=%" PRIu64, trace, i); - return 0; + BT_LIB_LOGV("Added destruction listener: " "%![trace-]+t, " + "listener-id=%" PRIu64, trace, i); + return BT_TRACE_STATUS_OK; } BT_ASSERT_PRE_FUNC static -bool has_listener_id(struct bt_trace *trace, uint64_t listener_id) +bool has_listener_id(const struct bt_trace *trace, uint64_t listener_id) { - BT_ASSERT(listener_id < trace->is_static_listeners->len); - return (&g_array_index(trace->is_static_listeners, - struct bt_trace_is_static_listener_elem, + BT_ASSERT(listener_id < trace->destruction_listeners->len); + return (&g_array_index(trace->destruction_listeners, + struct bt_trace_destruction_listener_elem, listener_id))->func != NULL; } -int bt_trace_remove_is_static_listener( - struct bt_trace *trace, uint64_t listener_id) +enum bt_trace_status bt_trace_remove_destruction_listener( + const struct bt_trace *c_trace, uint64_t listener_id) { - struct bt_trace_is_static_listener_elem *elem; + struct bt_trace *trace = (void *) c_trace; + struct bt_trace_destruction_listener_elem *elem; BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE(!trace->is_static, - "Trace is already static: %!+t", trace); - BT_ASSERT_PRE(trace->in_remove_listener, - "Cannot call this function while executing a " - "remove listener: %!+t", trace); BT_ASSERT_PRE(has_listener_id(trace, listener_id), - "Trace has no such \"trace is static\" listener ID: " + "Trace has no such trace destruction listener ID: " "%![trace-]+t, %" PRIu64, trace, listener_id); - elem = &g_array_index(trace->is_static_listeners, - struct bt_trace_is_static_listener_elem, + elem = &g_array_index(trace->destruction_listeners, + struct bt_trace_destruction_listener_elem, listener_id); BT_ASSERT(elem->func); - if (elem->removed) { - /* Call remove listener */ - BT_LIB_LOGV("Calling remove listener: " - "%![trace-]+t, listener-id=%" PRIu64, - trace, listener_id); - trace->in_remove_listener = true; - elem->removed(trace, elem->data); - trace->in_remove_listener = false; - } - elem->func = NULL; - elem->removed = NULL; elem->data = NULL; - BT_LIB_LOGV("Removed \"trace is static\" listener: " + BT_LIB_LOGV("Removed \"trace destruction listener: " "%![trace-]+t, listener-id=%" PRIu64, trace, listener_id); - return 0; + return BT_TRACE_STATUS_OK; } BT_HIDDEN -void _bt_trace_freeze(struct bt_trace *trace) +void _bt_trace_freeze(const struct bt_trace *trace) { - /* The packet header field classe is already frozen */ BT_ASSERT(trace); + BT_LIB_LOGD("Freezing trace's class: %!+T", trace->class); + bt_trace_class_freeze(trace->class); BT_LIB_LOGD("Freezing trace: %!+t", trace); - trace->frozen = true; -} - -bt_bool bt_trace_assigns_automatic_stream_class_id(struct bt_trace *trace) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - return (bt_bool) trace->assigns_automatic_stream_class_id; -} - -int bt_trace_set_assigns_automatic_stream_class_id( - struct bt_trace *trace, bt_bool value) -{ - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_TRACE_HOT(trace); - trace->assigns_automatic_stream_class_id = (bool) value; - BT_LIB_LOGV("Set trace's automatic stream class ID " - "assignment property: %!+t", trace); - return 0; + ((struct bt_trace *) trace)->frozen = true; } BT_HIDDEN @@ -642,8 +353,8 @@ void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream) } BT_HIDDEN -uint64_t bt_trace_get_automatic_stream_id(struct bt_trace *trace, - struct bt_stream_class *stream_class) +uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace, + const struct bt_stream_class *stream_class) { gpointer orig_key; gpointer value; @@ -658,3 +369,25 @@ uint64_t bt_trace_get_automatic_stream_id(struct bt_trace *trace, return id; } + +struct bt_trace_class *bt_trace_borrow_class(struct bt_trace *trace) +{ + BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + return trace->class; +} + +const struct bt_trace_class *bt_trace_borrow_class_const( + const struct bt_trace *trace) +{ + return bt_trace_borrow_class((void *) trace); +} + +void bt_trace_get_ref(const struct bt_trace *trace) +{ + bt_object_get_ref(trace); +} + +void bt_trace_put_ref(const struct bt_trace *trace) +{ + bt_object_put_ref(trace); +}