Example #1
0
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;
}
Example #2
0
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, &timestamp_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,
		&timestamp_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;
}
Example #3
0
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;
}