Exemplo n.º 1
0
BT_HIDDEN
int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
		struct bt_ctf_field *stream_event_context)
{
	int ret = 0;
	struct bt_ctf_field_type *field_type = NULL;
	struct bt_ctf_stream_class *stream_class = NULL;

	if (!event || !stream_event_context || event->frozen) {
		ret = -1;
		goto end;
	}

	stream_class = bt_ctf_event_class_get_stream_class(event->event_class);
	/*
	 * We should not have been able to create the event without associating
	 * the event class to a stream class.
	 */
	assert(stream_class);

	field_type = bt_ctf_field_get_type(stream_event_context);
	if (bt_ctf_field_type_compare(field_type,
			stream_class->event_context_type)) {
		ret = -1;
		goto end;
	}

	bt_get(stream_event_context);
	BT_MOVE(event->stream_event_context, stream_event_context);
end:
	BT_PUT(stream_class);
	bt_put(field_type);
	return ret;
}
Exemplo n.º 2
0
BT_HIDDEN
int bt_ctf_event_set_packet(struct bt_ctf_event *event,
		struct bt_ctf_packet *packet)
{
	struct bt_ctf_stream_class *event_stream_class = NULL;
	struct bt_ctf_stream_class *packet_stream_class = NULL;
	struct bt_ctf_stream *stream = NULL;
	int ret = 0;

	if (!event || !packet || event->frozen) {
		ret = -1;
		goto end;
	}

	/*
	 * Make sure the new packet was created by this event's
	 * stream, if it is set.
	 */
	stream = bt_ctf_event_get_stream(event);
	if (stream) {
		if (packet->stream != stream) {
			ret = -1;
			goto end;
		}
	} else {
		event_stream_class =
			bt_ctf_event_class_get_stream_class(event->event_class);
		packet_stream_class =
			bt_ctf_stream_get_class(packet->stream);

		assert(event_stream_class);
		assert(packet_stream_class);

		if (event_stream_class != packet_stream_class) {
			ret = -1;
			goto end;
		}
	}

	bt_get(packet);
	BT_MOVE(event->packet, packet);

end:
	BT_PUT(stream);
	BT_PUT(event_stream_class);
	BT_PUT(packet_stream_class);

