From 9f476966aa40bd0de2cd0654623ea03f8a3254eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Fri, 9 Jan 2015 11:00:44 -0500 Subject: [PATCH] Add event header accessors and support for custom event headers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- formats/ctf/ir/event.c | 171 +++++++++++++++++- formats/ctf/ir/stream-class.c | 47 ++++- formats/ctf/ir/stream.c | 15 +- .../babeltrace/ctf-ir/event-fields-internal.h | 2 +- include/babeltrace/ctf-ir/event-internal.h | 14 ++ include/babeltrace/ctf-ir/event.h | 25 +++ .../babeltrace/ctf-ir/stream-class-internal.h | 3 +- include/babeltrace/ctf-ir/stream-class.h | 32 ++++ include/babeltrace/ctf-ir/stream-internal.h | 4 +- include/babeltrace/ctf-ir/stream.h | 53 ++++-- 10 files changed, 335 insertions(+), 31 deletions(-) diff --git a/formats/ctf/ir/event.c b/formats/ctf/ir/event.c index 943295cb..ee019ff6 100644 --- a/formats/ctf/ir/event.c +++ b/formats/ctf/ir/event.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ static void bt_ctf_event_class_destroy(struct bt_ctf_ref *ref); static void bt_ctf_event_destroy(struct bt_ctf_ref *ref); +static +int set_integer_field_value(struct bt_ctf_field *field, uint64_t value); struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name) { @@ -284,13 +287,36 @@ struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class) bt_ctf_event_class_get(event_class); bt_ctf_event_class_freeze(event_class); event->event_class = event_class; + + assert(event_class->stream_class); + assert(event_class->stream_class->event_header_type); + + event->event_header = bt_ctf_field_create( + event_class->stream_class->event_header_type); + if (!event->event_header) { + goto error_destroy; + } if (event_class->context) { event->context_payload = bt_ctf_field_create( event_class->context); + if (!event->context_payload) { + goto error_destroy; + } } event->fields_payload = bt_ctf_field_create(event_class->fields); + if (!event->fields_payload) { + goto error_destroy; + } end: + /* + * Freeze the stream class since the event header must not be changed + * anymore. + */ + bt_ctf_stream_class_freeze(event_class->stream_class); return event; +error_destroy: + bt_ctf_event_destroy(&event->ref_count); + return NULL; } struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event) @@ -387,6 +413,58 @@ end: return field; } +struct bt_ctf_field *bt_ctf_event_get_event_header( + struct bt_ctf_event *event) +{ + struct bt_ctf_field *header = NULL; + + if (!event || !event->event_header) { + goto end; + } + + header = event->event_header; + bt_ctf_field_get(header); +end: + return header; +} + +int bt_ctf_event_set_event_header(struct bt_ctf_event *event, + struct bt_ctf_field *header) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + + if (!event || !header) { + ret = -1; + goto end; + } + + /* Could be NULL since an event class doesn't own a stream class */ + if (!event->event_class->stream_class) { + ret = -1; + goto end; + } + + /* + * Ensure the provided header's type matches the one registered to the + * stream class. + */ + field_type = bt_ctf_field_get_type(header); + if (field_type != event->event_class->stream_class->event_header_type) { + ret = -1; + goto end; + } + + bt_ctf_field_get(header); + bt_ctf_field_put(event->event_header); + event->event_header = header; +end: + if (field_type) { + bt_ctf_field_type_put(field_type); + } + return ret; +} + struct bt_ctf_field *bt_ctf_event_get_event_context( struct bt_ctf_event *event) { @@ -484,6 +562,9 @@ void bt_ctf_event_destroy(struct bt_ctf_ref *ref) if (event->event_class) { bt_ctf_event_class_put(event->event_class); } + if (event->event_header) { + bt_ctf_field_put(event->event_header); + } if (event->context_payload) { bt_ctf_field_put(event->context_payload); } @@ -493,6 +574,49 @@ void bt_ctf_event_destroy(struct bt_ctf_ref *ref) g_free(event); } +static +int set_integer_field_value(struct bt_ctf_field* field, uint64_t value) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + + if (!field) { + ret = -1; + goto end; + } + + if (!bt_ctf_field_validate(field)) { + /* Payload already set, skip! (not an error) */ + goto end; + } + + field_type = bt_ctf_field_get_type(field); + assert(field_type); + + if (bt_ctf_field_type_get_type_id(field_type) != CTF_TYPE_INTEGER) { + /* Not an integer and the value is unset, error. */ + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_get_signed(field_type)) { + ret = bt_ctf_field_signed_integer_set_value(field, (int64_t) value); + if (ret) { + /* Value is out of range, error. */ + goto end; + } + } else { + ret = bt_ctf_field_unsigned_integer_set_value(field, value); + if (ret) { + /* Value is out of range, error. */ + goto end; + } + } +end: + bt_ctf_field_type_put(field_type); + return ret; +} + BT_HIDDEN void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class) { @@ -549,7 +673,8 @@ int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, context->current_indentation_level = 1; g_string_assign(context->field_name, ""); - g_string_append_printf(context->string, "event {\n\tname = \"%s\";\n\tid = %u;\n\tstream_id = %" PRId64 ";\n", + g_string_append_printf(context->string, + "event {\n\tname = \"%s\";\n\tid = %u;\n\tstream_id = %" PRId64 ";\n", g_quark_to_string(event_class->name), event_class->id, stream_id); @@ -586,6 +711,11 @@ int bt_ctf_event_validate(struct bt_ctf_event *event) int ret; assert(event); + ret = bt_ctf_field_validate(event->event_header); + if (ret) { + goto end; + } + ret = bt_ctf_field_validate(event->fields_payload); if (ret) { goto end; @@ -646,3 +776,42 @@ uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event) assert(event); return event->timestamp; } + +BT_HIDDEN +int bt_ctf_event_populate_event_header(struct bt_ctf_event *event) +{ + int ret = 0; + struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL; + + if (!event) { + ret = -1; + goto end; + } + + id_field = bt_ctf_field_structure_get_field(event->event_header, "id"); + if (id_field) { + ret = set_integer_field_value(id_field, + (uint64_t) event->event_class->id); + if (ret) { + goto end; + } + } + + timestamp_field = bt_ctf_field_structure_get_field(event->event_header, + "timestamp"); + if (timestamp_field) { + ret = set_integer_field_value(timestamp_field, + (uint64_t) event->timestamp); + if (ret) { + goto end; + } + } +end: + if (id_field) { + bt_ctf_field_put(id_field); + } + if (timestamp_field) { + bt_ctf_field_put(timestamp_field); + } + return ret; +} diff --git a/formats/ctf/ir/stream-class.c b/formats/ctf/ir/stream-class.c index 058f4b29..07f15651 100644 --- a/formats/ctf/ir/stream-class.c +++ b/formats/ctf/ir/stream-class.c @@ -306,6 +306,47 @@ end: return ret; } +struct bt_ctf_field_type *bt_ctf_stream_class_get_event_header_type( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!stream_class || !stream_class->event_header_type) { + goto end; + } + + assert(stream_class->event_header_type); + bt_ctf_field_type_get(stream_class->event_header_type); + ret = stream_class->event_header_type; +end: + return ret; +} + +int bt_ctf_stream_class_set_event_header_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_header_type) +{ + int ret = 0; + + if (!stream_class || !event_header_type || stream_class->frozen) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_header_type) != + CTF_TYPE_STRUCT) { + /* An event header must be a structure */ + ret = -1; + goto end; + } + + bt_ctf_field_type_put(stream_class->event_header_type); + bt_ctf_field_type_get(event_header_type); + stream_class->event_header_type = event_header_type; +end: + return ret; +} + struct bt_ctf_field_type *bt_ctf_stream_class_get_event_context_type( struct bt_ctf_stream_class *stream_class) { @@ -480,7 +521,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); if (stream_class->event_context_type) { bt_ctf_field_type_put(stream_class->event_context_type); @@ -528,11 +568,6 @@ int init_event_header(struct bt_ctf_stream_class *stream_class, } stream_class->event_header_type = event_header_type; - stream_class->event_header = bt_ctf_field_create( - stream_class->event_header_type); - if (!stream_class->event_header) { - ret = -1; - } end: if (ret) { bt_ctf_field_type_put(event_header_type); diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c index d291981e..8b60e1e8 100644 --- a/formats/ctf/ir/stream.c +++ b/formats/ctf/ir/stream.c @@ -509,6 +509,11 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, goto end; } + ret = bt_ctf_event_populate_event_header(event); + if (ret) { + goto end; + } + /* Make sure the event's payload is set */ ret = bt_ctf_event_validate(event); if (ret) { @@ -681,7 +686,6 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) int ret = 0; size_t i; 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; @@ -713,7 +717,6 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) goto end; } - stream_class = stream->stream_class; timestamp_begin = ((struct bt_ctf_event *) g_ptr_array_index( stream->events, 0))->timestamp; timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index( @@ -779,24 +782,24 @@ 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); + ret = bt_ctf_field_reset(event->event_header); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->event_header, + ret = set_structure_field_integer(event->event_header, "id", event_id); if (ret) { goto end; } - ret = set_structure_field_integer(stream_class->event_header, + ret = set_structure_field_integer(event->event_header, "timestamp", timestamp); if (ret) { goto end; } /* Write event header */ - ret = bt_ctf_field_serialize(stream_class->event_header, + ret = bt_ctf_field_serialize(event->event_header, &stream->pos); if (ret) { goto end; diff --git a/include/babeltrace/ctf-ir/event-fields-internal.h b/include/babeltrace/ctf-ir/event-fields-internal.h index 69abe136..88f372dd 100644 --- a/include/babeltrace/ctf-ir/event-fields-internal.h +++ b/include/babeltrace/ctf-ir/event-fields-internal.h @@ -90,7 +90,7 @@ 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. */ +/* Validate that the field's payload is set (returns 0 if set). */ BT_HIDDEN int bt_ctf_field_validate(struct bt_ctf_field *field); diff --git a/include/babeltrace/ctf-ir/event-internal.h b/include/babeltrace/ctf-ir/event-internal.h index ac4cd6de..5c712863 100644 --- a/include/babeltrace/ctf-ir/event-internal.h +++ b/include/babeltrace/ctf-ir/event-internal.h @@ -39,6 +39,7 @@ struct bt_ctf_event_class { GQuark name; int id_set; uint32_t id; + /* An event class does not have ownership of a stream class */ struct bt_ctf_stream_class *stream_class; /* Structure type containing the event's context */ struct bt_ctf_field_type *context; @@ -51,6 +52,7 @@ struct bt_ctf_event { struct bt_ctf_ref ref_count; uint64_t timestamp; struct bt_ctf_event_class *event_class; + struct bt_ctf_field *event_header; struct bt_ctf_field *context_payload; struct bt_ctf_field *fields_payload; }; @@ -79,4 +81,16 @@ int bt_ctf_event_set_timestamp(struct bt_ctf_event *event, uint64_t timestamp); BT_HIDDEN uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event); +/* + * Attempt to populate the "id" and "timestamp" fields of the event header if + * they are present, unset and their types are integers. + * + * Not finding these fields or encountering unexpected types is not an error + * since the user may have defined a different event header layout. In this + * case, it is expected that the fields be manually populated before appending + * an event to a stream. + */ +BT_HIDDEN +int bt_ctf_event_populate_event_header(struct bt_ctf_event *event); + #endif /* BABELTRACE_CTF_IR_EVENT_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/event.h b/include/babeltrace/ctf-ir/event.h index 948747a9..c6b30960 100644 --- a/include/babeltrace/ctf-ir/event.h +++ b/include/babeltrace/ctf-ir/event.h @@ -275,6 +275,31 @@ extern int bt_ctf_event_set_payload(struct bt_ctf_event *event, extern struct bt_ctf_field *bt_ctf_event_get_payload_by_index( struct bt_ctf_event *event, int index); +/* + * bt_ctf_event_get_header: get an event's header. + * + * @param event Event instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_event_get_header( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_set_header: set an event's header. + * + * The event header's type must match the stream class' event + * header type. + * + * @param event Event instance. + * @param header Event header field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern int bt_ctf_event_set_header( + struct bt_ctf_event *event, + struct bt_ctf_field *header); + /* * bt_ctf_event_get_event_context: Get an event's context * diff --git a/include/babeltrace/ctf-ir/stream-class-internal.h b/include/babeltrace/ctf-ir/stream-class-internal.h index 55ad787e..b25c197d 100644 --- a/include/babeltrace/ctf-ir/stream-class-internal.h +++ b/include/babeltrace/ctf-ir/stream-class-internal.h @@ -44,9 +44,8 @@ struct bt_ctf_stream_class { uint32_t id; uint32_t next_event_id; uint32_t next_stream_id; - 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_type *event_header_type; struct bt_ctf_field_type *event_context_type; int frozen; }; diff --git a/include/babeltrace/ctf-ir/stream-class.h b/include/babeltrace/ctf-ir/stream-class.h index 71b10679..b52dcb78 100644 --- a/include/babeltrace/ctf-ir/stream-class.h +++ b/include/babeltrace/ctf-ir/stream-class.h @@ -52,6 +52,11 @@ struct bt_ctf_clock; * - uint64_t packet_size * - uint64_t events_discarded * + * A stream class's event header is a structure initialized the following + * fields: + * - uint32_t id + * - uint64_t timestamp + * * @param name Stream name. * * Returns an allocated stream class on success, NULL on error. @@ -127,6 +132,8 @@ extern int bt_ctf_stream_class_set_id( * The stream class will share the ownership of "event_class" by incrementing * its reference count. * + * Note that an event class may only be added to one stream class. + * * @param stream_class Stream class. * @param event_class Event class to add to the provided stream class. * @@ -194,6 +201,31 @@ 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_event_header_type: get the stream class' + * event header type. + * + * @param stream_class Stream class. + * + * Returns the stream event header's type (a structure), NULL on error. + */ +extern struct bt_ctf_field_type * +bt_ctf_stream_class_get_event_header_type( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_event_header_type: set the stream class' + * event header type. + * + * @param stream_class Stream class. + * @param event_header_type Event header type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_event_header_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_header_type); + /* * bt_ctf_stream_class_get_event_context_type: get the stream class' * event context type. diff --git a/include/babeltrace/ctf-ir/stream-internal.h b/include/babeltrace/ctf-ir/stream-internal.h index 4b3250b0..ca6a2eb3 100644 --- a/include/babeltrace/ctf-ir/stream-internal.h +++ b/include/babeltrace/ctf-ir/stream-internal.h @@ -44,12 +44,14 @@ struct bt_ctf_stream { struct bt_ctf_stream_class *stream_class; /* Array of pointers to bt_ctf_event for the current packet */ GPtrArray *events; - /* Array of pointers to bt_ctf_field associated with each event*/ + /* Array of pointers to bt_ctf_field associated with each event */ + GPtrArray *event_headers; 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_header; struct bt_ctf_field *event_context; }; diff --git a/include/babeltrace/ctf-ir/stream.h b/include/babeltrace/ctf-ir/stream.h index f302583d..b38d80d4 100644 --- a/include/babeltrace/ctf-ir/stream.h +++ b/include/babeltrace/ctf-ir/stream.h @@ -97,6 +97,31 @@ 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_header: get a stream's packet header. + * + * @param stream Stream instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_stream_get_packet_header( + struct bt_ctf_stream *stream); + +/* + * bt_ctf_stream_set_packet_header: set a stream's packet header. + * + * The packet header's type must match the trace's packet header + * type. + * + * @param stream Stream instance. + * @param packet_header Packet header instance. + * + * Returns a field instance on success, NULL on error. + */ +extern int bt_ctf_stream_set_packet_header( + struct bt_ctf_stream *stream, + struct bt_ctf_field *packet_header); + /* * bt_ctf_stream_get_packet_context: get a stream's packet context. * @@ -123,23 +148,23 @@ extern int bt_ctf_stream_set_packet_context( struct bt_ctf_field *packet_context); /* - * bt_ctf_stream_get_event_context: get a stream's event context. + * bt_ctf_stream_get_event_header: get a stream's event header. * * @param stream Stream instance. * * Returns a field instance on success, NULL on error. */ -extern struct bt_ctf_field *bt_ctf_stream_get_event_context( +extern struct bt_ctf_field *bt_ctf_stream_get_event_header( struct bt_ctf_stream *stream); /* - * bt_ctf_stream_set_event_context: set a stream's event context. + * bt_ctf_stream_set_event_header: set a stream's event header. * - * The event context's type must match the stream class' event - * context type. + * The event header's type must match the stream class' event + * header type. * * @param stream Stream instance. - * @param event_context Event context field instance. + * @param event_header Event header field instance. * * Returns a field instance on success, NULL on error. */ @@ -148,29 +173,29 @@ extern int bt_ctf_stream_set_event_context( struct bt_ctf_field *event_context); /* - * bt_ctf_stream_get_packet_header: get a stream's packet header. + * bt_ctf_stream_get_event_context: get a stream's event context. * * @param stream Stream instance. * * Returns a field instance on success, NULL on error. */ -extern struct bt_ctf_field *bt_ctf_stream_get_packet_header( +extern struct bt_ctf_field *bt_ctf_stream_get_event_context( struct bt_ctf_stream *stream); /* - * bt_ctf_stream_set_packet_header: set a stream's packet header. + * bt_ctf_stream_set_event_context: set a stream's event context. * - * The packet header's type must match the trace's packet header - * type. + * The event context's type must match the stream class' event + * context type. * * @param stream Stream instance. - * @param packet_header Packet header instance. + * @param event_context Event context field instance. * * Returns a field instance on success, NULL on error. */ -extern int bt_ctf_stream_set_packet_header( +extern int bt_ctf_stream_set_event_context( struct bt_ctf_stream *stream, - struct bt_ctf_field *packet_header); + struct bt_ctf_field *event_context); /* * bt_ctf_stream_flush: flush a stream. -- 2.34.1