From 12c8a1a3121ed7125e8758065c44658d8eda1333 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 29 Jul 2014 16:51:51 -0400 Subject: [PATCH] Add stream packet header accessors MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Stream packet contexts may now be modified to contain custom fields. The events_discarded field is now handled like a generic packet context field. Signed-off-by: Jérémie Galarneau --- formats/ctf/ir/event-fields.c | 228 ++++++++++++++++ formats/ctf/ir/stream-class.c | 59 ++++- formats/ctf/ir/stream.c | 248 ++++++++++++++++-- formats/ctf/writer/writer.c | 14 +- .../babeltrace/ctf-ir/event-fields-internal.h | 5 + .../babeltrace/ctf-ir/stream-class-internal.h | 1 - include/babeltrace/ctf-ir/stream-class.h | 31 +++ include/babeltrace/ctf-ir/stream-internal.h | 2 +- include/babeltrace/ctf-ir/stream.h | 41 ++- tests/lib/test_ctf_writer.c | 96 ++++++- 10 files changed, 676 insertions(+), 49 deletions(-) diff --git a/formats/ctf/ir/event-fields.c b/formats/ctf/ir/event-fields.c index ed2cf489..14fade72 100644 --- a/formats/ctf/ir/event-fields.c +++ b/formats/ctf/ir/event-fields.c @@ -88,6 +88,21 @@ int bt_ctf_field_array_validate(struct bt_ctf_field *field); static int bt_ctf_field_sequence_validate(struct bt_ctf_field *field); +static +int bt_ctf_field_generic_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_structure_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_variant_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_enumeration_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_array_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_sequence_reset(struct bt_ctf_field *field); +static +int bt_ctf_field_string_reset(struct bt_ctf_field *field); + static int bt_ctf_field_integer_serialize(struct bt_ctf_field *, struct ctf_stream_pos *); @@ -155,6 +170,18 @@ int (*field_validate_funcs[])(struct bt_ctf_field *) = { [CTF_TYPE_STRING] = bt_ctf_field_generic_validate, }; +static +int (*field_reset_funcs[])(struct bt_ctf_field *) = { + [CTF_TYPE_INTEGER] = bt_ctf_field_generic_reset, + [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_reset, + [CTF_TYPE_FLOAT] = bt_ctf_field_generic_reset, + [CTF_TYPE_STRUCT] = bt_ctf_field_structure_reset, + [CTF_TYPE_VARIANT] = bt_ctf_field_variant_reset, + [CTF_TYPE_ARRAY] = bt_ctf_field_array_reset, + [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_reset, + [CTF_TYPE_STRING] = bt_ctf_field_string_reset, +}; + static int (*field_serialize_funcs[])(struct bt_ctf_field *, struct ctf_stream_pos *) = { @@ -883,6 +910,28 @@ end: return ret; } +BT_HIDDEN +int bt_ctf_field_reset(struct bt_ctf_field *field) +{ + int ret = 0; + enum ctf_type_id type_id; + + if (!field) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(field->type); + if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) { + ret = -1; + goto end; + } + + ret = field_reset_funcs[type_id](field); +end: + return ret; +} + BT_HIDDEN int bt_ctf_field_serialize(struct bt_ctf_field *field, struct ctf_stream_pos *pos) @@ -1297,6 +1346,185 @@ end: return ret; } +static +int bt_ctf_field_generic_reset(struct bt_ctf_field *field) +{ + int ret = 0; + + if (!field) { + ret = -1; + goto end; + } + + field->payload_set = 0; +end: + return ret; +} + +static +int bt_ctf_field_enumeration_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_enumeration *enumeration; + + if (!field) { + ret = -1; + goto end; + } + + enumeration = container_of(field, struct bt_ctf_field_enumeration, + parent); + if (!enumeration->payload) { + goto end; + } + + ret = bt_ctf_field_reset(enumeration->payload); +end: + return ret; +} + +static +int bt_ctf_field_structure_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_structure *structure; + + if (!field) { + ret = -1; + goto end; + } + + structure = container_of(field, struct bt_ctf_field_structure, parent); + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field *member = structure->fields->pdata[i]; + + if (!member) { + /* + * Structure members are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_variant_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_variant *variant; + + if (!field) { + ret = -1; + goto end; + } + + variant = container_of(field, struct bt_ctf_field_variant, parent); + if (variant->payload) { + ret = bt_ctf_field_reset(variant->payload); + } +end: + return ret; +} + +static +int bt_ctf_field_array_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_array *array; + + if (!field) { + ret = -1; + goto end; + } + + array = container_of(field, struct bt_ctf_field_array, parent); + for (i = 0; i < array->elements->len; i++) { + struct bt_ctf_field *member = array->elements->pdata[i]; + + if (!member) { + /* + * Array elements are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_sequence_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_sequence *sequence; + + if (!field) { + ret = -1; + goto end; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + for (i = 0; i < sequence->elements->len; i++) { + struct bt_ctf_field *member = sequence->elements->pdata[i]; + + if (!member) { + /* + * Sequence elements are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_string_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_string *string; + + if (!field) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_generic_reset(field); + if (ret) { + goto end; + } + + string = container_of(field, struct bt_ctf_field_string, parent); + if (string->payload) { + g_string_truncate(string->payload, 0); + } +end: + return ret; +} + static int bt_ctf_field_integer_serialize(struct bt_ctf_field *field, struct ctf_stream_pos *pos) diff --git a/formats/ctf/ir/stream-class.c b/formats/ctf/ir/stream-class.c index 5cd572fe..10095a2c 100644 --- a/formats/ctf/ir/stream-class.c +++ b/formats/ctf/ir/stream-class.c @@ -49,6 +49,7 @@ int init_packet_context(struct bt_ctf_stream_class *stream_class, struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) { + int ret; struct bt_ctf_stream_class *stream_class = NULL; if (!name || !strlen(name)) { @@ -67,6 +68,11 @@ struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) goto error_destroy; } + ret = init_packet_context(stream_class, BT_CTF_BYTE_ORDER_NATIVE); + if (ret) { + goto error_destroy; + } + bt_ctf_ref_init(&stream_class->ref_count); return stream_class; @@ -257,6 +263,48 @@ end: return event_class; } +struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!stream_class) { + goto end; + } + + assert(stream_class->packet_context_type); + bt_ctf_field_type_get(stream_class->packet_context_type); + ret = stream_class->packet_context_type; +end: + return ret; +} + +int bt_ctf_stream_class_set_packet_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type) +{ + int ret = 0; + + if (!stream_class || !packet_context_type) { + ret = -1; + goto end; + } + + assert(stream_class->packet_context_type); + if (bt_ctf_field_type_get_type_id(stream_class->packet_context_type) != + CTF_TYPE_STRUCT) { + /* A packet context must be a structure */ + ret = -1; + goto end; + } + + bt_ctf_field_type_put(stream_class->packet_context_type); + bt_ctf_field_type_get(packet_context_type); + stream_class->packet_context_type = packet_context_type; +end: + return ret; +} + void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class) { if (!stream_class) { @@ -283,6 +331,7 @@ void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class) } stream_class->frozen = 1; + bt_ctf_field_type_freeze(stream_class->packet_context_type); bt_ctf_clock_freeze(stream_class->clock); g_ptr_array_foreach(stream_class->event_classes, (GFunc)bt_ctf_event_class_freeze, NULL); @@ -294,11 +343,6 @@ int bt_ctf_stream_class_set_byte_order(struct bt_ctf_stream_class *stream_class, { int ret = 0; - ret = init_packet_context(stream_class, byte_order); - if (ret) { - goto end; - } - ret = init_event_header(stream_class, byte_order); if (ret) { goto end; @@ -395,7 +439,6 @@ void bt_ctf_stream_class_destroy(struct bt_ctf_ref *ref) bt_ctf_field_type_put(stream_class->event_header_type); bt_ctf_field_put(stream_class->event_header); bt_ctf_field_type_put(stream_class->packet_context_type); - bt_ctf_field_put(stream_class->packet_context); bt_ctf_field_type_put(stream_class->event_context_type); bt_ctf_field_put(stream_class->event_context); g_free(stream_class); @@ -511,10 +554,6 @@ int init_packet_context(struct bt_ctf_stream_class *stream_class, } stream_class->packet_context_type = packet_context_type; - stream_class->packet_context = bt_ctf_field_create(packet_context_type); - if (!stream_class->packet_context) { - ret = -1; - } end: if (ret) { bt_ctf_field_type_put(packet_context_type); diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c index e618251e..9b0be90b 100644 --- a/formats/ctf/ir/stream.c +++ b/formats/ctf/ir/stream.c @@ -48,6 +48,7 @@ BT_HIDDEN struct bt_ctf_stream *bt_ctf_stream_create( struct bt_ctf_stream_class *stream_class) { + int ret; struct bt_ctf_stream *stream = NULL; if (!stream_class) { @@ -60,6 +61,19 @@ struct bt_ctf_stream *bt_ctf_stream_create( } bt_ctf_ref_init(&stream->ref_count); + stream->packet_context = bt_ctf_field_create( + stream_class->packet_context_type); + if (!stream->packet_context) { + goto error_destroy; + } + + /* Initialize events_discarded*/ + ret = set_structure_field_integer(stream->packet_context, + "events_discarded", 0); + if (ret) { + goto error_destroy; + } + stream->pos.fd = -1; stream->id = stream_class->next_stream_id++; stream->stream_class = stream_class; @@ -69,6 +83,9 @@ struct bt_ctf_stream *bt_ctf_stream_create( (GDestroyNotify)bt_ctf_event_put); end: return stream; +error_destroy: + bt_ctf_stream_destroy(&stream->ref_count); + return NULL; } BT_HIDDEN @@ -107,25 +124,127 @@ int bt_ctf_stream_get_discarded_events_count( struct bt_ctf_stream *stream, uint64_t *count) { int64_t ret = 0; + int field_signed; + struct bt_ctf_field *events_discarded_field = NULL; + struct bt_ctf_field_type *events_discarded_field_type = NULL; - if (!stream || !count) { + if (!stream || !count || !stream->packet_context) { ret = -1; goto end; } - *count = stream->events_discarded; + events_discarded_field = bt_ctf_field_structure_get_field( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + ret = -1; + goto end; + } + + events_discarded_field_type = bt_ctf_field_get_type( + events_discarded_field); + if (!events_discarded_field_type) { + ret = -1; + goto end; + } + + field_signed = bt_ctf_field_type_integer_get_signed( + events_discarded_field_type); + if (field_signed < 0) { + ret = field_signed; + goto end; + } + + if (field_signed) { + int64_t signed_count; + + ret = bt_ctf_field_signed_integer_get_value( + events_discarded_field, &signed_count); + if (ret) { + goto end; + } + if (signed_count < 0) { + /* Invalid value */ + ret = -1; + goto end; + } + *count = (uint64_t) signed_count; + } else { + ret = bt_ctf_field_unsigned_integer_get_value( + events_discarded_field, count); + if (ret) { + goto end; + } + } end: + if (events_discarded_field) { + bt_ctf_field_put(events_discarded_field); + } + if (events_discarded_field_type) { + bt_ctf_field_type_put(events_discarded_field_type); + } return ret; } void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, uint64_t event_count) { - if (!stream) { - return; + int ret; + int field_signed; + uint64_t previous_count; + uint64_t new_count; + struct bt_ctf_field *events_discarded_field = NULL; + struct bt_ctf_field_type *events_discarded_field_type = NULL; + + if (!stream || !stream->packet_context) { + goto end; + } + + ret = bt_ctf_stream_get_discarded_events_count(stream, + &previous_count); + if (ret) { + goto end; + } + + events_discarded_field = bt_ctf_field_structure_get_field( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + goto end; + } + + events_discarded_field_type = bt_ctf_field_get_type( + events_discarded_field); + if (!events_discarded_field_type) { + goto end; + } + + field_signed = bt_ctf_field_type_integer_get_signed( + events_discarded_field_type); + if (field_signed < 0) { + goto end; } - stream->events_discarded += event_count; + new_count = previous_count + event_count; + if (field_signed) { + ret = bt_ctf_field_signed_integer_set_value( + events_discarded_field, (int64_t) new_count); + if (ret) { + goto end; + } + } else { + ret = bt_ctf_field_unsigned_integer_set_value( + events_discarded_field, new_count); + if (ret) { + goto end; + } + } + +end: + if (events_discarded_field) { + bt_ctf_field_put(events_discarded_field); + } + if (events_discarded_field_type) { + bt_ctf_field_type_put(events_discarded_field_type); + } } int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, @@ -156,11 +275,53 @@ end: return ret; } +struct bt_ctf_field *bt_ctf_stream_get_packet_context( + struct bt_ctf_stream *stream) +{ + struct bt_ctf_field *packet_context = NULL; + + if (!stream) { + goto end; + } + + packet_context = stream->packet_context; +end: + if (packet_context) { + bt_ctf_field_get(packet_context); + } + return packet_context; +} + +int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream, + struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_type *field_type; + + if (!stream || !field) { + ret = -1; + goto end; + } + + field_type = bt_ctf_field_get_type(field); + if (field_type != stream->stream_class->packet_context_type) { + ret = -1; + goto end; + } + + bt_ctf_field_type_put(field_type); + bt_ctf_field_get(field); + bt_ctf_field_put(stream->packet_context); + stream->packet_context = field; +end: + return ret; +} + int bt_ctf_stream_flush(struct bt_ctf_stream *stream) { int ret = 0; size_t i; - uint64_t timestamp_begin, timestamp_end; + uint64_t timestamp_begin, timestamp_end, events_discarded; struct bt_ctf_stream_class *stream_class; struct bt_ctf_field *integer = NULL; struct ctf_stream_pos packet_context_pos; @@ -183,31 +344,27 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) stream->events, 0))->timestamp; timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index( stream->events, stream->events->len - 1))->timestamp; - ret = set_structure_field_integer(stream_class->packet_context, + + /* Set the default context attributes if present and unset. */ + ret = set_structure_field_integer(stream->packet_context, "timestamp_begin", timestamp_begin); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->packet_context, + ret = set_structure_field_integer(stream->packet_context, "timestamp_end", timestamp_end); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->packet_context, - "events_discarded", stream->events_discarded); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->packet_context, + ret = set_structure_field_integer(stream->packet_context, "content_size", UINT64_MAX); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->packet_context, + ret = set_structure_field_integer(stream->packet_context, "packet_size", UINT64_MAX); if (ret) { goto end; @@ -216,12 +373,31 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) /* Write packet context */ memcpy(&packet_context_pos, &stream->pos, sizeof(struct ctf_stream_pos)); - ret = bt_ctf_field_serialize(stream_class->packet_context, + ret = bt_ctf_field_serialize(stream->packet_context, &stream->pos); if (ret) { goto end; } + ret = bt_ctf_stream_get_discarded_events_count(stream, + &events_discarded); + if (ret) { + goto end; + } + + /* Unset the packet context's fields. */ + ret = bt_ctf_field_reset(stream->packet_context); + if (ret) { + goto end; + } + + /* Set the previous number of discarded events. */ + ret = set_structure_field_integer(stream->packet_context, + "events_discarded", events_discarded); + if (ret) { + goto end; + } + for (i = 0; i < stream->events->len; i++) { struct bt_ctf_event *event = g_ptr_array_index( stream->events, i); @@ -229,6 +405,11 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) event->event_class); uint64_t timestamp = bt_ctf_event_get_timestamp(event); + ret = bt_ctf_field_reset(stream_class->event_header); + if (ret) { + goto end; + } + ret = set_structure_field_integer(stream_class->event_header, "id", event_id); if (ret) { @@ -261,19 +442,19 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) * packet is resized). */ packet_context_pos.base_mma = stream->pos.base_mma; - ret = set_structure_field_integer(stream_class->packet_context, + ret = set_structure_field_integer(stream->packet_context, "content_size", stream->pos.offset); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->packet_context, + ret = set_structure_field_integer(stream->packet_context, "packet_size", stream->pos.packet_size); if (ret) { goto end; } - ret = bt_ctf_field_serialize(stream_class->packet_context, + ret = bt_ctf_field_serialize(stream->packet_context, &packet_context_pos); if (ret) { goto end; @@ -318,8 +499,16 @@ void bt_ctf_stream_destroy(struct bt_ctf_ref *ref) if (close(stream->pos.fd)) { perror("close"); } - bt_ctf_stream_class_put(stream->stream_class); - g_ptr_array_free(stream->events, TRUE); + + if (stream->stream_class) { + bt_ctf_stream_class_put(stream->stream_class); + } + if (stream->events) { + g_ptr_array_free(stream->events, TRUE); + } + if (stream->packet_context) { + bt_ctf_field_put(stream->packet_context); + } g_free(stream); } @@ -328,14 +517,25 @@ int set_structure_field_integer(struct bt_ctf_field *structure, char *name, uint64_t value) { int ret = 0; - struct bt_ctf_field *integer = bt_ctf_field_structure_get_field(structure, name); - if (!integer) { + + if (!structure || !name) { ret = -1; goto end; } + if (!integer) { + /* Field not found, not an error. */ + goto end; + } + + /* Make sure the payload has not already been set. */ + if (!bt_ctf_field_validate(integer)) { + /* Payload already set, not an error */ + goto end; + } + ret = bt_ctf_field_unsigned_integer_set_value(integer, value); end: bt_ctf_field_put(integer); diff --git a/formats/ctf/writer/writer.c b/formats/ctf/writer/writer.c index a1605fce..460ac81c 100644 --- a/formats/ctf/writer/writer.c +++ b/formats/ctf/writer/writer.c @@ -215,6 +215,13 @@ struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, goto error; } + ret = bt_ctf_stream_class_set_byte_order(stream_class, + writer->byte_order == LITTLE_ENDIAN ? + BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN); + if (ret) { + goto error; + } + stream = bt_ctf_stream_create(stream_class); if (!stream) { goto error; @@ -227,13 +234,6 @@ struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, bt_ctf_stream_set_flush_callback(stream, (flush_func)stream_flush_cb, writer); - ret = bt_ctf_stream_class_set_byte_order(stream->stream_class, - writer->byte_order == LITTLE_ENDIAN ? - BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN); - if (ret) { - goto error; - } - for (i = 0; i < writer->stream_classes->len; i++) { if (writer->stream_classes->pdata[i] == stream->stream_class) { diff --git a/include/babeltrace/ctf-ir/event-fields-internal.h b/include/babeltrace/ctf-ir/event-fields-internal.h index b79a4288..89b9496b 100644 --- a/include/babeltrace/ctf-ir/event-fields-internal.h +++ b/include/babeltrace/ctf-ir/event-fields-internal.h @@ -90,9 +90,14 @@ BT_HIDDEN int bt_ctf_field_structure_set_field(struct bt_ctf_field *structure, const char *name, struct bt_ctf_field *value); +/* Validate that the field's payload is set. */ BT_HIDDEN int bt_ctf_field_validate(struct bt_ctf_field *field); +/* Mark field payload as unset. */ +BT_HIDDEN +int bt_ctf_field_reset(struct bt_ctf_field *field); + BT_HIDDEN int bt_ctf_field_serialize(struct bt_ctf_field *field, struct ctf_stream_pos *pos); diff --git a/include/babeltrace/ctf-ir/stream-class-internal.h b/include/babeltrace/ctf-ir/stream-class-internal.h index c53823d1..67a9d17b 100644 --- a/include/babeltrace/ctf-ir/stream-class-internal.h +++ b/include/babeltrace/ctf-ir/stream-class-internal.h @@ -47,7 +47,6 @@ struct bt_ctf_stream_class { struct bt_ctf_field_type *event_header_type; struct bt_ctf_field *event_header; struct bt_ctf_field_type *packet_context_type; - struct bt_ctf_field *packet_context; struct bt_ctf_field_type *event_context_type; struct bt_ctf_field *event_context; int frozen; diff --git a/include/babeltrace/ctf-ir/stream-class.h b/include/babeltrace/ctf-ir/stream-class.h index ef6bc778..5c5918d1 100644 --- a/include/babeltrace/ctf-ir/stream-class.h +++ b/include/babeltrace/ctf-ir/stream-class.h @@ -44,6 +44,14 @@ struct bt_ctf_clock; * Allocate a new stream class of the given name. The creation of an event class * sets its reference count to 1. * + * A stream class' packet context is a structure initialized with the following + * fields: + * - uint64_t timestamp_begin + * - uint64_t timestamp_end + * - uint64_t content_size + * - uint64_t packet_size + * - uint64_t events_discarded + * * @param name Stream name. * * Returns an allocated stream class on success, NULL on error. @@ -162,6 +170,29 @@ extern struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class( extern struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_name( struct bt_ctf_stream_class *stream_class, const char *name); +/* + * bt_ctf_stream_class_get_packet_context_type: get the stream class' packet + * context type. + * + * @param stream_class Stream class. + * + * Returns the packet context's type, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_packet_context_type: set the stream class' packet + * context type. + * + * @param stream_class Stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_packet_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type); + /* * bt_ctf_stream_class_get and bt_ctf_stream_class_put: increment and * decrement the stream class' reference count. diff --git a/include/babeltrace/ctf-ir/stream-internal.h b/include/babeltrace/ctf-ir/stream-internal.h index daaa430b..9214abb8 100644 --- a/include/babeltrace/ctf-ir/stream-internal.h +++ b/include/babeltrace/ctf-ir/stream-internal.h @@ -51,7 +51,7 @@ struct bt_ctf_stream { GPtrArray *events; struct ctf_stream_pos pos; unsigned int flushed_packet_count; - uint64_t events_discarded; + struct bt_ctf_field *packet_context; }; BT_HIDDEN diff --git a/include/babeltrace/ctf-ir/stream.h b/include/babeltrace/ctf-ir/stream.h index abf50904..d9e2bc26 100644 --- a/include/babeltrace/ctf-ir/stream.h +++ b/include/babeltrace/ctf-ir/stream.h @@ -43,6 +43,10 @@ struct bt_ctf_stream; * bt_ctf_stream_get_discarded_events_count: get the number of discarded * events associated with this stream. * + * Note that discarded events are not stored if the stream's packet + * context has no "events_discarded" field. An error will be returned + * in that case. + * * @param stream Stream instance. * * Returns the number of discarded events, a negative value on error. @@ -53,7 +57,8 @@ extern int bt_ctf_stream_get_discarded_events_count( /* * bt_ctf_stream_append_discarded_events: increment discarded events count. * - * Increase the current packet's discarded event count. + * Increase the current packet's discarded event count. Has no effect if the + * stream class' packet context has no "events_discarded" field. * * @param stream Stream instance. * @param event_count Number of discarded events to add to the stream's current @@ -79,11 +84,41 @@ extern void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, extern int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, struct bt_ctf_event *event); +/* + * bt_ctf_stream_get_packet_context: get a stream's packet context. + * + * @param stream Stream instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_stream_get_packet_context( + struct bt_ctf_stream *stream); + +/* + * bt_ctf_stream_set_packet_context: set a stream's packet context. + * + * The packet context's type must match the stream class' packet + * context type. + * + * @param stream Stream instance. + * @param packet_context Packet context field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern int bt_ctf_stream_set_packet_context( + struct bt_ctf_stream *stream, + struct bt_ctf_field *packet_context); + /* * bt_ctf_stream_flush: flush a stream. * - * The stream's current packet's events will be flushed to disk. Events - * subsequently appended to the stream will be added to a new packet. + * The stream's current packet's events will be flushed, thus closing the + * current packet. Events subsequently appended to the stream will be + * added to a new packet. + * + * Flushing will also set the packet context's default attributes if + * they remained unset while populating the current packet. These default + * attributes, along with their expected types, are detailed in stream-class.h. * * @param stream Stream instance. * diff --git a/tests/lib/test_ctf_writer.c b/tests/lib/test_ctf_writer.c index bbe354f2..c6429331 100644 --- a/tests/lib/test_ctf_writer.c +++ b/tests/lib/test_ctf_writer.c @@ -287,6 +287,8 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, uint64_t ret_range_start_uint64_t, ret_range_end_uint64_t; struct bt_ctf_clock *ret_clock; struct bt_ctf_event_class *ret_event_class; + struct bt_ctf_field *packet_context; + struct bt_ctf_field *packet_context_field; ok(uint_12_type, "Create an unsigned integer type"); @@ -517,6 +519,29 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, ok(bt_ctf_stream_append_event(stream, simple_event) == 0, "Append simple event to trace stream"); + ok(bt_ctf_stream_get_packet_context(NULL) == NULL, + "bt_ctf_stream_get_packet_context handles NULL correctly"); + packet_context = bt_ctf_stream_get_packet_context(stream); + ok(packet_context, + "bt_ctf_stream_get_packet_context returns a packet context"); + + packet_context_field = bt_ctf_field_structure_get_field(packet_context, + "packet_size"); + ok(packet_context_field, + "Packet context contains the default packet_size field."); + bt_ctf_field_put(packet_context_field); + packet_context_field = bt_ctf_field_structure_get_field(packet_context, + "custom_field"); + ok(bt_ctf_field_unsigned_integer_set_value(packet_context_field, 8) == 0, + "Custom packet context field value successfully set."); + + ok(bt_ctf_stream_set_packet_context(NULL, packet_context_field) < 0, + "bt_ctf_stream_set_packet_context handles a NULL stream correctly"); + ok(bt_ctf_stream_set_packet_context(stream, NULL) < 0, + "bt_ctf_stream_set_packet_context handles a NULL packet context correctly"); + ok(bt_ctf_stream_set_packet_context(stream, packet_context) == 0, + "Successfully set a stream's packet context"); + ok(bt_ctf_stream_flush(stream) == 0, "Flush trace stream with one event"); @@ -534,6 +559,8 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, bt_ctf_field_put(enum_field_unsigned); bt_ctf_field_put(enum_container_field); bt_ctf_field_put(enum_container_field_unsigned); + bt_ctf_field_put(packet_context); + bt_ctf_field_put(packet_context_field); } void append_complex_event(struct bt_ctf_stream_class *stream_class, @@ -574,6 +601,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, size_t ret_size_t; struct bt_ctf_stream_class *ret_stream_class; struct bt_ctf_event_class *ret_event_class; + struct bt_ctf_field *packet_context, *packet_context_field; bt_ctf_field_type_set_alignment(int_16_type, 32); bt_ctf_field_type_integer_set_signed(int_16_type, 1); @@ -921,6 +949,16 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, bt_ctf_clock_set_time(clock, ++current_time); ok(bt_ctf_stream_append_event(stream, event) == 0, "Append a complex event to a stream"); + + /* + * Populate the custom packet context field with a dummy value + * otherwise flush will fail. + */ + packet_context = bt_ctf_stream_get_packet_context(stream); + packet_context_field = bt_ctf_field_structure_get_field(packet_context, + "custom_field"); + bt_ctf_field_unsigned_integer_set_value(packet_context_field, 1); + ok(bt_ctf_stream_flush(stream) == 0, "Flush a stream containing a complex event"); @@ -934,6 +972,8 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, bt_ctf_field_put(enum_container_field); bt_ctf_field_put(variant_field); bt_ctf_field_put(ret_field); + bt_ctf_field_put(packet_context_field); + bt_ctf_field_put(packet_context); bt_ctf_field_type_put(uint_35_type); bt_ctf_field_type_put(int_16_type); bt_ctf_field_type_put(string_type); @@ -1262,6 +1302,8 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class, struct bt_ctf_field *ret_field; struct bt_ctf_field_type *ret_field_type; uint64_t ret_uint64; + int events_appended = 0; + struct bt_ctf_field *packet_context, *packet_context_field; ret |= bt_ctf_event_class_add_field(event_class, integer_type, "field_1"); @@ -1310,7 +1352,8 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class, break; } } - + + events_appended = 1; ok(bt_ctf_stream_get_discarded_events_count(NULL, &ret_uint64) == -1, "bt_ctf_stream_get_discarded_events_count handles a NULL stream correctly"); ok(bt_ctf_stream_get_discarded_events_count(stream, NULL) == -1, @@ -1324,7 +1367,17 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class, "bt_ctf_stream_get_discarded_events_count returns a correct number of discarded events when some were discarded"); end: - ok(ret == 0, "Append 100 000 events to a stream"); + ok(events_appended, "Append 100 000 events to a stream"); + + /* + * Populate the custom packet context field with a dummy value + * otherwise flush will fail. + */ + packet_context = bt_ctf_stream_get_packet_context(stream); + packet_context_field = bt_ctf_field_structure_get_field(packet_context, + "custom_field"); + bt_ctf_field_unsigned_integer_set_value(packet_context_field, 2); + ok(bt_ctf_stream_flush(stream) == 0, "Flush a stream that forces a packet resize"); ret = bt_ctf_stream_get_discarded_events_count(stream, &ret_uint64); @@ -1332,6 +1385,8 @@ end: "bt_ctf_stream_get_discarded_events_count returns a correct number of discarded events after a flush"); bt_ctf_field_type_put(integer_type); bt_ctf_field_type_put(string_type); + bt_ctf_field_put(packet_context); + bt_ctf_field_put(packet_context_field); bt_ctf_event_class_put(event_class); } @@ -1356,6 +1411,8 @@ int main(int argc, char **argv) struct bt_ctf_stream_class *stream_class; struct bt_ctf_stream *stream1; const char *ret_string; + struct bt_ctf_field_type *packet_context_type, *packet_context_field_type; + int ret; if (argc < 3) { printf("Usage: tests-ctf-writer path_to_ctf_parser_test path_to_babeltrace\n"); @@ -1518,7 +1575,7 @@ int main(int argc, char **argv) "bt_ctf_stream_class_get_name handles NULL correctly"); ret_string = bt_ctf_stream_class_get_name(stream_class); ok(!strcmp(ret_string, "test_stream"), - "bt_ctf_stream_class_get_name returns a correct stream class name"); + "bt_ctf_stream_class_get_name returns a correct stream class name"); ok(bt_ctf_stream_class_get_clock(stream_class) == NULL, "bt_ctf_stream_class_get_clock returns NULL when a clock was not set"); @@ -1547,10 +1604,41 @@ int main(int argc, char **argv) ok(bt_ctf_stream_class_get_id(stream_class) == 123, "bt_ctf_stream_class_get_id returns the correct value"); + /* Create a "uint5_t" equivalent custom packet context field */ + packet_context_field_type = bt_ctf_field_type_integer_create(5); + + ok(bt_ctf_stream_class_get_packet_context_type(NULL) == NULL, + "bt_ctf_stream_class_get_packet_context_type handles NULL correctly"); + + /* Add a custom field to the stream class' packet context */ + packet_context_type = bt_ctf_stream_class_get_packet_context_type(stream_class); + ok(packet_context_type, + "bt_ctf_stream_class_get_packet_context_type returns a packet context type."); + ok(bt_ctf_field_type_get_type_id(packet_context_type) == CTF_TYPE_STRUCT, + "Packet context is a structure"); + + ok(bt_ctf_stream_class_set_packet_context_type(NULL, packet_context_type), + "bt_ctf_stream_class_set_packet_context_type handles a NULL stream class correctly"); + ok(bt_ctf_stream_class_set_packet_context_type(stream_class, NULL), + "bt_ctf_stream_class_set_packet_context_type handles a NULL packet context type correctly"); + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + packet_context_field_type, "custom_field"); + ok(ret == 0, "Packet context field added successfully"); + + /* Instantiate a stream and append events */ stream1 = bt_ctf_writer_create_stream(writer, stream_class); ok(stream1, "Instanciate a stream class from writer"); + /* + * Try to modify the packet context type after a stream has been + * created. + */ + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + packet_context_field_type, "should_fail"); + ok(ret < 0, + "Packet context type can't be modified once a stream class has been instanciated"); + /* Should fail after instanciating a stream (locked)*/ ok(bt_ctf_stream_class_set_clock(stream_class, clock), "Changes to a stream class that was already instantiated fail"); @@ -1572,6 +1660,8 @@ int main(int argc, char **argv) bt_ctf_stream_class_put(stream_class); bt_ctf_writer_put(writer); bt_ctf_stream_put(stream1); + bt_ctf_field_type_put(packet_context_type); + bt_ctf_field_type_put(packet_context_field_type); free(metadata_string); /* Remove all trace files and delete temporary trace directory */ -- 2.34.1