	return ret;
}
Exemplo n.º 3
0
static void test_example_scenario(void)
{
	/**
	 * Weak pointers to CTF-IR objects are to be used very carefully.
	 * This is NOT a good practice and is strongly discouraged; this
	 * is only done to facilitate the validation of expected reference
	 * counts without affecting them by taking "real" references to the
	 * objects.
	 */
	struct bt_ctf_trace *tc1 = NULL, *weak_tc1 = NULL;
	struct bt_ctf_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL;
	struct bt_ctf_event_class *weak_ec1 = NULL, *weak_ec2 = NULL,
			*weak_ec3 = NULL;
	struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 };

	/* The only reference which exists at this point is on TC1. */
	tc1 = create_tc1();
	ok(tc1, "Initialize trace");
	if (!tc1) {
		return;
	}

	init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1,
			&weak_ec2, &weak_ec3);

	ok(bt_object_get_ref_count(weak_sc1) == 0,
			"Initial SC1 reference count is 0");
	ok(bt_object_get_ref_count(weak_sc2) == 0,
			"Initial SC2 reference count is 0");
	ok(bt_object_get_ref_count(weak_ec1) == 0,
			"Initial EC1 reference count is 0");
	ok(bt_object_get_ref_count(weak_ec2) == 0,
			"Initial EC2 reference count is 0");
	ok(bt_object_get_ref_count(weak_ec3) == 0,
			"Initial EC3 reference count is 0");

	/* User A has ownership of the trace. */
	BT_MOVE(user_a.tc, tc1);
	ok(bt_object_get_ref_count(user_a.tc) == 1,
			"TC1 reference count is 1");

	/* User A acquires a reference to SC2 from TC1. */
	user_a.sc = bt_ctf_trace_get_stream_class(user_a.tc, 1);
	ok(user_a.sc, "User A acquires SC2 from TC1");
	ok(bt_object_get_ref_count(weak_tc1) == 2,
			"TC1 reference count is 2");
	ok(bt_object_get_ref_count(weak_sc2) == 1,
			"SC2 reference count is 1");

	/* User A acquires a reference to EC3 from SC2. */
	user_a.ec = bt_ctf_stream_class_get_event_class(user_a.sc, 0);
	ok(user_a.ec, "User A acquires EC3 from SC2");
	ok(bt_object_get_ref_count(weak_tc1) == 2,
			"TC1 reference count is 2");
	ok(bt_object_get_ref_count(weak_sc2) == 2,
			"SC2 reference count is 2");
	ok(bt_object_get_ref_count(weak_ec3) == 1,
			"EC3 reference count is 1");

	/* User A releases its reference to SC2. */
	diag("User A releases SC2");
	BT_PUT(user_a.sc);
	/*
	 * We keep the pointer to SC2 around to validate its reference
	 * count.
	 */
	ok(bt_object_get_ref_count(weak_tc1) == 2,
			"TC1 reference count is 2");
	ok(bt_object_get_ref_count(weak_sc2) == 1,
			"SC2 reference count is 1");
	ok(bt_object_get_ref_count(weak_ec3) == 1,
			"EC3 reference count is 1");

	/* User A releases its reference to TC1. */
	diag("User A releases TC1");
	BT_PUT(user_a.tc);
	/*
	 * We keep the pointer to TC1 around to validate its reference
	 * count.
	 */
	ok(bt_object_get_ref_count(weak_tc1) == 1,
			"TC1 reference count is 1");
	ok(bt_object_get_ref_count(weak_sc2) == 1,
			"SC2 reference count is 1");
	ok(bt_object_get_ref_count(weak_ec3) == 1,
			"EC3 reference count is 1");

	/* User B acquires a reference to SC1. */
	diag("User B acquires a reference to SC1");
	user_b.sc = bt_get(weak_sc1);
	ok(bt_object_get_ref_count(weak_tc1) == 2,
			"TC1 reference count is 2");
	ok(bt_object_get_ref_count(weak_sc1) == 1,
			"SC1 reference count is 1");

	/* User C acquires a reference to EC1. */
	diag("User C acquires a reference to EC1");
	user_c.ec = bt_ctf_stream_class_get_event_class(user_b.sc, 0);
	ok(bt_object_get_ref_count(weak_ec1) == 1,
			"EC1 reference count is 1");
	ok(bt_object_get_ref_count(weak_sc1) == 2,
			"SC1 reference count is 2");

	/* User A releases its reference on EC3. */
	diag("User A releases its reference on EC3");
	BT_PUT(user_a.ec);
	ok(bt_object_get_ref_count(weak_ec3) == 0,
			"EC3 reference count is 1");
	ok(bt_object_get_ref_count(weak_sc2) == 0,
			"SC2 reference count is 0");
	ok(bt_object_get_ref_count(weak_tc1) == 1,
			"TC1 reference count is 1");

	/* User B releases its reference on SC1. */
	diag("User B releases its reference on SC1");
	BT_PUT(user_b.sc);
	ok(bt_object_get_ref_count(weak_sc1) == 1,
			"SC1 reference count is 1");

	/*
	 * User C is the sole owner of an object and is keeping the whole
	 * trace hierarchy "alive" by holding a reference to EC1.
	 */
	ok(bt_object_get_ref_count(weak_tc1) == 1,
			"TC1 reference count is 1");
	ok(bt_object_get_ref_count(weak_sc1) == 1,
			"SC1 reference count is 1");
	ok(bt_object_get_ref_count(weak_sc2) == 0,
			"SC2 reference count is 0");
	ok(bt_object_get_ref_count(weak_ec1) == 1,
			"EC1 reference count is 1");
	ok(bt_object_get_ref_count(weak_ec2) == 0,
			"EC2 reference count is 0");
	ok(bt_object_get_ref_count(weak_ec3) == 0,
			"EC3 reference count is 0");

	/* Reclaim last reference held by User C. */
	BT_PUT(user_c.ec);
}
Exemplo n.º 4
0
int bt_event_set_packet(struct bt_event *event,
		struct bt_packet *packet)
{
	struct bt_stream_class *event_stream_class = NULL;
	struct bt_stream_class *packet_stream_class = NULL;
	struct bt_stream *stream = NULL;
	int ret = 0;

