X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fctf-ir%2Fstream.c;h=5741a7a520f6fbc4126f50ec031b5be12f269174;hb=7d7fae6d7f0be96112fe30e47715b83f169bff52;hp=402597edd3e1e1905e66c910ca8e1a87e76a934b;hpb=b3376dd98f1daa25bf03af261f4560a3789fb367;p=babeltrace.git diff --git a/lib/ctf-ir/stream.c b/lib/ctf-ir/stream.c index 402597ed..5741a7a5 100644 --- a/lib/ctf-ir/stream.c +++ b/lib/ctf-ir/stream.c @@ -48,6 +48,7 @@ #include #include #include +#include static void bt_ctf_stream_destroy(struct bt_object *obj); @@ -353,18 +354,50 @@ int set_packet_context_events_discarded(struct bt_ctf_stream *stream) 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_value_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: @@ -634,46 +667,80 @@ int create_stream_file(struct bt_ctf_writer *writer, 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_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_string_printf(filename, "stream_%" PRId64, ret); + 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, "_%" PRIu32, 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); @@ -697,9 +764,10 @@ void component_destroy_listener(struct bt_component *component, void *data) g_hash_table_remove(stream->comp_cur_port, component); } -struct bt_ctf_stream *bt_ctf_stream_create( +static +struct bt_ctf_stream *bt_ctf_stream_create_with_id_no_check( struct bt_ctf_stream_class *stream_class, - const char *name) + const char *name, uint64_t id) { int ret; struct bt_ctf_stream *stream = NULL; @@ -712,10 +780,11 @@ struct bt_ctf_stream *bt_ctf_stream_create( } BT_LOGD("Creating stream object: stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-name=\"%s\"", + "stream-class-name=\"%s\", stream-name=\"%s\", " + "stream-id=%" PRIu64, stream_class, bt_ctf_stream_class_get_name(stream_class), - name); - trace = bt_ctf_stream_class_get_trace(stream_class); + name, id); + trace = bt_ctf_stream_class_borrow_trace(stream_class); if (!trace) { BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " "stream-class-addr=%p, stream-class-name=\"%s\", " @@ -739,6 +808,29 @@ struct bt_ctf_stream *bt_ctf_stream_create( goto error; } + if (id != -1ULL) { + /* + * Validate that the given ID is unique amongst all the + * existing trace's streams created from the same stream + * class. + */ + size_t i; + + for (i = 0; i < trace->streams->len; i++) { + struct bt_ctf_stream *trace_stream = + g_ptr_array_index(trace->streams, i); + + if (trace_stream->stream_class != stream_class) { + continue; + } + + if (trace_stream->id == id) { + BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID."); + goto error; + } + } + } + stream = g_new0(struct bt_ctf_stream, 1); if (!stream) { BT_LOGE_STR("Failed to allocate one stream."); @@ -751,9 +843,9 @@ struct bt_ctf_stream *bt_ctf_stream_create( * reachable; it needs its parent to remain valid. */ bt_object_set_parent(stream, trace); - stream->id = stream_class->next_stream_id++; stream->stream_class = stream_class; stream->pos.fd = -1; + stream->id = (int64_t) id; stream->destroy_listeners = g_array_new(FALSE, TRUE, sizeof(struct bt_ctf_stream_destroy_listener)); @@ -774,8 +866,8 @@ struct bt_ctf_stream *bt_ctf_stream_create( if (trace->is_created_by_writer) { int fd; - writer = (struct bt_ctf_writer *) - bt_object_get_parent(trace); + writer = (struct bt_ctf_writer *) bt_object_get_parent(trace); + stream->id = (int64_t) stream_class->next_stream_id++; BT_LOGD("Stream object belongs to a writer's trace: " "writer-addr=%p", writer); @@ -794,7 +886,7 @@ struct bt_ctf_stream *bt_ctf_stream_create( /* 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); @@ -859,18 +951,71 @@ struct bt_ctf_stream *bt_ctf_stream_create( /* Add this stream to the trace's streams */ g_ptr_array_add(trace->streams, stream); - - BT_PUT(trace); - BT_PUT(writer); BT_LOGD("Created stream object: addr=%p", stream); - return stream; + goto end; + error: BT_PUT(stream); - BT_PUT(trace); - BT_PUT(writer); + +end: + bt_put(writer); + return stream; +} + +struct bt_ctf_stream *bt_ctf_stream_create_with_id( + struct bt_ctf_stream_class *stream_class, + const char *name, uint64_t id_param) +{ + struct bt_ctf_trace *trace; + struct bt_ctf_stream *stream = NULL; + int64_t id = (int64_t) id_param; + + if (!stream_class) { + BT_LOGW_STR("Invalid parameter: stream class is NULL."); + goto end; + } + + if (id < 0) { + BT_LOGW("Invalid parameter: invalid stream's ID: " + "name=\"%s\", id=%" PRIu64, + name, id_param); + goto end; + } + + trace = bt_ctf_stream_class_borrow_trace(stream_class); + if (!trace) { + BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-name=\"%s\", stream-id=%" PRIu64, + stream_class, bt_ctf_stream_class_get_name(stream_class), + name, id_param); + goto end; + } + + if (trace->is_created_by_writer) { + BT_LOGW("Invalid parameter: cannot create a CTF writer stream with this function; use bt_ctf_stream_create(): " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-name=\"%s\", stream-id=%" PRIu64, + stream_class, bt_ctf_stream_class_get_name(stream_class), + name, id_param); + goto end; + } + + stream = bt_ctf_stream_create_with_id_no_check(stream_class, + name, id_param); + +end: return stream; } +struct bt_ctf_stream *bt_ctf_stream_create( + struct bt_ctf_stream_class *stream_class, + const char *name) +{ + return bt_ctf_stream_create_with_id_no_check(stream_class, + name, -1ULL); +} + struct bt_ctf_stream_class *bt_ctf_stream_get_class( struct bt_ctf_stream *stream) { @@ -887,20 +1032,20 @@ end: 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; } @@ -908,7 +1053,7 @@ int64_t bt_ctf_stream_get_discarded_events_count( 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; } @@ -1011,10 +1156,14 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream, 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; @@ -1026,8 +1175,12 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream, 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) { @@ -1340,9 +1493,10 @@ void reset_structure_field(struct bt_ctf_field *structure, const char *name) 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_value(member); + bt_put(member); + } } int bt_ctf_stream_flush(struct bt_ctf_stream *stream) @@ -1352,11 +1506,12 @@ 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) { @@ -1365,19 +1520,23 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) 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; @@ -1452,13 +1611,15 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) 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 */ @@ -1483,8 +1644,24 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) } } + 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, @@ -1537,12 +1714,16 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) g_ptr_array_set_size(stream->events, 0); stream->flushed_packet_count++; stream->size += stream->pos.packet_size / CHAR_BIT; + 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) { /* @@ -1557,6 +1738,8 @@ end: "packet-size=%" PRIu64, stream->pos.offset, stream->pos.packet_size); } + +end_no_stream: return ret; } @@ -1606,16 +1789,14 @@ void bt_ctf_stream_destroy(struct bt_object *obj) 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); } } @@ -1681,7 +1862,7 @@ int _set_structure_field_integer(struct bt_ctf_field *structure, char *name, } /* Make sure the payload has not already been set. */ - if (!force && bt_ctf_field_is_set(integer)) { + if (!force && bt_ctf_field_value_is_set(integer)) { /* Payload already set, not an error */ BT_LOGV("Field's payload is already set: struct-field-addr=%p, " "name=\"%s\", force=%d", structure, name, force); @@ -1777,15 +1958,16 @@ void bt_ctf_stream_map_component_to_port(struct bt_ctf_stream *stream, * 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 @@ -1838,3 +2020,23 @@ void bt_ctf_stream_remove_destroy_listener(struct bt_ctf_stream *stream, } } } + +int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream) +{ + int64_t ret; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = (int64_t) -1; + goto end; + } + + ret = stream->id; + if (ret < 0) { + BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + } + +end: + return ret; +}