X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=formats%2Fctf%2Fir%2Fstream.c;h=c0b4e979a9ff9195b21e323bc7402110cafe335e;hb=92cbbcc5ffb90362b3616beea9a615a55c768b37;hp=d4dbc447ca6a6b1fe16d6004c90e408c97f1ee61;hpb=835b2d10c5c80ebad6427ba3794d712dd44ef145;p=babeltrace.git diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c index d4dbc447..c0b4e979 100644 --- a/formats/ctf/ir/stream.c +++ b/formats/ctf/ir/stream.c @@ -26,8 +26,9 @@ * SOFTWARE. */ -#include -#include +#include +#include +#include #include #include #include @@ -48,6 +49,45 @@ void bt_ctf_stream_destroy(struct bt_object *obj); static int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); +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; + } + + field_type = bt_ctf_field_get_type(field); + assert(field_type); + + if (bt_ctf_field_type_get_type_id(field_type) != + BT_CTF_TYPE_ID_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_put(field_type); + return ret; +} + static int set_packet_header_magic(struct bt_ctf_stream *stream) { @@ -344,17 +384,19 @@ struct bt_ctf_stream *bt_ctf_stream_create( bt_object_get_parent(trace); assert(writer); - stream->packet_context = bt_ctf_field_create( - stream_class->packet_context_type); - if (!stream->packet_context) { - goto error; - } + if (stream_class->packet_context_type) { + stream->packet_context = bt_ctf_field_create( + stream_class->packet_context_type); + if (!stream->packet_context) { + goto error; + } - /* Initialize events_discarded */ - ret = set_structure_field_integer(stream->packet_context, - "events_discarded", 0); - if (ret) { - goto error; + /* Initialize events_discarded */ + ret = set_structure_field_integer(stream->packet_context, + "events_discarded", 0); + if (ret) { + goto error; + } } stream->events = g_ptr_array_new_with_free_func( @@ -553,6 +595,86 @@ end: bt_put(events_discarded_field_type); } +static int auto_populate_event_header(struct bt_ctf_stream *stream, + struct bt_ctf_event *event) +{ + int ret = 0; + struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL; + struct bt_ctf_clock_class *mapped_clock_class = NULL; + + if (!event || event->frozen) { + ret = -1; + goto end; + } + + /* + * The condition to automatically set the ID are: + * + * 1. The event header field "id" exists and is an integer + * field. + * 2. The event header field "id" is NOT set. + */ + id_field = bt_ctf_field_structure_get_field(event->event_header, "id"); + if (id_field && !bt_ctf_field_is_set(id_field)) { + ret = set_integer_field_value(id_field, + (uint64_t) bt_ctf_event_class_get_id( + event->event_class)); + if (ret) { + goto end; + } + } + + /* + * The conditions to automatically set the timestamp are: + * + * 1. The event header field "timestamp" exists and is an + * integer field. + * 2. This stream's class has a registered clock (set with + * bt_ctf_stream_class_set_clock()). + * 3. The event header field "timestamp" has its type mapped to + * a clock class which is also the clock class of this + * stream's class's registered clock. + * 4. The event header field "timestamp" is NOT set. + */ + timestamp_field = bt_ctf_field_structure_get_field(event->event_header, + "timestamp"); + if (timestamp_field && !bt_ctf_field_is_set(timestamp_field) && + stream->stream_class->clock) { + struct bt_ctf_clock_class *stream_class_clock_class = + stream->stream_class->clock->clock_class; + struct bt_ctf_field_type *timestamp_field_type = + bt_ctf_field_get_type(timestamp_field); + + assert(timestamp_field_type); + mapped_clock_class = + bt_ctf_field_type_integer_get_mapped_clock_class( + timestamp_field_type); + BT_PUT(timestamp_field_type); + if (mapped_clock_class == stream_class_clock_class) { + uint64_t timestamp; + + ret = bt_ctf_clock_get_value( + stream->stream_class->clock, + ×tamp); + if (ret) { + goto end; + } + + ret = set_integer_field_value(timestamp_field, + timestamp); + if (ret) { + goto end; + } + } + } + +end: + bt_put(id_field); + bt_put(timestamp_field); + bt_put(mapped_clock_class); + return ret; +} + int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, struct bt_ctf_event *event) { @@ -577,7 +699,7 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, } bt_object_set_parent(event, stream); - ret = bt_ctf_event_populate_event_header(event); + ret = auto_populate_event_header(stream, event); if (ret) { goto error; } @@ -750,6 +872,8 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) uint64_t timestamp_begin, timestamp_end, events_discarded; struct bt_ctf_field *integer = NULL; struct ctf_stream_pos packet_context_pos; + bool empty_packet; + uint64_t packet_size_bits; if (!stream || stream->pos.fd < 0) { /* @@ -760,14 +884,17 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) goto end; } - if (!stream->events->len) { + if (!stream->packet_context && stream->flushed_packet_count > 0) { + /* + * A stream without a packet context, and thus without + * content and packet size members, can't have more than + * one packet. + */ + ret = -1; goto end; } - ret = bt_ctf_field_validate(stream->packet_header); - if (ret) { - goto end; - } + empty_packet = (stream->events->len == 0); /* mmap the next packet */ ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); @@ -777,66 +904,68 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) goto end; } - /* Set the default context attributes if present and unset. */ - if (!get_event_header_timestamp( - ((struct bt_ctf_event *) g_ptr_array_index( - stream->events, 0))->event_header, ×tamp_begin)) { + if (stream->packet_context) { + /* Set the default context attributes if present and unset. */ + if (!empty_packet && !get_event_header_timestamp( + ((struct bt_ctf_event *) g_ptr_array_index( + stream->events, 0))->event_header, ×tamp_begin)) { + ret = set_structure_field_integer(stream->packet_context, + "timestamp_begin", timestamp_begin); + if (ret) { + goto end; + } + } + + if (!empty_packet && !get_event_header_timestamp( + ((struct bt_ctf_event *) g_ptr_array_index( + stream->events, stream->events->len - 1))->event_header, + ×tamp_end)) { + + ret = set_structure_field_integer(stream->packet_context, + "timestamp_end", timestamp_end); + if (ret) { + goto end; + } + } ret = set_structure_field_integer(stream->packet_context, - "timestamp_begin", timestamp_begin); + "content_size", UINT64_MAX); if (ret) { goto end; } - } - - if (!get_event_header_timestamp( - ((struct bt_ctf_event *) g_ptr_array_index( - stream->events, stream->events->len - 1))->event_header, - ×tamp_end)) { ret = set_structure_field_integer(stream->packet_context, - "timestamp_end", timestamp_end); + "packet_size", UINT64_MAX); if (ret) { goto end; } - } - ret = set_structure_field_integer(stream->packet_context, - "content_size", UINT64_MAX); - if (ret) { - goto end; - } - ret = set_structure_field_integer(stream->packet_context, - "packet_size", UINT64_MAX); - if (ret) { - goto end; - } - - /* Write packet context */ - memcpy(&packet_context_pos, &stream->pos, - sizeof(struct ctf_stream_pos)); - ret = bt_ctf_field_serialize(stream->packet_context, - &stream->pos); - if (ret) { - goto end; - } + /* Write packet context */ + memcpy(&packet_context_pos, &stream->pos, + sizeof(struct ctf_stream_pos)); + 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; - } + 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; - } + /* 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; + /* 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++) { @@ -871,33 +1000,41 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) } } - /* - * Update the packet total size and content size and overwrite the - * packet context. - * Copy base_mma as the packet may have been remapped (e.g. when a - * packet is resized). - */ - packet_context_pos.base_mma = stream->pos.base_mma; - ret = set_structure_field_integer(stream->packet_context, - "content_size", stream->pos.offset); - if (ret) { - goto end; - } + /* Rounded-up in case content_size is not byte-aligned. */ + packet_size_bits = (stream->pos.offset + (CHAR_BIT - 1)) & + ~(CHAR_BIT - 1); + stream->pos.packet_size = packet_size_bits; - ret = set_structure_field_integer(stream->packet_context, - "packet_size", stream->pos.packet_size); - if (ret) { - goto end; - } + if (stream->packet_context) { + /* + * Update the packet total size and content size and overwrite + * the packet context. + * Copy base_mma as the packet may have been remapped (e.g. when + * a packet is resized). + */ + packet_context_pos.base_mma = stream->pos.base_mma; + ret = set_structure_field_integer(stream->packet_context, + "content_size", stream->pos.offset); + if (ret) { + goto end; + } - ret = bt_ctf_field_serialize(stream->packet_context, - &packet_context_pos); - if (ret) { - goto end; + ret = set_structure_field_integer(stream->packet_context, + "packet_size", packet_size_bits); + if (ret) { + goto end; + } + + ret = bt_ctf_field_serialize(stream->packet_context, + &packet_context_pos); + if (ret) { + goto end; + } } g_ptr_array_set_size(stream->events, 0); stream->flushed_packet_count++; + stream->size += packet_size_bits / CHAR_BIT; end: bt_put(integer); return ret; @@ -920,8 +1057,24 @@ void bt_ctf_stream_destroy(struct bt_object *obj) stream = container_of(obj, struct bt_ctf_stream, base); ctf_fini_pos(&stream->pos); - if (stream->pos.fd >= 0 && close(stream->pos.fd)) { - perror("close"); + if (stream->pos.fd >= 0) { + int ret; + + /* + * Truncate the file's size to the minimum required to fit the + * last packet as we might have grown it too much on the last + * mmap. + */ + do { + ret = ftruncate(stream->pos.fd, stream->size); + } while (ret == -1 && errno == EINTR); + if (ret) { + perror("ftruncate"); + } + + if (close(stream->pos.fd)) { + perror("close"); + } } if (stream->events) { @@ -1000,3 +1153,17 @@ const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream) end: return name; } + +int bt_ctf_stream_is_writer(struct bt_ctf_stream *stream) +{ + int ret = -1; + + if (!stream) { + goto end; + } + + ret = (stream->pos.fd >= 0); + +end: + return ret; +}