	if (!event || !packet) {
		BT_LOGW("Invalid parameter: event or packet is NULL: "
			"event-addr=%p, packet-addr=%p",
			event, packet);
		ret = -1;
		goto end;
	}

	if (event->frozen) {
		BT_LOGW("Invalid parameter: event is frozen: addr=%p, "
			"event-class-name=\"%s\", event-class-id=%" PRId64,
			event, bt_event_class_get_name(event->event_class),
			bt_event_class_get_id(event->event_class));
		ret = -1;
		goto end;
	}

	/*
	 * Make sure the new packet was created by this event's
	 * stream, if it is set.
	 */
	stream = bt_event_get_stream(event);
	if (stream) {
		if (packet->stream != stream) {
			BT_LOGW("Invalid parameter: packet's stream and event's stream differ: "
				"event-addr=%p, event-class-name=\"%s\", "
				"event-class-id=%" PRId64 ", packet-stream-addr=%p, "
				"event-stream-addr=%p",
				event, bt_event_class_get_name(event->event_class),
				bt_event_class_get_id(event->event_class),
				packet->stream, stream);
			ret = -1;
			goto end;
		}
	} else {
		event_stream_class =
			bt_event_class_get_stream_class(event->event_class);
		packet_stream_class =
			bt_stream_get_class(packet->stream);

		assert(event_stream_class);
		assert(packet_stream_class);

		if (event_stream_class != packet_stream_class) {
			BT_LOGW("Invalid parameter: packet's stream class and event's stream class differ: "
				"event-addr=%p, event-class-name=\"%s\", "
				"event-class-id=%" PRId64 ", packet-stream-class-addr=%p, "
				"event-stream-class-addr=%p",
				event, bt_event_class_get_name(event->event_class),
				bt_event_class_get_id(event->event_class),
				packet_stream_class, event_stream_class);
			ret = -1;
			goto end;
		}
	}

	bt_get(packet);
	BT_MOVE(event->packet, packet);
	BT_LOGV("Set event's packet: event-addr=%p, "
		"event-class-name=\"%s\", event-class-id=%" PRId64 ", "
		"packet-addr=%p",
		event, bt_event_class_get_name(event->event_class),
		bt_event_class_get_id(event->event_class), packet);

end:
	BT_PUT(stream);
	BT_PUT(event_stream_class);
	BT_PUT(packet_stream_class);

	return ret;
}
Exemplo n.º 5
0
int bt_event_set_stream_event_context(struct bt_event *event,
		struct bt_field *stream_event_context)
{
	int ret = 0;
	struct bt_field_type *field_type = NULL;
	struct bt_stream_class *stream_class = NULL;

	if (!event) {
		BT_LOGW_STR("Invalid parameter: event is NULL.");
		ret = -1;
		goto end;
	}

	if (event->frozen) {
		BT_LOGW("Invalid parameter: event is frozen: addr=%p, "
			"event-class-name=\"%s\", event-class-id=%" PRId64,
			event, bt_event_class_get_name(event->event_class),
			bt_event_class_get_id(event->event_class));
		ret = -1;
		goto end;
	}

	stream_class = bt_event_class_get_stream_class(event->event_class);
	/*
	 * We should not have been able to create the event without associating
	 * the event class to a stream class.
	 */
	assert(stream_class);

	if (stream_event_context) {
		field_type = bt_field_get_type(stream_event_context);
		if (bt_field_type_compare(field_type,
				stream_class->event_context_type)) {
			BT_LOGW("Invalid parameter: stream event context field type is different from the expected field type: "
				"event-addr=%p, event-class-name=\"%s\", "
				"event-class-id=%" PRId64,
				event,
				bt_event_class_get_name(event->event_class),
				bt_event_class_get_id(event->event_class));
			ret = -1;
			goto end;
		}
	} else {
		if (stream_class->event_context_type) {
			BT_LOGW("Invalid parameter: setting no stream event context but stream event context field type is not NULL: "
				"event-addr=%p, event-class-name=\"%s\", "
				"event-class-id=%" PRId64 ", "
				"stream-event-context-ft-addr=%p",
				event,
				bt_event_class_get_name(event->event_class),
				bt_event_class_get_id(event->event_class),
				stream_class->event_context_type);
			ret = -1;
			goto end;
		}
	}

