#include <babeltrace/ctf-ir/validation-internal.h>
#include <babeltrace/ctf-ir/visitor-internal.h>
#include <babeltrace/ctf-ir/utils.h>
+#include <babeltrace/ctf-ir/utils-internal.h>
#include <babeltrace/compiler-internal.h>
#include <babeltrace/values.h>
#include <babeltrace/values-internal.h>
#include <babeltrace/ref.h>
#include <babeltrace/types.h>
#include <babeltrace/endian-internal.h>
+#include <babeltrace/assert-internal.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
goto end;
}
- if (bt_identifier_is_valid(name)) {
+ if (!bt_identifier_is_valid(name)) {
BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
"trace-addr=%p, trace-name=\"%s\", "
"env-name=\"%s\"",
}
ret = bt_attributes_get_count(trace->environment);
- assert(ret >= 0);
+ BT_ASSERT(ret >= 0);
end:
return ret;
ret = bt_field_type_structure_get_field_by_index(
packet_header_type, &field_name, NULL, 0);
- assert(ret == 0);
+ BT_ASSERT(ret == 0);
if (strcmp(field_name, "magic") != 0) {
BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
}
elem_ft = bt_field_type_array_get_element_type(field_type);
- assert(elem_ft);
+ BT_ASSERT(elem_ft);
if (!bt_field_type_is_integer(elem_ft)) {
BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
goto invalid;
}
- assert(int_ft);
+ BT_ASSERT(int_ft);
if (bt_field_type_integer_is_signed(int_ft)) {
BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
"id-ft-addr=%p", int_ft);
return is_valid;
}
+static
+int check_packet_header_type_has_no_clock_class(struct bt_trace *trace)
+{
+ int ret = 0;
+
+ if (trace->packet_header_type) {
+ struct bt_clock_class *clock_class = NULL;
+
+ ret = bt_validate_single_clock_class(trace->packet_header_type,
+ &clock_class);
+ bt_put(clock_class);
+ if (ret || clock_class) {
+ BT_LOGW("Trace's packet header field type cannot "
+ "contain a field type which is mapped to "
+ "a clock class: "
+ "trace-addr=%p, trace-name=\"%s\", "
+ "clock-class-name=\"%s\"",
+ trace, bt_trace_get_name(trace),
+ clock_class ?
+ bt_clock_class_get_name(clock_class) :
+ NULL);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
int bt_trace_add_stream_class(struct bt_trace *trace,
struct bt_stream_class *stream_class)
{
struct bt_field_type *stream_event_ctx_type = NULL;
int64_t event_class_count;
struct bt_trace *current_parent_trace = NULL;
+ struct bt_clock_class *expected_clock_class = NULL;
if (!trace) {
BT_LOGW_STR("Invalid parameter: trace is NULL.");
event_class_count =
bt_stream_class_get_event_class_count(stream_class);
- assert(event_class_count >= 0);
+ BT_ASSERT(event_class_count >= 0);
if (stream_class->clock) {
struct bt_clock_class *stream_clock_class =
ret = -1;
goto end;
}
+
+ if (stream_class->clock_class &&
+ stream_class->clock_class !=
+ stream_class->clock->clock_class) {
+ /*
+ * Stream class already has an expected clock
+ * class, but it does not match its clock's
+ * class.
+ */
+ BT_LOGW("Invalid parameter: stream class's clock's "
+ "class does not match stream class's "
+ "expected clock class: "
+ "stream-class-addr=%p, "
+ "stream-class-id=%" PRId64 ", "
+ "stream-class-name=\"%s\", "
+ "expected-clock-class-addr=%p, "
+ "expected-clock-class-name=\"%s\"",
+ stream_class,
+ bt_stream_class_get_id(stream_class),
+ bt_stream_class_get_name(stream_class),
+ expected_clock_class,
+ bt_clock_class_get_name(expected_clock_class));
+ } else if (!stream_class->clock_class) {
+ /*
+ * Set expected clock class to stream class's
+ * clock's class.
+ */
+ expected_clock_class =
+ bt_get(stream_class->clock->clock_class);
+ }
+ }
+
+ if (!stream_class->frozen) {
+ /*
+ * Stream class is not frozen yet. Validate that the
+ * stream class contains at most a single clock class
+ * because the previous
+ * bt_stream_class_add_event_class() calls did not make
+ * this validation since the stream class's direct field
+ * types (packet context, event header, event context)
+ * could change afterwards. This stream class is about
+ * to be frozen and those field types won't be changed
+ * if this function succeeds.
+ *
+ * At this point we're also sure that the stream class's
+ * clock, if any, has the same class as the stream
+ * class's expected clock class, if any. This is why, if
+ * bt_stream_class_validate_single_clock_class()
+ * succeeds below, the call to
+ * bt_stream_class_map_clock_class() at the end of this
+ * function is safe because it maps to the same, single
+ * clock class.
+ */
+ ret = bt_stream_class_validate_single_clock_class(stream_class,
+ &expected_clock_class);
+ if (ret) {
+ BT_LOGW("Invalid parameter: stream class or one of its "
+ "event classes contains a field type which is "
+ "not recursively mapped to the expected "
+ "clock class: "
+ "stream-class-addr=%p, "
+ "stream-class-id=%" PRId64 ", "
+ "stream-class-name=\"%s\", "
+ "expected-clock-class-addr=%p, "
+ "expected-clock-class-name=\"%s\"",
+ stream_class, bt_stream_class_get_id(stream_class),
+ bt_stream_class_get_name(stream_class),
+ expected_clock_class,
+ expected_clock_class ?
+ bt_clock_class_get_name(expected_clock_class) :
+ NULL);
+ goto end;
+ }
+ }
+
+ ret = check_packet_header_type_has_no_clock_class(trace);
+ if (ret) {
+ /* check_packet_header_type_has_no_clock_class() logs errors */
+ goto end;
}
/*
bt_stream_class_freeze(stream_class);
bt_trace_freeze(trace);
+ /*
+ * It is safe to set the stream class's unique clock class
+ * now because the stream class is frozen.
+ */
+ if (expected_clock_class) {
+ BT_MOVE(stream_class->clock_class, expected_clock_class);
+ }
+
/* Notifiy listeners of the trace's schema modification. */
bt_stream_class_visit(stream_class,
bt_trace_object_modification, trace);
g_free(ec_validation_outputs);
bt_validation_output_put_types(&trace_sc_validation_output);
bt_put(current_parent_trace);
- assert(!packet_header_type);
- assert(!packet_context_type);
- assert(!event_header_type);
- assert(!stream_event_ctx_type);
+ bt_put(expected_clock_class);
+ BT_ASSERT(!packet_header_type);
+ BT_ASSERT(!packet_context_type);
+ BT_ASSERT(!event_header_type);
+ BT_ASSERT(!stream_event_ctx_type);
return ret;
}
{
struct search_query query = { .value = clock_class, .found = 0 };
- assert(trace);
- assert(clock_class);
+ BT_ASSERT(trace);
+ BT_ASSERT(clock_class);
g_ptr_array_foreach(trace->clocks, value_exists, &query);
return query.found;
g_string_append(context->string, "trace {\n");
g_string_append(context->string, "\tmajor = 1;\n");
g_string_append(context->string, "\tminor = 8;\n");
- assert(trace->native_byte_order == BT_BYTE_ORDER_LITTLE_ENDIAN ||
+ BT_ASSERT(trace->native_byte_order == BT_BYTE_ORDER_LITTLE_ENDIAN ||
trace->native_byte_order == BT_BYTE_ORDER_BIG_ENDIAN ||
trace->native_byte_order == BT_BYTE_ORDER_NETWORK);
env_field_value_obj = bt_attributes_get_field_value(
trace->environment, i);
- assert(entry_name);
- assert(env_field_value_obj);
+ BT_ASSERT(entry_name);
+ BT_ASSERT(env_field_value_obj);
switch (bt_value_get_type(env_field_value_obj)) {
case BT_VALUE_TYPE_INTEGER:
ret = bt_value_integer_get(env_field_value_obj,
&int_value);
- assert(ret == 0);
+ BT_ASSERT(ret == 0);
g_string_append_printf(context->string,
"\t%s = %" PRId64 ";\n", entry_name,
int_value);
ret = bt_value_string_get(env_field_value_obj,
&str_value);
- assert(ret == 0);
+ BT_ASSERT(ret == 0);
escaped_str = g_strescape(str_value, NULL);
if (!escaped_str) {
BT_LOGE("Cannot escape string: string=\"%s\"",
size_t i;
struct bt_trace *trace = trace_ptr;
- assert(trace);
- assert(object);
+ BT_ASSERT(trace);
+ BT_ASSERT(object);
if (trace->listeners->len == 0) {
goto end;
goto end;
}
+ ret = check_packet_header_type_has_no_clock_class(trace);
+ if (ret) {
+ /* check_packet_header_type_has_no_clock_class() logs errors */
+ goto end;
+ }
+
trace->is_static = BT_TRUE;
bt_trace_freeze(trace);
BT_LOGV("Set trace static: addr=%p, name=\"%s\"",