BT_HIDDEN struct bt_ctf_stream *bt_ctf_stream_create( struct bt_ctf_stream_class *stream_class, struct bt_ctf_trace *trace) { int ret; struct bt_ctf_stream *stream = NULL; if (!stream_class || !trace) { goto end; } stream = g_new0(struct bt_ctf_stream, 1); if (!stream) { goto end; } /* A stream has no ownership of its trace (weak ptr) */ stream->trace = trace; bt_object_init(stream, bt_ctf_stream_destroy); stream->packet_context = bt_ctf_field_create( stream_class->packet_context_type); if (!stream->packet_context) { goto error; } /* * A stream class may not have a stream event context defined * in which case this stream will never have a stream_event_context * member since, after a stream's creation, the parent stream class * is "frozen" (immutable). */ if (stream_class->event_context_type) { stream->event_context = bt_ctf_field_create( stream_class->event_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; } stream->pos.fd = -1; stream->id = stream_class->next_stream_id++; stream->stream_class = stream_class; bt_get(stream_class); stream->events = g_ptr_array_new_with_free_func( (GDestroyNotify) put_event); if (!stream->events) { goto error; } if (stream_class->event_context_type) { stream->event_contexts = g_ptr_array_new_with_free_func( (GDestroyNotify) bt_ctf_field_put); if (!stream->event_contexts) { goto error; } } /* A trace is not allowed to have a NULL packet header */ assert(trace->packet_header_type); stream->packet_header = bt_ctf_field_create(trace->packet_header_type); if (!stream->packet_header) { goto error; } /* * Attempt to populate the default trace packet header fields * (magic, uuid and stream_id). This will _not_ fail shall the * fields not be found or be of an incompatible type; they will * simply not be populated automatically. The user will have to * make sure to set the trace packet header fields himself before * flushing. */ ret = set_packet_header(stream); if (ret) { goto error; } end: return stream; error: BT_PUT(stream); return stream; }
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_field *integer = NULL; struct ctf_stream_pos packet_context_pos; if (!stream || stream->pos.fd < 0) { /* * Stream does not have an associated fd. It is, * therefore, not a stream being used to write events. */ ret = -1; goto end; } if (!stream->events->len) { goto end; } ret = bt_ctf_field_validate(stream->packet_header); if (ret) { goto end; } /* mmap the next packet */ ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos); if (ret) { 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)) { ret = set_structure_field_integer(stream->packet_context, "timestamp_begin", timestamp_begin); 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); 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; } 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); ret = bt_ctf_field_reset(event->event_header); if (ret) { goto end; } /* Write event header */ ret = bt_ctf_field_serialize(event->event_header, &stream->pos); if (ret) { goto end; } /* Write stream event context */ if (stream->event_contexts) { ret = bt_ctf_field_serialize( g_ptr_array_index(stream->event_contexts, i), &stream->pos); if (ret) { goto end; } } /* Write event content */ ret = bt_ctf_event_serialize(event, &stream->pos); if (ret) { goto end; } } /* * 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 = set_structure_field_integer(stream->packet_context, "packet_size", stream->pos.packet_size); 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); if (stream->event_contexts) { g_ptr_array_set_size(stream->event_contexts, 0); } stream->flushed_packet_count++; end: bt_put(integer); return ret; }
struct bt_ctf_stream *bt_ctf_stream_create( struct bt_ctf_stream_class *stream_class, const char *name) { int ret; struct bt_ctf_stream *stream = NULL; struct bt_ctf_trace *trace = NULL; struct bt_ctf_writer *writer = NULL; if (!stream_class) { goto error; } trace = bt_ctf_stream_class_get_trace(stream_class); if (!trace) { goto error; } stream = g_new0(struct bt_ctf_stream, 1); if (!stream) { goto error; } bt_object_init(stream, bt_ctf_stream_destroy); /* * Acquire reference to parent since stream will become publicly * 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; if (name) { stream->name = g_string_new(name); if (!stream->name) { goto error; } } if (trace->is_created_by_writer) { int fd; writer = (struct bt_ctf_writer *) 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; } /* 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( (GDestroyNotify) release_event); if (!stream->events) { goto error; } /* A trace is not allowed to have a NULL packet header */ assert(trace->packet_header_type); stream->packet_header = bt_ctf_field_create(trace->packet_header_type); if (!stream->packet_header) { goto error; } /* * Attempt to populate the default trace packet header fields * (magic, uuid and stream_id). This will _not_ fail shall the * fields not be found or be of an incompatible type; they will * simply not be populated automatically. The user will have to * make sure to set the trace packet header fields himself * before flushing. */ ret = set_packet_header(stream); if (ret) { goto error; } /* Create file associated with this stream */ fd = create_stream_file(writer, stream); if (fd < 0) { goto error; } ret = set_stream_fd(stream, fd); if (ret) { goto error; } /* Freeze the writer */ bt_ctf_writer_freeze(writer); } else { /* Non-writer stream indicated by a negative FD */ ret = set_stream_fd(stream, -1); if (ret) { goto error; } stream->clock_values = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); } /* Add this stream to the trace's streams */ g_ptr_array_add(trace->streams, stream); BT_PUT(trace); BT_PUT(writer); return stream; error: BT_PUT(stream); BT_PUT(trace); BT_PUT(writer); return stream; }