	bt_get(stream_event_context);
	BT_MOVE(event->stream_event_context, stream_event_context);
	BT_LOGV("Set event's stream event context field: event-addr=%p, "
		"event-class-name=\"%s\", event-class-id=%" PRId64 ", "
		"stream-event-context-field-addr=%p",
		event, bt_event_class_get_name(event->event_class),
		bt_event_class_get_id(event->event_class),
		stream_event_context);
end:
	BT_PUT(stream_class);
	bt_put(field_type);
	return ret;
}
Exemplo n.º 6
0
struct bt_event *bt_event_create(struct bt_event_class *event_class)
{
	int ret;
	enum bt_validation_flag validation_flags =
		BT_VALIDATION_FLAG_STREAM |
		BT_VALIDATION_FLAG_EVENT;
	struct bt_event *event = NULL;
	struct bt_trace *trace = NULL;
	struct bt_stream_class *stream_class = NULL;
	struct bt_field_type *packet_header_type = NULL;
	struct bt_field_type *packet_context_type = NULL;
	struct bt_field_type *event_header_type = NULL;
	struct bt_field_type *stream_event_ctx_type = NULL;
	struct bt_field_type *event_context_type = NULL;
	struct bt_field_type *event_payload_type = NULL;
	struct bt_field *event_header = NULL;
	struct bt_field *stream_event_context = NULL;
	struct bt_field *event_context = NULL;
	struct bt_field *event_payload = NULL;
	struct bt_value *environment = NULL;
	struct bt_validation_output validation_output = { 0 };
	int trace_valid = 0;

	BT_LOGD("Creating event object: event-class-addr=%p, "
		"event-class-name=\"%s\", event-class-id=%" PRId64,
		event_class, bt_event_class_get_name(event_class),
		bt_event_class_get_id(event_class));

	if (!event_class) {
		BT_LOGW_STR("Invalid parameter: event class is NULL.");
		goto error;
	}

	stream_class = bt_event_class_get_stream_class(event_class);

	/*
	 * We disallow the creation of an event if its event class has not been
	 * associated to a stream class.
	 */
	if (!stream_class) {
		BT_LOGW_STR("Event class is not part of a stream class.");
		goto error;
	}

	/* The event class was frozen when added to its stream class */
	assert(event_class->frozen);

	/* Validate the trace (if any), the stream class, and the event class */
	trace = bt_stream_class_get_trace(stream_class);
	if (trace) {
		BT_LOGD_STR("Event's class is part of a trace.");
		packet_header_type = bt_trace_get_packet_header_type(trace);
		trace_valid = trace->valid;
		assert(trace_valid);
		environment = trace->environment;
	}

	packet_context_type = bt_stream_class_get_packet_context_type(
		stream_class);
	event_header_type = bt_stream_class_get_event_header_type(
		stream_class);
	stream_event_ctx_type = bt_stream_class_get_event_context_type(
		stream_class);
	event_context_type = bt_event_class_get_context_type(event_class);
	event_payload_type = bt_event_class_get_payload_type(event_class);
	ret = bt_validate_class_types(environment, packet_header_type,
		packet_context_type, event_header_type, stream_event_ctx_type,
		event_context_type, event_payload_type, trace_valid,
		stream_class->valid, event_class->valid,
		&validation_output, validation_flags);
	BT_PUT(packet_header_type);
	BT_PUT(packet_context_type);
	BT_PUT(event_header_type);
	BT_PUT(stream_event_ctx_type);
	BT_PUT(event_context_type);
	BT_PUT(event_payload_type);
	if (ret) {
		/*
		 * This means something went wrong during the validation
		 * process, not that the objects are invalid.
		 */
		BT_LOGE("Failed to validate event and parents: ret=%d", ret);
		goto error;
	}

