#include <babeltrace/compiler-internal.h>
#include <babeltrace/align-internal.h>
#include <inttypes.h>
+#include <unistd.h>
static
void bt_ctf_stream_destroy(struct bt_object *obj);
goto end;
}
- ret = bt_ctf_field_unsigned_integer_set_value(field,
- stream->discarded_events);
- if (ret) {
- BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
- "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
- stream, bt_ctf_stream_get_name(stream),
- field, stream->discarded_events);
+ /*
+ * If the field is set by the user, make sure that the value is
+ * greater than or equal to the stream's current count of
+ * discarded events. We do not allow wrapping here. If it's
+ * valid, update the stream's current count.
+ */
+ if (bt_ctf_field_is_set(field)) {
+ uint64_t user_val;
+
+ ret = bt_ctf_field_unsigned_integer_get_value(field,
+ &user_val);
+ if (ret) {
+ BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
+ stream, bt_ctf_stream_get_name(stream), field);
+ goto end;
+ }
+
+ if (user_val < stream->discarded_events) {
+ BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
+ "value is lesser than the stream's current discarded events count: "
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
+ "value=%" PRIu64 ", "
+ "stream-discarded-events-count=%" PRIu64,
+ stream, bt_ctf_stream_get_name(stream), field,
+ user_val, stream->discarded_events);
+ goto end;
+ }
+
+ stream->discarded_events = user_val;
} else {
- BT_LOGV("Set packet context field's `events_discarded` field's value: "
- "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
- stream, bt_ctf_stream_get_name(stream),
- field, stream->discarded_events);
+ ret = bt_ctf_field_unsigned_integer_set_value(field,
+ stream->discarded_events);
+ if (ret) {
+ BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+ stream, bt_ctf_stream_get_name(stream),
+ field, stream->discarded_events);
+ } else {
+ BT_LOGV("Set packet context field's `events_discarded` field's value: "
+ "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+ stream, bt_ctf_stream_get_name(stream),
+ field, stream->discarded_events);
+ }
}
end:
struct bt_ctf_stream *stream)
{
int fd;
- GString *filename = g_string_new(stream->stream_class->name->str);
+ GString *filename = g_string_new(NULL);
+ int64_t stream_class_id;
+ char *file_path = NULL;
BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
"stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
writer, stream, bt_ctf_stream_get_name(stream),
stream->stream_class, stream->stream_class->name->str);
- if (stream->stream_class->name->len == 0) {
- int64_t ret;
-
- ret = bt_ctf_stream_class_get_id(stream->stream_class);
- if (ret < 0) {
- BT_LOGW("Cannot get stream class's ID: "
- "stream-class-addr=%p, "
- "stream-class-name=\"%s\"",
- stream->stream_class,
- stream->stream_class->name->str);
- fd = -1;
- goto end;
+ if (stream->name && stream->name->len > 0) {
+ /* Use stream name's base name as prefix */
+ gchar *basename = g_path_get_basename(stream->name->str);
+
+ assert(basename);
+
+ if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+ g_string_assign(filename, "stream");
+ } else {
+ g_string_assign(filename, basename);
}
- g_string_printf(filename, "stream_%" PRId64, ret);
+ g_free(basename);
+ goto append_ids;
+ }
+
+ if (stream->stream_class->name &&
+ stream->stream_class->name->len > 0) {
+ /* Use stream class name's base name as prefix */
+ gchar *basename =
+ g_path_get_basename(stream->stream_class->name->str);
+
+ assert(basename);
+
+ if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+ g_string_assign(filename, "stream");
+ } else {
+ g_string_assign(filename, basename);
+ }
+
+ g_free(basename);
+ goto append_ids;
+ }
+
+ /* Default to using `stream-` as prefix */
+ g_string_assign(filename, "stream");
+
+append_ids:
+ stream_class_id = bt_ctf_stream_class_get_id(stream->stream_class);
+ assert(stream_class_id >= 0);
+ assert(stream->id >= 0);
+ g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
+ stream_class_id, stream->id);
+
+ file_path = g_build_filename(writer->path->str, filename->str, NULL);
+ if (file_path == NULL) {
+ fd = -1;
+ goto end;
}
- g_string_append_printf(filename, "_%" PRId64, stream->id);
- fd = openat(writer->trace_dir_fd, filename->str,
+ fd = open(file_path,
O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ g_free(file_path);
if (fd < 0) {
- BT_LOGW("Failed to open stream file for writing: %s: "
- "writer-trace-dir-fd=%d, filename=\"%s\", "
- "ret=%d, errno=%d", strerror(errno),
- writer->trace_dir_fd, filename->str, fd, errno);
+ BT_LOGW_ERRNO("Failed to open stream file for writing",
+ ": file_path=\"%s\", filename=\"%s\", ret=%d",
+ file_path, filename->str, fd);
goto end;
}
BT_LOGD("Created stream file for writing: "
- "stream-addr=%p, stream-name=\"%s\", writer-trace-dir-fd=%d, "
+ "stream-addr=%p, stream-name=\"%s\", "
"filename=\"%s\", fd=%d", stream, bt_ctf_stream_get_name(stream),
- writer->trace_dir_fd, filename->str, fd);
+ filename->str, fd);
end:
g_string_free(filename, TRUE);
/* Initialize events_discarded */
ret = try_set_structure_field_integer(
stream->packet_context, "events_discarded", 0);
- if (ret != 1) {
+ if (ret < 0) {
BT_LOGW("Cannot set `events_discarded` field in packet context: "
"ret=%d, packet-context-field-addr=%p",
ret, stream->packet_context);
return stream_class;
}
-int64_t bt_ctf_stream_get_discarded_events_count(
+int bt_ctf_stream_get_discarded_events_count(
struct bt_ctf_stream *stream, uint64_t *count)
{
- int64_t ret = 0;
+ int ret = 0;
if (!stream) {
BT_LOGW_STR("Invalid parameter: stream is NULL.");
- ret = (int64_t) -1;
+ ret = -1;
goto end;
}
if (!count) {
BT_LOGW_STR("Invalid parameter: count is NULL.");
- ret = (int64_t) -1;
+ ret = -1;
goto end;
}
BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
"stream-addr=%p, stream-name=\"%s\"",
stream, bt_ctf_stream_get_name(stream));
- ret = (int64_t) -1;
+ ret = -1;
goto end;
}
int ret = 0;
struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
struct bt_ctf_clock_class *mapped_clock_class = NULL;
- uint64_t event_class_id;
+ int64_t event_class_id;
assert(event);
+ if (!event->event_header) {
+ goto end;
+ }
+
if (event->frozen) {
BT_LOGW_STR("Cannot populate event header field: event is frozen.");
ret = -1;
stream, bt_ctf_stream_get_name(stream), event);
id_field = bt_ctf_field_structure_get_field(event->event_header, "id");
- event_class_id = (uint64_t) bt_ctf_event_class_get_id(event->event_class);
- assert(event_class_id >= 0);
+ event_class_id = bt_ctf_event_class_get_id(event->event_class);
+ if (event_class_id < 0) {
+ BT_LOGE("Event class ID cannot be found");
+ ret = -1;
+ goto end;
+ }
if (id_field && bt_ctf_field_type_is_integer(id_field->type)) {
ret = set_integer_field_value(id_field, event_class_id);
if (ret) {
struct bt_ctf_field *member;
member = bt_ctf_field_structure_get_field(structure, name);
- assert(member);
- (void) bt_ctf_field_reset(member);
- bt_put(member);
+ if (member) {
+ (void) bt_ctf_field_reset(member);
+ bt_put(member);
+ }
}
int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
struct bt_ctf_stream_pos packet_context_pos;
struct bt_ctf_trace *trace;
enum bt_ctf_byte_order native_byte_order;
+ bool has_packet_size = false;
if (!stream) {
BT_LOGW_STR("Invalid parameter: stream is NULL.");
ret = -1;
- goto end;
+ goto end_no_stream;
}
if (stream->pos.fd < 0) {
goto end;
}
- if (stream->flushed_packet_count == 1) {
+ if (stream->packet_context) {
struct bt_ctf_field *packet_size_field;
+ packet_size_field = bt_ctf_field_structure_get_field(
+ stream->packet_context, "packet_size");
+ has_packet_size = (packet_size_field != NULL);
+ bt_put(packet_size_field);
+ }
+
+ if (stream->flushed_packet_count == 1) {
if (!stream->packet_context) {
BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
ret = -1;
goto end;
}
- packet_size_field = bt_ctf_field_structure_get_field(
- stream->packet_context, "packet_size");
- bt_put(packet_size_field);
- if (!packet_size_field) {
+ if (!has_packet_size) {
BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
ret = -1;
goto end;
stream->pos.offset, stream->pos.packet_size);
/* Write event header */
- BT_LOGV_STR("Serializing event's header field.");
- ret = bt_ctf_field_serialize(event->event_header,
- &stream->pos, native_byte_order);
- if (ret) {
- BT_LOGW("Cannot serialize event's header field: "
- "field-addr=%p", event->event_header);
- goto end;
+ if (event->event_header) {
+ BT_LOGV_STR("Serializing event's header field.");
+ ret = bt_ctf_field_serialize(event->event_header,
+ &stream->pos, native_byte_order);
+ if (ret) {
+ BT_LOGW("Cannot serialize event's header field: "
+ "field-addr=%p", event->event_header);
+ goto end;
+ }
}
/* Write stream event context */
}
}
+ if (!has_packet_size && stream->pos.offset % 8 != 0) {
+ BT_LOGW("Stream's packet context field type has no `packet_size` field, "
+ "but current content size is not a multiple of 8 bits: "
+ "content-size=%" PRId64 ", "
+ "packet-size=%" PRIu64,
+ stream->pos.offset,
+ stream->pos.packet_size);
+ ret = -1;
+ goto end;
+ }
+
assert(stream->pos.packet_size % 8 == 0);
+ /*
+ * Remove extra padding bytes.
+ */
+ stream->pos.packet_size = (stream->pos.offset + 7) & ~7;
+
if (stream->packet_context) {
/*
* The whole packet is serialized at this point. Make sure that,
g_ptr_array_set_size(stream->events, 0);
stream->flushed_packet_count++;
stream->size += stream->pos.packet_size / CHAR_BIT;
+
+ do {
+ ret = ftruncate(stream->pos.fd, stream->size);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ BT_LOGE_ERRNO("Cannot truncate stream file to new size",
+ ": size=%" PRIu64 ", stream-addr=%p, "
+ "stream-name=\"%s\"",
+ stream->size, stream,
+ bt_ctf_stream_get_name(stream));
+ }
+
end:
/* Reset automatically-set fields. */
- reset_structure_field(stream->packet_context, "timestamp_begin");
- reset_structure_field(stream->packet_context, "timestamp_end");
- reset_structure_field(stream->packet_context, "packet_size");
- reset_structure_field(stream->packet_context, "content_size");
+ if (stream->packet_context) {
+ reset_structure_field(stream->packet_context, "timestamp_begin");
+ reset_structure_field(stream->packet_context, "timestamp_end");
+ reset_structure_field(stream->packet_context, "packet_size");
+ reset_structure_field(stream->packet_context, "content_size");
+ reset_structure_field(stream->packet_context, "events_discarded");
+ }
if (ret < 0) {
/*
"packet-size=%" PRIu64,
stream->pos.offset, stream->pos.packet_size);
}
+
+end_no_stream:
return ret;
}
ret = ftruncate(stream->pos.fd, stream->size);
} while (ret == -1 && errno == EINTR);
if (ret) {
- BT_LOGE("Failed to truncate stream file: %s: "
- "ret=%d, errno=%d, size=%" PRIu64,
- strerror(errno), ret, errno,
- (uint64_t) stream->size);
+ BT_LOGE_ERRNO("Failed to truncate stream file",
+ ": ret=%d, size=%" PRIu64,
+ ret, (uint64_t) stream->size);
}
if (close(stream->pos.fd)) {
- BT_LOGE("Failed to close stream file: %s: "
- "ret=%d, errno=%d", strerror(errno),
- ret, errno);
+ BT_LOGE_ERRNO("Failed to close stream file",
+ ": ret=%d", ret);
}
}
* listener so that we remove this hash table entry when we know
* the component is destroyed.
*/
- bt_component_add_destroy_listener(comp, component_destroy_listener,
- stream);
- g_hash_table_insert(stream->comp_cur_port, comp, port);
- BT_LOGV("Mapped component to port for stream: stream-addr=%p, "
- "stream-name=\"%s\", comp-addr=%p, comp-name=\"%s\", "
- "port-addr=%p, port-name=\"%s\"",
+ BT_LOGV("Adding component's destroy listener for stream: "
+ "stream-addr=%p, stream-name=\"%s\", comp-addr=%p, "
+ "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
stream, bt_ctf_stream_get_name(stream),
comp, bt_component_get_name(comp), port,
bt_port_get_name(port));
+ bt_component_add_destroy_listener(comp, component_destroy_listener,
+ stream);
+ g_hash_table_insert(stream->comp_cur_port, comp, port);
+ BT_LOGV_STR("Mapped component to port for stream.");
}
BT_HIDDEN