#include <babeltrace/ctf-ir/stream-class-internal.h>
#include <babeltrace/ctf-writer/functor-internal.h>
#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/ctf-ir/utils.h>
#include <babeltrace/compiler.h>
#define DEFAULT_IDENTIFIER_SIZE 128
static
int init_trace_packet_header(struct bt_ctf_trace *trace);
-static
-const char * const reserved_keywords_str[] = {"align", "callsite",
- "const", "char", "clock", "double", "enum", "env", "event",
- "floating_point", "float", "integer", "int", "long", "short", "signed",
- "stream", "string", "struct", "trace", "typealias", "typedef",
- "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"};
-
static
const unsigned int field_type_aliases_alignments[] = {
[FIELD_TYPE_ALIAS_UINT5_T] = 1,
[FIELD_TYPE_ALIAS_UINT64_T] = 64,
};
-static GHashTable *reserved_keywords_set;
-static int init_done;
-static int global_data_refcount;
-
struct bt_ctf_trace *bt_ctf_trace_create(void)
{
struct bt_ctf_trace *trace = NULL;
goto error;
}
- ret = bt_ctf_stream_class_set_byte_order(stream_class,
- trace->byte_order == LITTLE_ENDIAN ?
- BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN);
- if (ret) {
- goto error;
- }
-
stream = bt_ctf_stream_create(stream_class, trace);
if (!stream) {
goto error;
}
if (!stream_class_found) {
- int64_t stream_id = bt_ctf_stream_class_get_id(stream_class);
-
- if (stream_id < 0) {
- /* Try to assign a new stream id */
- if (bt_ctf_stream_class_set_id(stream->stream_class,
- trace->next_stream_id++)) {
- goto error;
- }
- }
-
- for (i = 0; i < trace->stream_classes->len; i++) {
- if (stream_id == bt_ctf_stream_class_get_id(
- trace->stream_classes->pdata[i])) {
- /* Duplicate stream id found */
- goto error;
- }
+ ret = bt_ctf_trace_add_stream_class(trace, stream_class);
+ if (ret) {
+ goto error;
}
- bt_ctf_stream_class_get(stream->stream_class);
- g_ptr_array_add(trace->stream_classes, stream->stream_class);
}
bt_ctf_stream_get(stream);
g_ptr_array_add(trace->streams, stream);
- trace->frozen = 1;
- return stream;
+ return stream;
error:
bt_ctf_stream_put(stream);
return NULL;
char *escaped_value = NULL;
int ret = 0;
- if (!trace || !name || !value || validate_identifier(name)) {
+ if (!trace || !name || !value || bt_ctf_validate_identifier(name)) {
ret = -1;
goto error;
}
goto error;
}
+ var->type = BT_ENVIRONMENT_FIELD_TYPE_STRING;
escaped_value = g_strescape(value, NULL);
if (!escaped_value) {
ret = -1;
}
var->name = g_string_new(name);
- var->value = g_string_new(escaped_value);
+ var->value.string = g_string_new(escaped_value);
g_free(escaped_value);
- if (!var->name || !var->value) {
+ if (!var->name || !var->value.string) {
ret = -1;
goto error;
}
g_string_free(var->name, TRUE);
}
- if (var && var->value) {
- g_string_free(var->value, TRUE);
+ if (var && var->value.string) {
+ g_string_free(var->value.string, TRUE);
+ }
+
+ g_free(var);
+ return ret;
+}
+
+int bt_ctf_trace_add_environment_field_integer(struct bt_ctf_trace *trace,
+ const char *name,
+ int64_t value)
+{
+ struct environment_variable *var = NULL;
+ int ret = 0;
+
+ if (!trace || !name) {
+ ret = -1;
+ goto error;
+ }
+
+ var = g_new0(struct environment_variable, 1);
+ if (!var) {
+ ret = -1;
+ goto error;
+ }
+
+ var->type = BT_ENVIRONMENT_FIELD_TYPE_INTEGER;
+ var->name = g_string_new(name);
+ var->value.integer = value;
+ if (!var->name) {
+ ret = -1;
+ goto error;
+ }
+
+ g_ptr_array_add(trace->environment, var);
+ return ret;
+
+error:
+ if (var && var->name) {
+ g_string_free(var->name, TRUE);
}
g_free(var);
return ret;
}
+int bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
+{
+ int ret = 0;
+
+ if (!trace) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = trace->environment->len;
+end:
+ return ret;
+}
+
+enum bt_environment_field_type
+bt_ctf_trace_get_environment_field_type(struct bt_ctf_trace *trace, int index)
+{
+ struct environment_variable *var;
+ enum bt_environment_field_type type = BT_ENVIRONMENT_FIELD_TYPE_UNKNOWN;
+
+ if (!trace || index < 0 || index >= trace->environment->len) {
+ goto end;
+ }
+
+ var = g_ptr_array_index(trace->environment, index);
+ type = var->type;
+end:
+ return type;
+}
+
+const char *
+bt_ctf_trace_get_environment_field_name(struct bt_ctf_trace *trace,
+ int index)
+{
+ struct environment_variable *var;
+ const char *ret = NULL;
+
+ if (!trace || index < 0 || index >= trace->environment->len) {
+ goto end;
+ }
+
+ var = g_ptr_array_index(trace->environment, index);
+ ret = var->name->str;
+end:
+ return ret;
+}
+
+const char *
+bt_ctf_trace_get_environment_field_value_string(struct bt_ctf_trace *trace,
+ int index)
+{
+ struct environment_variable *var;
+ const char *ret = NULL;
+
+ if (!trace || index < 0 || index >= trace->environment->len) {
+ goto end;
+ }
+
+ var = g_ptr_array_index(trace->environment, index);
+ if (var->type != BT_ENVIRONMENT_FIELD_TYPE_STRING) {
+ goto end;
+ }
+ ret = var->value.string->str;
+end:
+ return ret;
+}
+
+int
+bt_ctf_trace_get_environment_field_value_integer(struct bt_ctf_trace *trace,
+ int index, int64_t *value)
+{
+ struct environment_variable *var;
+ int ret = 0;
+
+ if (!trace || !value || index < 0 || index >= trace->environment->len) {
+ ret = -1;
+ goto end;
+ }
+
+ var = g_ptr_array_index(trace->environment, index);
+ if (var->type != BT_ENVIRONMENT_FIELD_TYPE_INTEGER) {
+ ret = -1;
+ goto end;
+ }
+ *value = var->value.integer;
+end:
+ return ret;
+}
+
int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace,
struct bt_ctf_clock *clock)
{
return clock;
}
+int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
+ struct bt_ctf_stream_class *stream_class)
+{
+ int ret, i;
+ int64_t stream_id;
+
+ if (!trace || !stream_class) {
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < trace->stream_classes->len; i++) {
+ if (trace->stream_classes->pdata[i] == stream_class) {
+ ret = -1;
+ goto end;
+ }
+ }
+
+ stream_id = bt_ctf_stream_class_get_id(stream_class);
+ if (stream_id < 0) {
+ stream_id = trace->next_stream_id++;
+
+ /* Try to assign a new stream id */
+ for (i = 0; i < trace->stream_classes->len; i++) {
+ if (stream_id == bt_ctf_stream_class_get_id(
+ trace->stream_classes->pdata[i])) {
+ /* Duplicate stream id found */
+ ret = -1;
+ goto end;
+ }
+ }
+
+ if (_bt_ctf_stream_class_set_id(stream_class,
+ trace->next_stream_id++)) {
+ /* TODO Should retry with a different stream id */
+ ret = -1;
+ goto end;
+ }
+ }
+
+ bt_ctf_stream_class_get(stream_class);
+ g_ptr_array_add(trace->stream_classes, stream_class);
+
+ /*
+ * Freeze the trace and its packet header.
+ *
+ * All field type byte orders set as "native" byte ordering can now be
+ * safely set to trace's own endianness, including the stream class'.
+ */
+ bt_ctf_field_type_set_native_byte_order(trace->packet_header_type,
+ trace->byte_order);
+ ret = bt_ctf_stream_class_set_byte_order(stream_class,
+ trace->byte_order == LITTLE_ENDIAN ?
+ BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN);
+ if (ret) {
+ goto end;
+ }
+ bt_ctf_stream_class_freeze(stream_class);
+ trace->frozen = 1;
+
+end:
+ return ret;
+}
+
+int bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
+{
+ int ret;
+
+ if (!trace) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = trace->stream_classes->len;
+end:
+ return ret;
+}
+
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class(
+ struct bt_ctf_trace *trace, int index)
+{
+ struct bt_ctf_stream_class *stream_class = NULL;
+
+ if (!trace || index < 0 || index >= trace->stream_classes->len) {
+ goto end;
+ }
+
+ stream_class = g_ptr_array_index(trace->stream_classes, index);
+ bt_ctf_stream_class_get(stream_class);
+end:
+ return stream_class;
+}
+
BT_HIDDEN
const char *get_byte_order_string(int byte_order)
{
void append_env_field_metadata(struct environment_variable *var,
struct metadata_context *context)
{
- g_string_append_printf(context->string, "\t%s = \"%s\";\n",
- var->name->str, var->value->str);
+ switch (var->type) {
+ case BT_ENVIRONMENT_FIELD_TYPE_STRING:
+ g_string_append_printf(context->string, "\t%s = \"%s\";\n",
+ var->name->str, var->value.string->str);
+ break;
+ case BT_ENVIRONMENT_FIELD_TYPE_INTEGER:
+ g_string_append_printf(context->string, "\t%s = %" PRId64 ";\n",
+ var->name->str, var->value.integer);
+ break;
+ default:
+ assert(0);
+ }
}
static
return metadata;
}
+enum bt_ctf_byte_order bt_ctf_trace_get_byte_order(struct bt_ctf_trace *trace)
+{
+ enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
+
+ if (!trace) {
+ goto end;
+ }
+
+ switch (trace->byte_order) {
+ case BIG_ENDIAN:
+ ret = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
+ break;
+ case LITTLE_ENDIAN:
+ ret = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
+ break;
+ default:
+ break;
+ }
+end:
+ return ret;
+}
+
int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace,
enum bt_ctf_byte_order byte_order)
{
switch (byte_order) {
case BT_CTF_BYTE_ORDER_NATIVE:
- internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ?
+ /*
+ * This doesn't make sense since the CTF specification defines
+ * the "native" byte order as "the byte order described in the
+ * trace description". However, this behavior had been
+ * implemented as part of v1.2 and is kept to maintain
+ * compatibility.
+ *
+ * This may be changed on a major version bump only.
+ */
+ internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ?
LITTLE_ENDIAN : BIG_ENDIAN;
break;
case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
}
trace->byte_order = internal_byte_order;
- if (trace->packet_header_type) {
- init_trace_packet_header(trace);
- }
end:
return ret;
}
bt_ctf_ref_put(&trace->ref_count, bt_ctf_trace_destroy);
}
-BT_HIDDEN
-int validate_identifier(const char *input_string)
-{
- int ret = 0;
- char *string = NULL;
- char *save_ptr, *token;
-
- if (!input_string || input_string[0] == '\0') {
- ret = -1;
- goto end;
- }
-
- string = strdup(input_string);
- if (!string) {
- ret = -1;
- goto end;
- }
-
- token = strtok_r(string, " ", &save_ptr);
- while (token) {
- if (g_hash_table_lookup_extended(reserved_keywords_set,
- GINT_TO_POINTER(g_quark_from_string(token)),
- NULL, NULL)) {
- ret = -1;
- goto end;
- }
-
- token = strtok_r(NULL, " ", &save_ptr);
- }
-end:
- free(string);
- return ret;
-}
-
BT_HIDDEN
struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
{
goto end;
}
- ret = bt_ctf_field_type_set_byte_order(_uint32_t,
- (trace->byte_order == LITTLE_ENDIAN ?
- BT_CTF_BYTE_ORDER_LITTLE_ENDIAN :
- BT_CTF_BYTE_ORDER_BIG_ENDIAN));
- if (ret) {
- goto end;
- }
-
ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
_uint32_t, "magic");
if (ret) {
goto end;
}
- bt_ctf_field_type_put(trace->packet_header_type);
- trace->packet_header_type = trace_packet_header_type;
+ ret = bt_ctf_trace_set_packet_header_type(trace,
+ trace_packet_header_type);
+ if (ret) {
+ goto end;
+ }
end:
bt_ctf_field_type_put(uuid_array_type);
bt_ctf_field_type_put(_uint32_t);
bt_ctf_field_type_put(_uint8_t);
bt_ctf_field_put(magic);
bt_ctf_field_put(uuid_array);
- if (ret) {
- bt_ctf_field_type_put(trace_packet_header_type);
- }
+ bt_ctf_field_type_put(trace_packet_header_type);
return ret;
}
void environment_variable_destroy(struct environment_variable *var)
{
g_string_free(var->name, TRUE);
- g_string_free(var->value, TRUE);
- g_free(var);
-}
-
-static __attribute__((constructor))
-void trace_init(void)
-{
- size_t i;
- const size_t reserved_keywords_count =
- sizeof(reserved_keywords_str) / sizeof(char *);
-
- global_data_refcount++;
- if (init_done) {
- return;
- }
-
- reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal);
- for (i = 0; i < reserved_keywords_count; i++) {
- gpointer quark = GINT_TO_POINTER(g_quark_from_string(
- reserved_keywords_str[i]));
-
- g_hash_table_insert(reserved_keywords_set, quark, quark);
- }
-
- init_done = 1;
-}
-
-static __attribute__((destructor))
-void trace_finalize(void)
-{
- if (--global_data_refcount == 0) {
- g_hash_table_destroy(reserved_keywords_set);
+ if (var->type == BT_ENVIRONMENT_FIELD_TYPE_STRING) {
+ g_string_free(var->value.string, TRUE);
}
+ g_free(var);
}