	if ((validation_output.valid_flags & validation_flags) !=
			validation_flags) {
		/* Invalid trace/stream class/event class */
		BT_LOGW("Invalid trace, stream class, or event class: "
			"valid-flags=0x%x", validation_output.valid_flags);
		goto error;
	}

	/*
	 * At this point we know the trace (if associated to the stream
	 * class), the stream class, and the event class, with their
	 * current types, are valid. We may proceed with creating
	 * the event.
	 */
	event = g_new0(struct bt_event, 1);
	if (!event) {
		BT_LOGE_STR("Failed to allocate one event.");
		goto error;
	}

	bt_object_init(event, bt_event_destroy);

	/*
	 * event does not share a common ancestor with the event class; it has
	 * to guarantee its existence by holding a reference. This reference
	 * shall be released once the event is associated to a stream since,
	 * from that point, the event and its class will share the same
	 * lifetime.
	 */
	event->event_class = bt_get(event_class);
	event->clock_values = g_hash_table_new_full(g_direct_hash,
			g_direct_equal, bt_put, bt_put);

	if (validation_output.event_header_type) {
		BT_LOGD("Creating initial event header field: ft-addr=%p",
			validation_output.event_header_type);
		event_header =
			bt_field_create(validation_output.event_header_type);
		if (!event_header) {
			BT_LOGE_STR("Cannot create initial event header field object.");
			goto error;
		}
	}

	if (validation_output.stream_event_ctx_type) {
		BT_LOGD("Creating initial stream event context field: ft-addr=%p",
			validation_output.stream_event_ctx_type);
		stream_event_context = bt_field_create(
			validation_output.stream_event_ctx_type);
		if (!stream_event_context) {
			BT_LOGE_STR("Cannot create initial stream event context field object.");
			goto error;
		}
	}

	if (validation_output.event_context_type) {
		BT_LOGD("Creating initial event context field: ft-addr=%p",
			validation_output.event_context_type);
		event_context = bt_field_create(
			validation_output.event_context_type);
		if (!event_context) {
			BT_LOGE_STR("Cannot create initial event context field object.");
			goto error;
		}
	}

	if (validation_output.event_payload_type) {
		BT_LOGD("Creating initial event payload field: ft-addr=%p",
			validation_output.event_payload_type);
		event_payload = bt_field_create(
			validation_output.event_payload_type);
		if (!event_payload) {
			BT_LOGE_STR("Cannot create initial event payload field object.");
			goto error;
		}
	}

	/*
	 * At this point all the fields are created, potentially from
	 * validated copies of field types, so that the field types and
	 * fields can be replaced in the trace, stream class,
	 * event class, and created event.
	 */
	bt_validation_replace_types(trace, stream_class,
		event_class, &validation_output, validation_flags);
	BT_MOVE(event->event_header, event_header);
	BT_MOVE(event->stream_event_context, stream_event_context);
	BT_MOVE(event->context_payload, event_context);
	BT_MOVE(event->fields_payload, event_payload);

	/*
	 * Put what was not moved in bt_validation_replace_types().
	 */
	bt_validation_output_put_types(&validation_output);

	/*
	 * Freeze the stream class since the event header must not be changed
	 * anymore.
	 */
	bt_stream_class_freeze(stream_class);

	/*
	 * Mark stream class, and event class as valid since
	 * they're all frozen now.
	 */
	stream_class->valid = 1;
	event_class->valid = 1;

	/* Put stuff we borrowed from the event class */
	BT_PUT(stream_class);
	BT_PUT(trace);
	BT_LOGD("Created event object: addr=%p, event-class-name=\"%s\", "
		"event-class-id=%" PRId64,
		event, bt_event_class_get_name(event->event_class),
		bt_event_class_get_id(event_class));
	return event;

error:
	bt_validation_output_put_types(&validation_output);
	BT_PUT(event);
	BT_PUT(stream_class);
	BT_PUT(trace);
	BT_PUT(event_header);
	BT_PUT(stream_event_context);
	BT_PUT(event_context);
	BT_PUT(event_payload);
	assert(!packet_header_type);
	assert(!packet_context_type);
	assert(!event_header_type);
	assert(!stream_event_ctx_type);
	assert(!event_context_type);
	assert(!event_payload_type);

