X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=formats%2Fctf%2Fir%2Ftrace.c;h=32ceca636f813e44aae98da61df8a41de5e2c5c7;hp=4d27b833be4c0c0ca93330eb6e500ec5fc961194;hb=f3985ab106d89d8e764c1a8dd0c8bda09b755d10;hpb=f67f3a6e48bc72149e6a9b370da39abddc2c57a6 diff --git a/formats/ctf/ir/trace.c b/formats/ctf/ir/trace.c index 4d27b833..32ceca63 100644 --- a/formats/ctf/ir/trace.c +++ b/formats/ctf/ir/trace.c @@ -27,21 +27,35 @@ */ #include -#include +#include #include #include +#include +#include +#include #include -#include +#include +#include #include +#include +#include #include +#include #include -#include +#include +#include +#include #define DEFAULT_IDENTIFIER_SIZE 128 #define DEFAULT_METADATA_STRING_SIZE 4096 +struct listener_wrapper { + bt_ctf_listener_cb listener; + void *data; +}; + static -void bt_ctf_trace_destroy(struct bt_ctf_ref *ref); +void bt_ctf_trace_destroy(struct bt_object *obj); static int init_trace_packet_header(struct bt_ctf_trace *trace); static @@ -65,13 +79,6 @@ const unsigned int field_type_aliases_sizes[] = { [FIELD_TYPE_ALIAS_UINT64_T] = 64, }; -static -void put_stream_class(struct bt_ctf_stream_class *stream_class) -{ - (void) bt_ctf_stream_class_set_trace(stream_class, NULL); - bt_ctf_stream_class_put(stream_class); -} - struct bt_ctf_trace *bt_ctf_trace_create(void) { struct bt_ctf_trace *trace = NULL; @@ -82,114 +89,115 @@ struct bt_ctf_trace *bt_ctf_trace_create(void) } bt_ctf_trace_set_byte_order(trace, BT_CTF_BYTE_ORDER_NATIVE); - bt_ctf_ref_init(&trace->ref_count); + bt_object_init(trace, bt_ctf_trace_destroy); trace->clocks = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_clock_put); + (GDestroyNotify) bt_put); trace->streams = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_stream_put); + (GDestroyNotify) bt_object_release); trace->stream_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify) put_stream_class); + (GDestroyNotify) bt_object_release); if (!trace->clocks || !trace->stream_classes || !trace->streams) { - goto error_destroy; + goto error; } /* Generate a trace UUID */ uuid_generate(trace->uuid); if (init_trace_packet_header(trace)) { - goto error_destroy; + goto error; } /* Create the environment array object */ trace->environment = bt_ctf_attributes_create(); if (!trace->environment) { - goto error_destroy; + goto error; + } + + trace->listeners = g_ptr_array_new_with_free_func( + (GDestroyNotify) g_free); + if (!trace->listeners) { + goto error; } return trace; -error_destroy: - bt_ctf_trace_destroy(&trace->ref_count); - trace = NULL; error: + BT_PUT(trace); return trace; } -void bt_ctf_trace_destroy(struct bt_ctf_ref *ref) +const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace) { - struct bt_ctf_trace *trace; + const char *name = NULL; - if (!ref) { - return; + if (!trace || !trace->name) { + goto end; } - trace = container_of(ref, struct bt_ctf_trace, ref_count); - if (trace->environment) { - bt_ctf_attributes_destroy(trace->environment); - } + name = trace->name->str; +end: + return name; +} - if (trace->clocks) { - g_ptr_array_free(trace->clocks, TRUE); - } +int bt_ctf_trace_set_name(struct bt_ctf_trace *trace, const char *name) +{ + int ret = 0; - if (trace->streams) { - g_ptr_array_free(trace->streams, TRUE); + if (!trace || !name || trace->frozen) { + ret = -1; + goto end; } - if (trace->stream_classes) { - g_ptr_array_free(trace->stream_classes, TRUE); + trace->name = trace->name ? g_string_assign(trace->name, name) : + g_string_new(name); + if (!trace->name) { + ret = -1; + goto end; } - - bt_ctf_field_type_put(trace->packet_header_type); - g_free(trace); +end: + return ret; } -struct bt_ctf_stream *bt_ctf_trace_create_stream(struct bt_ctf_trace *trace, - struct bt_ctf_stream_class *stream_class) +void bt_ctf_trace_destroy(struct bt_object *obj) { - int ret; - int stream_class_found = 0; - size_t i; - struct bt_ctf_stream *stream = NULL; + struct bt_ctf_trace *trace; - if (!trace || !stream_class) { - goto error; + trace = container_of(obj, struct bt_ctf_trace, base); + if (trace->environment) { + bt_ctf_attributes_destroy(trace->environment); } - stream = bt_ctf_stream_create(stream_class, trace); - if (!stream) { - goto error; + if (trace->name) { + g_string_free(trace->name, TRUE); } - for (i = 0; i < trace->stream_classes->len; i++) { - if (trace->stream_classes->pdata[i] == stream_class) { - stream_class_found = 1; - } + if (trace->clocks) { + g_ptr_array_free(trace->clocks, TRUE); } - if (!stream_class_found) { - ret = bt_ctf_trace_add_stream_class(trace, stream_class); - if (ret) { - goto error; - } + if (trace->streams) { + g_ptr_array_free(trace->streams, TRUE); + } + + if (trace->stream_classes) { + g_ptr_array_free(trace->stream_classes, TRUE); } - bt_ctf_stream_get(stream); - g_ptr_array_add(trace->streams, stream); + if (trace->listeners) { + g_ptr_array_free(trace->listeners, TRUE); + } - return stream; -error: - bt_ctf_stream_put(stream); - return NULL; + bt_put(trace->packet_header_type); + g_free(trace); } int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace, - const char *name, struct bt_object *value) + const char *name, struct bt_value *value) { int ret = 0; - if (!trace || trace->frozen || !name || !value || + if (!trace || !name || !value || bt_ctf_validate_identifier(name) || - !(bt_object_is_integer(value) || bt_object_is_string(value))) { + !(bt_value_is_integer(value) || bt_value_is_string(value))) { ret = -1; goto end; } @@ -199,6 +207,26 @@ int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace, goto end; } + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + * + * The object passed is frozen like all other attributes. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + + bt_value_freeze(value); + } + ret = bt_ctf_attributes_set_field_value(trace->environment, name, value); @@ -210,26 +238,44 @@ int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace, const char *name, const char *value) { int ret = 0; - struct bt_object *env_value_string_obj = NULL; + struct bt_value *env_value_string_obj = NULL; if (!trace || !name || !value) { ret = -1; goto end; } - env_value_string_obj = bt_object_string_create_init(value); + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + } + + env_value_string_obj = bt_value_string_create_init(value); if (!env_value_string_obj) { ret = -1; goto end; } + if (trace->frozen) { + bt_value_freeze(env_value_string_obj); + } ret = bt_ctf_trace_set_environment_field(trace, name, env_value_string_obj); end: - BT_OBJECT_PUT(env_value_string_obj); - + BT_PUT(env_value_string_obj); return ret; } @@ -237,14 +283,30 @@ int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace, const char *name, int64_t value) { int ret = 0; - struct bt_object *env_value_integer_obj = NULL; + struct bt_value *env_value_integer_obj = NULL; if (!trace || !name) { ret = -1; goto end; } - env_value_integer_obj = bt_object_integer_create_init(value); + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + } + + env_value_integer_obj = bt_value_integer_create_init(value); if (!env_value_integer_obj) { ret = -1; goto end; @@ -252,10 +314,11 @@ int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace, ret = bt_ctf_trace_set_environment_field(trace, name, env_value_integer_obj); - + if (trace->frozen) { + bt_value_freeze(env_value_integer_obj); + } end: - BT_OBJECT_PUT(env_value_integer_obj); - + BT_PUT(env_value_integer_obj); return ret; } @@ -290,10 +353,10 @@ end: return ret; } -struct bt_object *bt_ctf_trace_get_environment_field_value( +struct bt_value *bt_ctf_trace_get_environment_field_value( struct bt_ctf_trace *trace, int index) { - struct bt_object *ret = NULL; + struct bt_value *ret = NULL; if (!trace) { goto end; @@ -305,10 +368,10 @@ end: return ret; } -struct bt_object *bt_ctf_trace_get_environment_field_value_by_name( +struct bt_value *bt_ctf_trace_get_environment_field_value_by_name( struct bt_ctf_trace *trace, const char *name) { - struct bt_object *ret = NULL; + struct bt_value *ret = NULL; if (!trace || !name) { goto end; @@ -321,31 +384,35 @@ end: return ret; } -int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace, - struct bt_ctf_clock *clock) +int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace, + struct bt_ctf_clock_class *clock_class) { int ret = 0; - struct search_query query = { .value = clock, .found = 0 }; + struct search_query query = { .value = clock_class, .found = 0 }; - if (!trace || !clock) { + if (!trace || !bt_ctf_clock_class_is_valid(clock_class)) { ret = -1; goto end; } - /* Check for duplicate clocks */ + /* Check for duplicate clock classes */ g_ptr_array_foreach(trace->clocks, value_exists, &query); if (query.found) { ret = -1; goto end; } - bt_ctf_clock_get(clock); - g_ptr_array_add(trace->clocks, clock); + bt_get(clock_class); + g_ptr_array_add(trace->clocks, clock_class); + + if (trace->frozen) { + bt_ctf_clock_class_freeze(clock_class); + } end: return ret; } -int bt_ctf_trace_get_clock_count(struct bt_ctf_trace *trace) +int bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace) { int ret = -1; @@ -358,19 +425,19 @@ end: return ret; } -struct bt_ctf_clock *bt_ctf_trace_get_clock(struct bt_ctf_trace *trace, - int index) +struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class( + struct bt_ctf_trace *trace, int index) { - struct bt_ctf_clock *clock = NULL; + struct bt_ctf_clock_class *clock_class = NULL; if (!trace || index < 0 || index >= trace->clocks->len) { goto end; } - clock = g_ptr_array_index(trace->clocks, index); - bt_ctf_clock_get(clock); + clock_class = g_ptr_array_index(trace->clocks, index); + bt_get(clock_class); end: - return clock; + return clock_class; } int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, @@ -378,14 +445,173 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, { int ret, i; int64_t stream_id; + struct bt_ctf_validation_output trace_sc_validation_output = { 0 }; + struct bt_ctf_validation_output *ec_validation_outputs = NULL; + const enum bt_ctf_validation_flag trace_sc_validation_flags = + BT_CTF_VALIDATION_FLAG_TRACE | + BT_CTF_VALIDATION_FLAG_STREAM; + const enum bt_ctf_validation_flag ec_validation_flags = + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_field_type *packet_header_type = NULL; + struct bt_ctf_field_type *packet_context_type = NULL; + struct bt_ctf_field_type *event_header_type = NULL; + struct bt_ctf_field_type *stream_event_ctx_type = NULL; + int event_class_count; + struct bt_ctf_trace *current_parent_trace = NULL; if (!trace || !stream_class) { ret = -1; goto end; } + current_parent_trace = bt_ctf_stream_class_get_trace(stream_class); + if (current_parent_trace) { + /* Stream class is already associated to a trace, abort. */ + ret = -1; + goto end; + } + + event_class_count = + bt_ctf_stream_class_get_event_class_count(stream_class); + assert(event_class_count >= 0); + + /* Check for duplicate stream classes */ for (i = 0; i < trace->stream_classes->len; i++) { if (trace->stream_classes->pdata[i] == stream_class) { + /* Stream class already registered to the trace */ + ret = -1; + goto end; + } + } + + if (stream_class->clock) { + struct bt_ctf_clock_class *stream_clock_class = + stream_class->clock->clock_class; + + if (trace->is_created_by_writer) { + /* + * Make sure this clock was also added to the + * trace (potentially through its CTF writer + * owner). + */ + size_t i; + + for (i = 0; i < trace->clocks->len; i++) { + if (trace->clocks->pdata[i] == + stream_clock_class) { + /* Found! */ + break; + } + } + + if (i == trace->clocks->len) { + /* Not found */ + ret = -1; + goto end; + } + } else { + /* + * This trace was NOT created by a CTF writer, + * thus do not allow the stream class to add to + * have a clock at all. Those are two + * independent APIs (non-writer and writer + * APIs), and isolating them simplifies things. + */ + ret = -1; + goto end; + } + } + + /* + * We're about to freeze both the trace and the stream class. + * Also, each event class contained in this stream class are + * already frozen. + * + * This trace, this stream class, and all its event classes + * should be valid at this point. + * + * Validate trace and stream class first, then each event + * class of this stream class can be validated individually. + */ + packet_header_type = + bt_ctf_trace_get_packet_header_type(trace); + packet_context_type = + bt_ctf_stream_class_get_packet_context_type(stream_class); + event_header_type = + bt_ctf_stream_class_get_event_header_type(stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_get_event_context_type(stream_class); + ret = bt_ctf_validate_class_types(trace->environment, + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, NULL, NULL, trace->valid, + stream_class->valid, 1, &trace_sc_validation_output, + trace_sc_validation_flags); + BT_PUT(packet_header_type); + BT_PUT(packet_context_type); + BT_PUT(event_header_type); + BT_PUT(stream_event_ctx_type); + + if (ret) { + /* + * This means something went wrong during the validation + * process, not that the objects are invalid. + */ + goto end; + } + + if ((trace_sc_validation_output.valid_flags & + trace_sc_validation_flags) != + trace_sc_validation_flags) { + /* Invalid trace/stream class */ + ret = -1; + goto end; + } + + if (event_class_count > 0) { + ec_validation_outputs = g_new0(struct bt_ctf_validation_output, + event_class_count); + if (!ec_validation_outputs) { + ret = -1; + goto end; + } + } + + /* Validate each event class individually */ + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class *event_class = + bt_ctf_stream_class_get_event_class(stream_class, i); + struct bt_ctf_field_type *event_context_type = NULL; + struct bt_ctf_field_type *event_payload_type = NULL; + + event_context_type = + bt_ctf_event_class_get_context_type(event_class); + event_payload_type = + bt_ctf_event_class_get_payload_type(event_class); + + /* + * It is important to use the field types returned by + * the previous trace and stream class validation here + * because copies could have been made. + */ + ret = bt_ctf_validate_class_types(trace->environment, + trace_sc_validation_output.packet_header_type, + trace_sc_validation_output.packet_context_type, + trace_sc_validation_output.event_header_type, + trace_sc_validation_output.stream_event_ctx_type, + event_context_type, event_payload_type, + 1, 1, event_class->valid, &ec_validation_outputs[i], + ec_validation_flags); + BT_PUT(event_context_type); + BT_PUT(event_payload_type); + BT_PUT(event_class); + + if (ret) { + goto end; + } + + if ((ec_validation_outputs[i].valid_flags & + ec_validation_flags) != ec_validation_flags) { + /* Invalid event class */ ret = -1; goto end; } @@ -405,7 +631,7 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, } } - if (_bt_ctf_stream_class_set_id(stream_class, + if (bt_ctf_stream_class_set_id_no_check(stream_class, stream_id)) { /* TODO Should retry with a different stream id */ ret = -1; @@ -413,37 +639,80 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, } } - /* Set weak reference to trace in stream class */ - ret = bt_ctf_stream_class_set_trace(stream_class, trace); - if (ret) { - /* Stream class already part of another trace */ - goto end; - } - - bt_ctf_stream_class_get(stream_class); + bt_object_set_parent(stream_class, trace); g_ptr_array_add(trace->stream_classes, stream_class); /* - * Freeze the trace and its packet header. - * + * At this point we know that the function will be successful. + * Therefore we can replace the trace and stream class field + * types with what's in their validation output structure and + * mark them as valid. We can also replace the field types of + * all the event classes of the stream class and mark them as + * valid. + */ + bt_ctf_validation_replace_types(trace, stream_class, NULL, + &trace_sc_validation_output, trace_sc_validation_flags); + trace->valid = 1; + stream_class->valid = 1; + + /* + * Put what was not moved in bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class *event_class = + bt_ctf_stream_class_get_event_class(stream_class, i); + + bt_ctf_validation_replace_types(NULL, NULL, event_class, + &ec_validation_outputs[i], ec_validation_flags); + event_class->valid = 1; + BT_PUT(event_class); + + /* + * Put what was not moved in + * bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&ec_validation_outputs[i]); + } + + /* * All field type byte orders set as "native" byte ordering can now be * safely set to trace's own endianness, including the stream class'. */ bt_ctf_field_type_set_native_byte_order(trace->packet_header_type, trace->byte_order); - ret = bt_ctf_stream_class_set_byte_order(stream_class, - trace->byte_order == LITTLE_ENDIAN ? - BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN); - if (ret) { - goto end; - } + bt_ctf_stream_class_set_byte_order(stream_class, trace->byte_order); + /* + * Freeze the trace and the stream class. + */ bt_ctf_stream_class_freeze(stream_class); bt_ctf_trace_freeze(trace); + + /* Notifiy listeners of the trace's schema modification. */ + bt_ctf_stream_class_visit(stream_class, + bt_ctf_trace_object_modification, trace); end: if (ret) { - (void) bt_ctf_stream_class_set_trace(stream_class, NULL); + bt_object_set_parent(stream_class, NULL); + + if (ec_validation_outputs) { + for (i = 0; i < event_class_count; i++) { + bt_ctf_validation_output_put_types( + &ec_validation_outputs[i]); + } + } } + + g_free(ec_validation_outputs); + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + bt_put(current_parent_trace); + assert(!packet_header_type); + assert(!packet_context_type); + assert(!event_header_type); + assert(!stream_event_ctx_type); + return ret; } @@ -471,39 +740,67 @@ struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class( } stream_class = g_ptr_array_index(trace->stream_classes, index); - bt_ctf_stream_class_get(stream_class); + bt_get(stream_class); end: return stream_class; } -struct bt_ctf_clock *bt_ctf_trace_get_clock_by_name( +struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id( + struct bt_ctf_trace *trace, uint32_t id) +{ + int i; + struct bt_ctf_stream_class *stream_class = NULL; + + if (!trace) { + goto end; + } + + for (i = 0; i < trace->stream_classes->len; i++) { + struct bt_ctf_stream_class *stream_class_candidate; + + stream_class_candidate = + g_ptr_array_index(trace->stream_classes, i); + + if (bt_ctf_stream_class_get_id(stream_class_candidate) == + (int64_t) id) { + stream_class = stream_class_candidate; + bt_get(stream_class); + goto end; + } + } + +end: + return stream_class; +} + +struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name( struct bt_ctf_trace *trace, const char *name) { size_t i; - struct bt_ctf_clock *clock = NULL; + struct bt_ctf_clock_class *clock_class = NULL; if (!trace || !name) { goto end; } - for (i = 0; i < trace->clocks->len; ++i) { - struct bt_ctf_clock *cur_clk = + for (i = 0; i < trace->clocks->len; i++) { + struct bt_ctf_clock_class *cur_clk = g_ptr_array_index(trace->clocks, i); - const char *cur_clk_name = bt_ctf_clock_get_name(cur_clk); + const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk); if (!cur_clk_name) { goto end; } if (!strcmp(cur_clk_name, name)) { - clock = cur_clk; - bt_ctf_clock_get(clock); + clock_class = cur_clk; + bt_get(clock_class); goto end; } } end: - return clock; + return clock_class; } BT_HIDDEN @@ -577,8 +874,8 @@ void append_env_metadata(struct bt_ctf_trace *trace, g_string_append(context->string, "env {\n"); - for (i = 0; i < env_size; ++i) { - struct bt_object *env_field_value_obj = NULL; + for (i = 0; i < env_size; i++) { + struct bt_value *env_field_value_obj = NULL; const char *entry_name; entry_name = bt_ctf_attributes_get_field_name( @@ -590,13 +887,13 @@ void append_env_metadata(struct bt_ctf_trace *trace, goto loop_next; } - switch (bt_object_get_type(env_field_value_obj)) { - case BT_OBJECT_TYPE_INTEGER: + switch (bt_value_get_type(env_field_value_obj)) { + case BT_VALUE_TYPE_INTEGER: { int ret; int64_t int_value; - ret = bt_object_integer_get(env_field_value_obj, + ret = bt_value_integer_get(env_field_value_obj, &int_value); if (ret) { @@ -608,13 +905,13 @@ void append_env_metadata(struct bt_ctf_trace *trace, int_value); break; } - case BT_OBJECT_TYPE_STRING: + case BT_VALUE_TYPE_STRING: { int ret; const char *str_value; char *escaped_str = NULL; - ret = bt_object_string_get(env_field_value_obj, + ret = bt_value_string_get(env_field_value_obj, &str_value); if (ret) { @@ -638,7 +935,7 @@ void append_env_metadata(struct bt_ctf_trace *trace, } loop_next: - BT_OBJECT_PUT(env_field_value_obj); + BT_PUT(env_field_value_obj); } g_string_append(context->string, "};\n\n"); @@ -668,7 +965,7 @@ char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace) } append_env_metadata(trace, context); g_ptr_array_foreach(trace->clocks, - (GFunc)bt_ctf_clock_serialize, context); + (GFunc)bt_ctf_clock_class_serialize, context); for (i = 0; i < trace->stream_classes->len; i++) { err = bt_ctf_stream_class_serialize( @@ -760,7 +1057,7 @@ struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type( goto end; } - bt_ctf_field_type_get(trace->packet_header_type); + bt_get(trace->packet_header_type); field_type = trace->packet_header_type; end: return field_type; @@ -771,64 +1068,165 @@ int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace, { int ret = 0; - if (!trace || !packet_header_type || trace->frozen) { + if (!trace || trace->frozen) { ret = -1; goto end; } - /* packet_header_type must be a structure */ - if (bt_ctf_field_type_get_type_id(packet_header_type) != - CTF_TYPE_STRUCT) { + /* packet_header_type must be a structure. */ + if (packet_header_type && + bt_ctf_field_type_get_type_id(packet_header_type) != + BT_CTF_TYPE_ID_STRUCT) { ret = -1; goto end; } - bt_ctf_field_type_get(packet_header_type); - bt_ctf_field_type_put(trace->packet_header_type); - trace->packet_header_type = packet_header_type; + bt_put(trace->packet_header_type); + trace->packet_header_type = bt_get(packet_header_type); end: return ret; } -void bt_ctf_trace_get(struct bt_ctf_trace *trace) +static +int get_stream_class_count(void *element) { - if (!trace) { - return; + return bt_ctf_trace_get_stream_class_count( + (struct bt_ctf_trace *) element); +} + +static +void *get_stream_class(void *element, int i) +{ + return bt_ctf_trace_get_stream_class( + (struct bt_ctf_trace *) element, i); +} + +static +int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data) +{ + return bt_ctf_stream_class_visit(object, visitor, data); +} + +int bt_ctf_trace_visit(struct bt_ctf_trace *trace, + bt_ctf_visitor visitor, void *data) +{ + int ret; + struct bt_ctf_object obj = + { .object = trace, .type = BT_CTF_OBJECT_TYPE_TRACE }; + + if (!trace || !visitor) { + ret = -1; + goto end; } - bt_ctf_ref_get(&trace->ref_count); + ret = visitor_helper(&obj, get_stream_class_count, + get_stream_class, visit_stream_class, visitor, data); +end: + return ret; } -void bt_ctf_trace_put(struct bt_ctf_trace *trace) +static +int invoke_listener(struct bt_ctf_object *object, void *data) { - if (!trace) { - return; + struct listener_wrapper *listener_wrapper = data; + + listener_wrapper->listener(object, listener_wrapper->data); + return 0; +} + +int bt_ctf_trace_add_listener(struct bt_ctf_trace *trace, + bt_ctf_listener_cb listener, void *listener_data) +{ + int ret = 0; + struct listener_wrapper *listener_wrapper = + g_new0(struct listener_wrapper, 1); + + if (!trace || !listener || !listener_wrapper) { + ret = -1; + goto error; + } + + listener_wrapper->listener = listener; + listener_wrapper->data = listener_data; + + /* Visit the current schema. */ + ret = bt_ctf_trace_visit(trace, invoke_listener, listener_wrapper); + if (ret) { + goto error; } - bt_ctf_ref_put(&trace->ref_count, bt_ctf_trace_destroy); + /* + * Add listener to the array of callbacks which will be invoked on + * schema changes. + */ + g_ptr_array_add(trace->listeners, listener_wrapper); + return ret; +error: + g_free(listener_wrapper); + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_object_modification(struct bt_ctf_object *object, + void *trace_ptr) +{ + size_t i; + struct bt_ctf_trace *trace = trace_ptr; + + assert(trace); + assert(object); + + if (trace->listeners->len == 0) { + goto end; + } + + for (i = 0; i < trace->listeners->len; i++) { + struct listener_wrapper *listener = + g_ptr_array_index(trace->listeners, i); + + listener->listener(object, listener->data); + } +end: + return 0; } BT_HIDDEN struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) { + int ret; unsigned int alignment, size; - struct bt_ctf_field_type *field_type; + struct bt_ctf_field_type *field_type = NULL; if (alias >= NR_FIELD_TYPE_ALIAS) { - return NULL; + goto end; } alignment = field_type_aliases_alignments[alias]; size = field_type_aliases_sizes[alias]; field_type = bt_ctf_field_type_integer_create(size); - bt_ctf_field_type_set_alignment(field_type, alignment); + ret = bt_ctf_field_type_set_alignment(field_type, alignment); + if (ret) { + BT_PUT(field_type); + } +end: return field_type; } static void bt_ctf_trace_freeze(struct bt_ctf_trace *trace) { + int i; + + bt_ctf_field_type_freeze(trace->packet_header_type); bt_ctf_attributes_freeze(trace->environment); + + for (i = 0; i < trace->clocks->len; i++) { + struct bt_ctf_clock_class *clock_class = + g_ptr_array_index(trace->clocks, i); + + bt_ctf_clock_class_freeze(clock_class); + } + trace->frozen = 1; } @@ -875,12 +1273,11 @@ int init_trace_packet_header(struct bt_ctf_trace *trace) goto end; } end: - bt_ctf_field_type_put(uuid_array_type); - bt_ctf_field_type_put(_uint32_t); - bt_ctf_field_type_put(_uint8_t); - bt_ctf_field_put(magic); - bt_ctf_field_put(uuid_array); - bt_ctf_field_type_put(trace_packet_header_type); - + bt_put(uuid_array_type); + bt_put(_uint32_t); + bt_put(_uint8_t); + bt_put(magic); + bt_put(uuid_array); + bt_put(trace_packet_header_type); return ret; }