From: Jérémie Galarneau Date: Thu, 18 Dec 2014 18:01:23 +0000 (-0500) Subject: Add trace packet header accessors and support custom headers X-Git-Tag: v2.0.0-pre1~1437 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=d246b1115dbace6a7d67828cfd3fb1d5dc1c4f58 Add trace packet header accessors and support custom headers Signed-off-by: Jérémie Galarneau --- diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c index 45f875ff..80d13111 100644 --- a/formats/ctf/ir/stream.c +++ b/formats/ctf/ir/stream.c @@ -38,20 +38,223 @@ #include #include #include +#include static void bt_ctf_stream_destroy(struct bt_ctf_ref *ref); static int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); +static +int set_packet_header_magic(struct bt_ctf_stream *stream) +{ + int ret = 0; + struct bt_ctf_field_type *magic_field_type = NULL; + struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field( + stream->packet_header, "magic"); + + if (!magic_field) { + /* No magic field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(magic_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + magic_field_type = bt_ctf_field_get_type(magic_field); + assert(magic_field_type); + + if (bt_ctf_field_type_get_type_id(magic_field_type) != + CTF_TYPE_INTEGER) { + /* Magic field is not an integer. Not an error, skip. */ + goto end; + } + + if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) { + /* + * Magic field is not of the expected size. + * Not an error, skip. + */ + goto end; + } + + ret = bt_ctf_field_type_integer_get_signed(magic_field_type); + assert(ret >= 0); + if (ret) { + ret = bt_ctf_field_signed_integer_set_value(magic_field, + (int64_t) 0xC1FC1FC1); + } else { + ret = bt_ctf_field_unsigned_integer_set_value(magic_field, + (uint64_t) 0xC1FC1FC1); + } +end: + if (magic_field) { + bt_ctf_field_put(magic_field); + } + if (magic_field_type) { + bt_ctf_field_type_put(magic_field_type); + } + return ret; +} + +static +int set_packet_header_uuid(struct bt_ctf_stream *stream) +{ + int i, ret = 0; + struct bt_ctf_field_type *uuid_field_type = NULL; + struct bt_ctf_field_type *element_field_type = NULL; + struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field( + stream->packet_header, "uuid"); + + if (!uuid_field) { + /* No uuid field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(uuid_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + uuid_field_type = bt_ctf_field_get_type(uuid_field); + assert(uuid_field_type); + if (bt_ctf_field_type_get_type_id(uuid_field_type) != + CTF_TYPE_ARRAY) { + /* UUID field is not an array. Not an error, skip. */ + goto end; + } + + if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) { + /* + * UUID field is not of the expected size. + * Not an error, skip. + */ + goto end; + } + + element_field_type = bt_ctf_field_type_array_get_element_type( + uuid_field_type); + assert(element_field_type); + if (bt_ctf_field_type_get_type_id(element_field_type) != + CTF_TYPE_INTEGER) { + /* UUID array elements are not integers. Not an error, skip */ + goto end; + } + + for (i = 0; i < 16; i++) { + struct bt_ctf_field *uuid_element = + bt_ctf_field_array_get_field(uuid_field, i); + + ret = bt_ctf_field_type_integer_get_signed(element_field_type); + assert(ret >= 0); + + if (ret) { + ret = bt_ctf_field_signed_integer_set_value( + uuid_element, (int64_t) stream->trace->uuid[i]); + } else { + ret = bt_ctf_field_unsigned_integer_set_value( + uuid_element, + (uint64_t) stream->trace->uuid[i]); + } + bt_ctf_field_put(uuid_element); + if (ret) { + goto end; + } + } + +end: + if (uuid_field) { + bt_ctf_field_put(uuid_field); + } + if (uuid_field_type) { + bt_ctf_field_type_put(uuid_field_type); + } + if (element_field_type) { + bt_ctf_field_type_put(element_field_type); + } + return ret; +} +static +int set_packet_header_stream_id(struct bt_ctf_stream *stream) +{ + int ret = 0; + uint32_t stream_id; + struct bt_ctf_field_type *stream_id_field_type = NULL; + struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field( + stream->packet_header, "stream_id"); + + if (!stream_id_field) { + /* No stream_id field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(stream_id_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + stream_id_field_type = bt_ctf_field_get_type(stream_id_field); + assert(stream_id_field_type); + if (bt_ctf_field_type_get_type_id(stream_id_field_type) != + CTF_TYPE_INTEGER) { + /* stream_id field is not an integer. Not an error, skip. */ + goto end; + } + + stream_id = stream->stream_class->id; + ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type); + assert(ret >= 0); + if (ret) { + ret = bt_ctf_field_signed_integer_set_value(stream_id_field, + (int64_t) stream_id); + } else { + ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field, + (uint64_t) stream_id); + } +end: + if (stream_id_field) { + bt_ctf_field_put(stream_id_field); + } + if (stream_id_field_type) { + bt_ctf_field_type_put(stream_id_field_type); + } + return ret; +} + +static +int set_packet_header(struct bt_ctf_stream *stream) +{ + int ret; + + ret = set_packet_header_magic(stream); + if (ret) { + goto end; + } + + ret = set_packet_header_uuid(stream); + if (ret) { + goto end; + } + + ret = set_packet_header_stream_id(stream); + if (ret) { + goto end; + } +end: + return ret; +} + BT_HIDDEN struct bt_ctf_stream *bt_ctf_stream_create( - struct bt_ctf_stream_class *stream_class) + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_trace *trace) { int ret; struct bt_ctf_stream *stream = NULL; - if (!stream_class) { + if (!stream_class || !trace) { goto end; } @@ -60,6 +263,7 @@ struct bt_ctf_stream *bt_ctf_stream_create( goto end; } + stream->trace = trace; bt_ctf_ref_init(&stream->ref_count); stream->packet_context = bt_ctf_field_create( stream_class->packet_context_type); @@ -105,6 +309,22 @@ struct bt_ctf_stream *bt_ctf_stream_create( goto error_destroy; } } + + /* A trace is not allowed to have a NULL packet header */ + assert(trace->packet_header_type); + stream->packet_header = bt_ctf_field_create(trace->packet_header_type); + /* + * Attempt to populate the default trace packet header fields + * (magic, uuid and stream_id). This will _not_ fail shall the + * fields not be found or be of an incompatible type; they will + * simply not be populated automatically. The user will have to + * make sure to set the trace packet header fields himself before + * flushing. + */ + ret = set_packet_header(stream); + if (ret) { + goto error_destroy; + } end: return stream; error_destroy: @@ -112,22 +332,6 @@ error_destroy: return NULL; } -BT_HIDDEN -int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream, - flush_func callback, void *data) -{ - int ret = stream ? 0 : -1; - - if (!stream) { - goto end; - } - - stream->flush.func = callback; - stream->flush.data = data; -end: - return ret; -} - BT_HIDDEN int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd) { @@ -144,6 +348,13 @@ end: return ret; } +BT_HIDDEN +void bt_ctf_stream_set_trace(struct bt_ctf_stream *stream, + struct bt_ctf_trace *trace) +{ + stream->trace = trace; +} + int bt_ctf_stream_get_discarded_events_count( struct bt_ctf_stream *stream, uint64_t *count) { @@ -428,8 +639,19 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) goto end; } - if (stream->flush.func) { - stream->flush.func(stream, stream->flush.data); + ret = bt_ctf_field_validate(stream->packet_header); + if (ret) { + goto end; + } + + if (stream->flushed_packet_count) { + /* ctf_init_pos has already initialized the first packet */ + ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); + } + + ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos); + if (ret) { + goto end; } stream_class = stream->stream_class; @@ -615,6 +837,9 @@ void bt_ctf_stream_destroy(struct bt_ctf_ref *ref) if (stream->event_contexts) { g_ptr_array_free(stream->event_contexts, TRUE); } + if (stream->packet_header) { + bt_ctf_field_put(stream->packet_header); + } if (stream->packet_context) { bt_ctf_field_put(stream->packet_context); } diff --git a/formats/ctf/ir/trace.c b/formats/ctf/ir/trace.c index 1ad37bec..6ffef05b 100644 --- a/formats/ctf/ir/trace.c +++ b/formats/ctf/ir/trace.c @@ -137,8 +137,7 @@ void bt_ctf_trace_destroy(struct bt_ctf_ref *ref) g_ptr_array_free(trace->stream_classes, TRUE); } - bt_ctf_field_type_put(trace->trace_packet_header_type); - bt_ctf_field_put(trace->trace_packet_header); + bt_ctf_field_type_put(trace->packet_header_type); g_free(trace); } @@ -161,7 +160,7 @@ struct bt_ctf_stream *bt_ctf_trace_create_stream(struct bt_ctf_trace *trace, goto error; } - stream = bt_ctf_stream_create(stream_class); + stream = bt_ctf_stream_create(stream_class, trace); if (!stream) { goto error; } @@ -354,7 +353,7 @@ int append_trace_metadata(struct bt_ctf_trace *trace, g_string_append(context->string, "\tpacket.header := "); context->current_indentation_level++; g_string_assign(context->field_name, ""); - ret = bt_ctf_field_type_serialize(trace->trace_packet_header_type, + ret = bt_ctf_field_type_serialize(trace->packet_header_type, context); if (ret) { goto end; @@ -460,14 +459,52 @@ int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace, } trace->byte_order = internal_byte_order; - if (trace->trace_packet_header_type || - trace->trace_packet_header) { + if (trace->packet_header_type) { init_trace_packet_header(trace); } end: return ret; } +struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type( + struct bt_ctf_trace *trace) +{ + struct bt_ctf_field_type *field_type = NULL; + + if (!trace) { + goto end; + } + + bt_ctf_field_type_get(trace->packet_header_type); + field_type = trace->packet_header_type; +end: + return field_type; +} + +int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace, + struct bt_ctf_field_type *packet_header_type) +{ + int ret = 0; + + if (!trace || !packet_header_type || 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) { + 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; +end: + return ret; +} + void bt_ctf_trace_get(struct bt_ctf_trace *trace) { if (!trace) { @@ -540,10 +577,8 @@ struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) static int init_trace_packet_header(struct bt_ctf_trace *trace) { - size_t i; int ret = 0; - struct bt_ctf_field *trace_packet_header = NULL, - *magic = NULL, *uuid_array = NULL; + struct bt_ctf_field *magic = NULL, *uuid_array = NULL; struct bt_ctf_field_type *_uint32_t = get_field_type(FIELD_TYPE_ALIAS_UINT32_T); struct bt_ctf_field_type *_uint8_t = @@ -584,35 +619,8 @@ int init_trace_packet_header(struct bt_ctf_trace *trace) goto end; } - trace_packet_header = bt_ctf_field_create(trace_packet_header_type); - if (!trace_packet_header) { - ret = -1; - goto end; - } - - magic = bt_ctf_field_structure_get_field(trace_packet_header, "magic"); - ret = bt_ctf_field_unsigned_integer_set_value(magic, 0xC1FC1FC1); - if (ret) { - goto end; - } - - uuid_array = bt_ctf_field_structure_get_field(trace_packet_header, - "uuid"); - for (i = 0; i < 16; i++) { - struct bt_ctf_field *uuid_element = - bt_ctf_field_array_get_field(uuid_array, i); - ret = bt_ctf_field_unsigned_integer_set_value(uuid_element, - trace->uuid[i]); - bt_ctf_field_put(uuid_element); - if (ret) { - goto end; - } - } - - bt_ctf_field_type_put(trace->trace_packet_header_type); - bt_ctf_field_put(trace->trace_packet_header); - trace->trace_packet_header_type = trace_packet_header_type; - trace->trace_packet_header = trace_packet_header; + bt_ctf_field_type_put(trace->packet_header_type); + trace->packet_header_type = trace_packet_header_type; end: bt_ctf_field_type_put(uuid_array_type); bt_ctf_field_type_put(_uint32_t); @@ -621,7 +629,6 @@ end: bt_ctf_field_put(uuid_array); if (ret) { bt_ctf_field_type_put(trace_packet_header_type); - bt_ctf_field_put(trace_packet_header); } return ret; diff --git a/formats/ctf/writer/writer.c b/formats/ctf/writer/writer.c index ed896ca4..54eab39b 100644 --- a/formats/ctf/writer/writer.c +++ b/formats/ctf/writer/writer.c @@ -47,9 +47,6 @@ void bt_ctf_writer_destroy(struct bt_ctf_ref *ref); static int create_stream_file(struct bt_ctf_writer *writer, struct bt_ctf_stream *stream); -static -void stream_flush_cb(struct bt_ctf_stream *stream, - struct bt_ctf_writer *writer); struct bt_ctf_writer *bt_ctf_writer_create(const char *path) { @@ -165,8 +162,6 @@ struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, goto error; } - bt_ctf_stream_set_flush_callback(stream, (flush_func)stream_flush_cb, - writer); writer->frozen = 1; return stream; @@ -302,23 +297,3 @@ int create_stream_file(struct bt_ctf_writer *writer, g_string_free(filename, TRUE); return fd; } - -static -void stream_flush_cb(struct bt_ctf_stream *stream, struct bt_ctf_writer *writer) -{ - struct bt_ctf_field *stream_id; - - /* Start a new packet in the stream */ - if (stream->flushed_packet_count) { - /* ctf_init_pos has already initialized the first packet */ - ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); - } - - stream_id = bt_ctf_field_structure_get_field( - writer->trace->trace_packet_header, "stream_id"); - bt_ctf_field_unsigned_integer_set_value(stream_id, stream->stream_class->id); - bt_ctf_field_put(stream_id); - - /* Write the trace_packet_header */ - bt_ctf_field_serialize(writer->trace->trace_packet_header, &stream->pos); -} diff --git a/include/babeltrace/ctf-ir/stream-internal.h b/include/babeltrace/ctf-ir/stream-internal.h index cc421d22..4b3250b0 100644 --- a/include/babeltrace/ctf-ir/stream-internal.h +++ b/include/babeltrace/ctf-ir/stream-internal.h @@ -36,35 +36,27 @@ #include #include -typedef void(*flush_func)(struct bt_ctf_stream *, void *); - -struct flush_callback { - flush_func func; - void *data; -}; - struct bt_ctf_stream { struct bt_ctf_ref ref_count; + /* Trace owning this stream. A stream does not own a trace. */ + struct bt_ctf_trace *trace; uint32_t id; struct bt_ctf_stream_class *stream_class; - struct flush_callback flush; /* Array of pointers to bt_ctf_event for the current packet */ GPtrArray *events; /* Array of pointers to bt_ctf_field associated with each event*/ GPtrArray *event_contexts; struct ctf_stream_pos pos; unsigned int flushed_packet_count; + struct bt_ctf_field *packet_header; struct bt_ctf_field *packet_context; struct bt_ctf_field *event_context; }; BT_HIDDEN struct bt_ctf_stream *bt_ctf_stream_create( - struct bt_ctf_stream_class *stream_class); - -BT_HIDDEN -int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream, - flush_func callback, void *data); + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_trace *trace); BT_HIDDEN int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd); diff --git a/include/babeltrace/ctf-ir/trace-internal.h b/include/babeltrace/ctf-ir/trace-internal.h index 169b76bf..dc0b7069 100644 --- a/include/babeltrace/ctf-ir/trace-internal.h +++ b/include/babeltrace/ctf-ir/trace-internal.h @@ -55,8 +55,7 @@ struct bt_ctf_trace { GPtrArray *clocks; /* Array of pointers to bt_ctf_clock */ GPtrArray *stream_classes; /* Array of ptrs to bt_ctf_stream_class */ GPtrArray *streams; /* Array of ptrs to bt_ctf_stream */ - struct bt_ctf_field_type *trace_packet_header_type; - struct bt_ctf_field *trace_packet_header; + struct bt_ctf_field_type *packet_header_type; uint64_t next_stream_id; }; diff --git a/include/babeltrace/ctf-ir/trace.h b/include/babeltrace/ctf-ir/trace.h index d36da0eb..dea9f70a 100644 --- a/include/babeltrace/ctf-ir/trace.h +++ b/include/babeltrace/ctf-ir/trace.h @@ -44,7 +44,13 @@ struct bt_ctf_clock; /* * bt_ctf_trace_create: create a trace instance. * - * Allocate a new trace + * Allocate a new trace. + * + * A trace's default packet header is a structure initialized with the following + * fields: + * - uint32_t magic + * - uint8_t uuid[16] + * - uint32_t stream_id * * Returns a new trace on success, NULL on error. */ @@ -142,6 +148,32 @@ extern char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace); extern int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace, enum bt_ctf_byte_order byte_order); +/* + * bt_ctf_trace_get_packet_header_type: get a trace's packet header type. + * + * Get the trace's packet header type. + * + * @param trace Trace instance. + * + * Returns the trace's packet header type (a structure) on success, NULL on + * error. + */ +extern struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type( + struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_set_packet_header_type: set a trace's packet header type. + * + * Set the trace's packet header type. + * + * @param trace Trace instance. + * @param packet_header_type Packet header field type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace, + struct bt_ctf_field_type *packet_header_type); + /* * bt_ctf_trace_get and bt_ctf_trace_put: increment and decrement the * trace's reference count.