	return event;
}
Exemplo n.º 7
0
static inline
enum bt_btr_status next_field_state(struct bt_btr *btr)
{
	int ret;
	struct stack_entry *top;
	struct bt_field_type *next_field_type = NULL;
	enum bt_btr_status status = BT_BTR_STATUS_OK;

	if (stack_empty(btr->stack)) {
		goto end;
	}

	top = stack_top(btr->stack);

	/* Are we done with this base type? */
	while (top->index == top->base_len) {
		if (btr->user.cbs.types.compound_end) {
			BT_LOGV("Calling user function (compound, end).");
			status = btr->user.cbs.types.compound_end(
				top->base_type, btr->user.data);
			BT_LOGV("User function returned: status=%s",
				bt_btr_status_string(status));
			if (status != BT_BTR_STATUS_OK) {
				BT_LOGW("User function failed: btr-addr=%p, status=%s",
					btr, bt_btr_status_string(status));
				goto end;
			}
		}

		stack_pop(btr->stack);

		/* Are we done with the root type? */
		if (stack_empty(btr->stack)) {
			btr->state = BTR_STATE_DONE;
			goto end;
		}

		top = stack_top(btr->stack);
		top->index++;
	}

	/* Get next field's type */
	switch (bt_field_type_get_type_id(top->base_type)) {
	case BT_FIELD_TYPE_ID_STRUCT:
		ret = bt_field_type_structure_get_field_by_index(
			top->base_type, NULL, &next_field_type,
			top->index);
		if (ret) {
			next_field_type = NULL;
		}
		break;
	case BT_FIELD_TYPE_ID_ARRAY:
		next_field_type =
			bt_field_type_array_get_element_type(
				top->base_type);
		break;
	case BT_FIELD_TYPE_ID_SEQUENCE:
		next_field_type =
			bt_field_type_sequence_get_element_type(
				top->base_type);
		break;
	case BT_FIELD_TYPE_ID_VARIANT:
		/* Variant types are dynamic: query the user, he should know! */
		next_field_type =
			btr->user.cbs.query.get_variant_type(
				top->base_type, btr->user.data);
		break;
	default:
		break;
	}

	if (!next_field_type) {
		BT_LOGW("Cannot get the field type of the next field: "
			"btr-addr=%p, base-ft-addr=%p, base-ft-id=%s, "
			"index=%" PRId64,
			btr, top->base_type,
			bt_field_type_id_string(
				bt_field_type_get_type_id(top->base_type)),
			top->index);
		status = BT_BTR_STATUS_ERROR;
		goto end;
	}

	if (is_compound_type(next_field_type)) {
		if (btr->user.cbs.types.compound_begin) {
			BT_LOGV("Calling user function (compound, begin).");
			status = btr->user.cbs.types.compound_begin(
				next_field_type, btr->user.data);
			BT_LOGV("User function returned: status=%s",
				bt_btr_status_string(status));
			if (status != BT_BTR_STATUS_OK) {
				BT_LOGW("User function failed: btr-addr=%p, status=%s",
					btr, bt_btr_status_string(status));
				goto end;
			}
		}

		ret = stack_push_with_len(btr, next_field_type);
		if (ret) {
			/* stack_push_with_len() logs errors */
			status = BT_BTR_STATUS_ERROR;
			goto end;
		}

		/* Next state: align a compound type */
		btr->state = BTR_STATE_ALIGN_COMPOUND;
	} else {
		/* Replace current basic field type */
		BT_LOGV("Replacing current basic field type: "
			"btr-addr=%p, cur-basic-ft-addr=%p, "
			"next-basic-ft-addr=%p",
			btr, btr->cur_basic_field_type, next_field_type);
		BT_MOVE(btr->cur_basic_field_type, next_field_type);

		/* Next state: align a basic type */
		btr->state = BTR_STATE_ALIGN_BASIC;
	}

end:
	BT_PUT(next_field_type);

	return status;
}