From 1c822dfb58d831ad298b704ecaea181c16d16f3f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 12 Oct 2016 06:43:48 -0400 Subject: [PATCH] Backport the CTF-IR interface --- configure.ac | 4 + formats/ctf/Makefile.am | 5 +- formats/ctf/ctf.c | 2 - formats/ctf/ir/Makefile.am | 29 + formats/ctf/ir/attributes.c | 291 ++ formats/ctf/ir/clock.c | 543 +++ formats/ctf/ir/event-class.c | 671 +++ formats/ctf/ir/event.c | 879 ++++ formats/ctf/ir/field-path.c | 147 + formats/ctf/ir/field-types.c | 4143 +++++++++++++++++ formats/ctf/ir/fields.c | 2357 ++++++++++ formats/ctf/ir/packet.c | 197 + formats/ctf/ir/resolve.c | 1193 +++++ formats/ctf/ir/stream-class.c | 918 ++++ formats/ctf/ir/stream.c | 1086 +++++ formats/ctf/ir/trace.c | 1120 +++++ formats/ctf/ir/utils.c | 106 + formats/ctf/ir/validation.c | 594 +++ formats/ctf/writer/Makefile.am | 5 - formats/ctf/writer/clock.c | 264 -- formats/ctf/writer/event-fields.c | 1262 ----- formats/ctf/writer/event-types.c | 1446 ------ formats/ctf/writer/event.c | 368 -- formats/ctf/writer/functor.c | 2 +- formats/ctf/writer/stream.c | 703 --- formats/ctf/writer/writer.c | 625 +-- include/Makefile.am | 42 +- include/babeltrace/compat/glib.h | 83 + .../babeltrace/ctf-ir/attributes-internal.h | 70 + include/babeltrace/ctf-ir/clock-internal.h | 91 + include/babeltrace/ctf-ir/clock.h | 247 + .../event-class-internal.h} | 69 +- include/babeltrace/ctf-ir/event-class.h | 309 ++ include/babeltrace/ctf-ir/event-internal.h | 78 + include/babeltrace/ctf-ir/event.h | 255 + .../babeltrace/ctf-ir/field-path-internal.h | 57 + include/babeltrace/ctf-ir/field-path.h | 81 + .../babeltrace/ctf-ir/field-types-internal.h | 276 ++ include/babeltrace/ctf-ir/field-types.h | 893 ++++ .../fields-internal.h} | 23 +- include/babeltrace/ctf-ir/fields.h | 467 ++ include/babeltrace/ctf-ir/metadata.h | 10 +- include/babeltrace/ctf-ir/packet-internal.h | 44 + include/babeltrace/ctf-ir/packet.h | 62 + include/babeltrace/ctf-ir/resolve-internal.h | 72 + .../stream-class-internal.h} | 65 +- include/babeltrace/ctf-ir/stream-class.h | 278 ++ .../stream-internal.h} | 53 +- include/babeltrace/ctf-ir/stream.h | 63 + include/babeltrace/ctf-ir/trace-internal.h | 82 + include/babeltrace/ctf-ir/trace.h | 345 ++ include/babeltrace/ctf-ir/utils.h | 56 + .../babeltrace/ctf-ir/validation-internal.h | 124 + include/babeltrace/ctf-writer/clock.h | 112 +- include/babeltrace/ctf-writer/event-fields.h | 164 +- .../ctf-writer/event-types-internal.h | 153 - include/babeltrace/ctf-writer/event-types.h | 299 +- include/babeltrace/ctf-writer/event.h | 110 +- .../babeltrace/ctf-writer/functor-internal.h | 2 +- include/babeltrace/ctf-writer/stream-class.h | 77 + include/babeltrace/ctf-writer/stream.h | 139 +- .../babeltrace/ctf-writer/writer-internal.h | 49 +- include/babeltrace/ctf-writer/writer.h | 48 +- include/babeltrace/object-internal.h | 117 + .../{ctf-writer => }/ref-internal.h | 38 +- include/babeltrace/ref.h | 108 + include/babeltrace/values.h | 976 ++++ lib/Makefile.am | 4 +- lib/ref.c | 55 + lib/values.c | 1202 +++++ tests/lib/test_ctf_writer.c | 15 - 71 files changed, 21258 insertions(+), 5665 deletions(-) create mode 100644 formats/ctf/ir/Makefile.am create mode 100644 formats/ctf/ir/attributes.c create mode 100644 formats/ctf/ir/clock.c create mode 100644 formats/ctf/ir/event-class.c create mode 100644 formats/ctf/ir/event.c create mode 100644 formats/ctf/ir/field-path.c create mode 100644 formats/ctf/ir/field-types.c create mode 100644 formats/ctf/ir/fields.c create mode 100644 formats/ctf/ir/packet.c create mode 100644 formats/ctf/ir/resolve.c create mode 100644 formats/ctf/ir/stream-class.c create mode 100644 formats/ctf/ir/stream.c create mode 100644 formats/ctf/ir/trace.c create mode 100644 formats/ctf/ir/utils.c create mode 100644 formats/ctf/ir/validation.c delete mode 100644 formats/ctf/writer/clock.c delete mode 100644 formats/ctf/writer/event-fields.c delete mode 100644 formats/ctf/writer/event-types.c delete mode 100644 formats/ctf/writer/event.c delete mode 100644 formats/ctf/writer/stream.c create mode 100644 include/babeltrace/compat/glib.h create mode 100644 include/babeltrace/ctf-ir/attributes-internal.h create mode 100644 include/babeltrace/ctf-ir/clock-internal.h create mode 100644 include/babeltrace/ctf-ir/clock.h rename include/babeltrace/{ctf-writer/event-internal.h => ctf-ir/event-class-internal.h} (59%) create mode 100644 include/babeltrace/ctf-ir/event-class.h create mode 100644 include/babeltrace/ctf-ir/event-internal.h create mode 100644 include/babeltrace/ctf-ir/event.h create mode 100644 include/babeltrace/ctf-ir/field-path-internal.h create mode 100644 include/babeltrace/ctf-ir/field-path.h create mode 100644 include/babeltrace/ctf-ir/field-types-internal.h create mode 100644 include/babeltrace/ctf-ir/field-types.h rename include/babeltrace/{ctf-writer/event-fields-internal.h => ctf-ir/fields-internal.h} (82%) create mode 100644 include/babeltrace/ctf-ir/fields.h create mode 100644 include/babeltrace/ctf-ir/packet-internal.h create mode 100644 include/babeltrace/ctf-ir/packet.h create mode 100644 include/babeltrace/ctf-ir/resolve-internal.h rename include/babeltrace/{ctf-writer/stream-internal.h => ctf-ir/stream-class-internal.h} (60%) create mode 100644 include/babeltrace/ctf-ir/stream-class.h rename include/babeltrace/{ctf-writer/clock-internal.h => ctf-ir/stream-internal.h} (55%) create mode 100644 include/babeltrace/ctf-ir/stream.h create mode 100644 include/babeltrace/ctf-ir/trace-internal.h create mode 100644 include/babeltrace/ctf-ir/trace.h create mode 100644 include/babeltrace/ctf-ir/utils.h create mode 100644 include/babeltrace/ctf-ir/validation-internal.h delete mode 100644 include/babeltrace/ctf-writer/event-types-internal.h create mode 100644 include/babeltrace/ctf-writer/stream-class.h create mode 100644 include/babeltrace/object-internal.h rename include/babeltrace/{ctf-writer => }/ref-internal.h (61%) create mode 100644 include/babeltrace/ref.h create mode 100644 include/babeltrace/values.h create mode 100644 lib/ref.c create mode 100644 lib/values.c diff --git a/configure.ac b/configure.ac index 9bdc879a..d91bee4a 100644 --- a/configure.ac +++ b/configure.ac @@ -302,6 +302,9 @@ AC_SUBST(babeltracectfincludedir) babeltracectfwriterincludedir="${includedir}/babeltrace/ctf-writer" AC_SUBST(babeltracectfwriterincludedir) +babeltracectfirincludedir="${includedir}/babeltrace/ctf-ir" +AC_SUBST(babeltracectfirincludedir) + AC_CONFIG_FILES([ Makefile types/Makefile @@ -316,6 +319,7 @@ AC_CONFIG_FILES([ formats/lttng-live/Makefile formats/ctf/metadata/Makefile formats/ctf/writer/Makefile + formats/ctf/ir/Makefile converter/Makefile doc/Makefile lib/Makefile diff --git a/formats/ctf/Makefile.am b/formats/ctf/Makefile.am index 909e59be..2eb526d1 100644 --- a/formats/ctf/Makefile.am +++ b/formats/ctf/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(builddir) -SUBDIRS = types metadata writer . +SUBDIRS = types metadata writer ir . lib_LTLIBRARIES = libbabeltrace-ctf.la @@ -20,7 +20,8 @@ libbabeltrace_ctf_la_LIBADD = \ types/libctf-types.la \ metadata/libctf-parser.la \ metadata/libctf-ast.la \ - writer/libctf-writer.la + writer/libctf-writer.la \ + ir/libctf-ir.la if ENABLE_DEBUG_INFO libbabeltrace_ctf_la_LIBADD += $(top_builddir)/lib/libdebug-info.la diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index bc962121..324b9f8e 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -779,8 +779,6 @@ int ctf_init_pos(struct ctf_stream_pos *pos, struct bt_trace_descriptor *trace, pos->parent.rw_table = write_dispatch_table; pos->parent.event_cb = ctf_write_event; pos->parent.trace = trace; - if (fd >= 0) - ctf_packet_seek(&pos->parent, 0, SEEK_SET); /* position for write */ break; default: assert(0); diff --git a/formats/ctf/ir/Makefile.am b/formats/ctf/ir/Makefile.am new file mode 100644 index 00000000..b9048bc5 --- /dev/null +++ b/formats/ctf/ir/Makefile.am @@ -0,0 +1,29 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include + +noinst_LTLIBRARIES = libctf-ir.la + +libctf_ir_la_SOURCES = \ + attributes.c \ + clock.c \ + event.c \ + event-class.c \ + fields.c \ + field-types.c \ + field-path.c \ + packet.c \ + stream.c \ + stream-class.c \ + trace.c \ + utils.c \ + resolve.c \ + validation.c + +libctf_ir_la_LIBADD = \ + $(top_builddir)/lib/libbabeltrace.la + +if BABELTRACE_BUILD_WITH_LIBUUID +libctf_ir_la_LIBADD += -luuid +endif +if BABELTRACE_BUILD_WITH_LIBC_UUID +libctf_ir_la_LIBADD += -lc +endif diff --git a/formats/ctf/ir/attributes.c b/formats/ctf/ir/attributes.c new file mode 100644 index 00000000..c6e8a232 --- /dev/null +++ b/formats/ctf/ir/attributes.c @@ -0,0 +1,291 @@ +/* + * attributes.c + * + * Babeltrace CTF IR - Attributes + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#define BT_CTF_ATTR_NAME_INDEX 0 +#define BT_CTF_ATTR_VALUE_INDEX 1 + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_create(void) +{ + /* + * Attributes: array value object of array value objects, each one + * containing two entries: a string value object (attributes + * field name), and a value object (attributes field value). + * + * Example (JSON representation): + * + * [ + * ["hostname", "eeppdesk"], + * ["sysname", "Linux"], + * ["tracer_major", 2], + * ["tracer_minor", 5] + * ] + */ + return bt_value_array_create(); +} + +BT_HIDDEN +void bt_ctf_attributes_destroy(struct bt_value *attr_obj) +{ + bt_put(attr_obj); +} + +BT_HIDDEN +int bt_ctf_attributes_get_count(struct bt_value *attr_obj) +{ + return bt_value_array_size(attr_obj); +} + +BT_HIDDEN +const char *bt_ctf_attributes_get_field_name(struct bt_value *attr_obj, + int index) +{ + int rc; + const char *ret = NULL; + struct bt_value *attr_field_obj = NULL; + struct bt_value *attr_field_name_obj = NULL; + + if (!attr_obj || index < 0) { + goto end; + } + + attr_field_obj = bt_value_array_get(attr_obj, index); + + if (!attr_field_obj) { + goto end; + } + + attr_field_name_obj = bt_value_array_get(attr_field_obj, + BT_CTF_ATTR_NAME_INDEX); + + if (!attr_field_name_obj) { + goto end; + } + + rc = bt_value_string_get(attr_field_name_obj, &ret); + + if (rc) { + ret = NULL; + } + +end: + BT_PUT(attr_field_name_obj); + BT_PUT(attr_field_obj); + return ret; +} + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_get_field_value(struct bt_value *attr_obj, + int index) +{ + struct bt_value *value_obj = NULL; + struct bt_value *attr_field_obj = NULL; + + if (!attr_obj || index < 0) { + goto end; + } + + attr_field_obj = bt_value_array_get(attr_obj, index); + + if (!attr_field_obj) { + goto end; + } + + value_obj = bt_value_array_get(attr_field_obj, + BT_CTF_ATTR_VALUE_INDEX); + +end: + BT_PUT(attr_field_obj); + return value_obj; +} + +static +struct bt_value *bt_ctf_attributes_get_field_by_name( + struct bt_value *attr_obj, const char *name) +{ + int i; + int attr_size; + struct bt_value *value_obj = NULL; + struct bt_value *attr_field_name_obj = NULL; + + attr_size = bt_value_array_size(attr_obj); + + if (attr_size < 0) { + goto error; + } + + for (i = 0; i < attr_size; ++i) { + int ret; + const char *field_name; + + value_obj = bt_value_array_get(attr_obj, i); + + if (!value_obj) { + goto error; + } + + attr_field_name_obj = bt_value_array_get(value_obj, 0); + + if (!attr_field_name_obj) { + goto error; + } + + ret = bt_value_string_get(attr_field_name_obj, &field_name); + if (ret) { + goto error; + } + + if (!strcmp(field_name, name)) { + BT_PUT(attr_field_name_obj); + break; + } + + BT_PUT(attr_field_name_obj); + BT_PUT(value_obj); + } + + return value_obj; + +error: + BT_PUT(attr_field_name_obj); + BT_PUT(value_obj); + + return value_obj; +} + +BT_HIDDEN +int bt_ctf_attributes_set_field_value(struct bt_value *attr_obj, + const char *name, struct bt_value *value_obj) +{ + int ret = 0; + struct bt_value *attr_field_obj = NULL; + + if (!attr_obj || !name || !value_obj) { + ret = -1; + goto end; + } + + attr_field_obj = bt_ctf_attributes_get_field_by_name(attr_obj, name); + + if (attr_field_obj) { + ret = bt_value_array_set(attr_field_obj, + BT_CTF_ATTR_VALUE_INDEX, value_obj); + goto end; + } + + attr_field_obj = bt_value_array_create(); + + if (!attr_field_obj) { + ret = -1; + goto end; + } + + ret = bt_value_array_append_string(attr_field_obj, name); + ret |= bt_value_array_append(attr_field_obj, value_obj); + + if (ret) { + goto end; + } + + ret = bt_value_array_append(attr_obj, attr_field_obj); + +end: + BT_PUT(attr_field_obj); + + return ret; +} + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_get_field_value_by_name( + struct bt_value *attr_obj, const char *name) +{ + struct bt_value *value_obj = NULL; + struct bt_value *attr_field_obj = NULL; + + if (!attr_obj || !name) { + goto end; + } + + attr_field_obj = bt_ctf_attributes_get_field_by_name(attr_obj, name); + + if (!attr_field_obj) { + goto end; + } + + value_obj = bt_value_array_get(attr_field_obj, + BT_CTF_ATTR_VALUE_INDEX); + +end: + BT_PUT(attr_field_obj); + + return value_obj; +} + +BT_HIDDEN +int bt_ctf_attributes_freeze(struct bt_value *attr_obj) +{ + int i; + int count; + int ret = 0; + + if (!attr_obj) { + ret = -1; + goto end; + } + + count = bt_value_array_size(attr_obj); + + if (count < 0) { + ret = -1; + goto end; + } + + /* + * We do not freeze the array value object itself here, since + * internal stuff could need to modify/add attributes. Each + * attribute is frozen one by one. + */ + for (i = 0; i < count; ++i) { + struct bt_value *obj = NULL; + + obj = bt_ctf_attributes_get_field_value(attr_obj, i); + + if (!obj) { + ret = -1; + goto end; + } + + bt_value_freeze(obj); + BT_PUT(obj); + } + +end: + return ret; +} diff --git a/formats/ctf/ir/clock.c b/formats/ctf/ir/clock.c new file mode 100644 index 00000000..9256bc1f --- /dev/null +++ b/formats/ctf/ir/clock.c @@ -0,0 +1,543 @@ +/* + * clock.c + * + * Babeltrace CTF IR - Clock + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_clock_destroy(struct bt_object *obj); + +BT_HIDDEN +struct bt_ctf_clock *_bt_ctf_clock_create(void) +{ + struct bt_ctf_clock *clock = g_new0( + struct bt_ctf_clock, 1); + + if (!clock) { + goto end; + } + + clock->precision = 1; + clock->frequency = 1000000000; + bt_object_init(clock, bt_ctf_clock_destroy); +end: + return clock; +} + +BT_HIDDEN +int bt_ctf_clock_set_name(struct bt_ctf_clock *clock, + const char *name) +{ + int ret = 0; + + if (bt_ctf_validate_identifier(name)) { + ret = -1; + goto end; + } + + if (clock->name) { + g_string_assign(clock->name, name); + } else { + clock->name = g_string_new(name); + if (!clock->name) { + ret = -1; + goto end; + } + } + +end: + return ret; +} + +struct bt_ctf_clock *bt_ctf_clock_create(const char *name) +{ + int ret; + struct bt_ctf_clock *clock = NULL; + + clock = _bt_ctf_clock_create(); + if (!clock) { + goto error; + } + + ret = bt_ctf_clock_set_name(clock, name); + if (ret) { + goto error; + } + + ret = bt_uuid_generate(clock->uuid); + if (ret) { + goto error; + } + + /* + * For backward compatibility reasons, a fresh clock can have + * a value because it could be added to a trace created by a + * CTF writer. As soon as this clock is added to a non-writer + * trace, then its value/time functions will be disabled. + */ + clock->has_value = 1; + clock->uuid_set = 1; + return clock; +error: + BT_PUT(clock); + return clock; +} + +const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock) +{ + const char *ret = NULL; + + if (!clock) { + goto end; + } + + if (clock->name) { + ret = clock->name->str; + } + +end: + return ret; +} + +const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock) +{ + const char *ret = NULL; + + if (!clock) { + goto end; + } + + if (clock->description) { + ret = clock->description->str; + } +end: + return ret; +} + +int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc) +{ + int ret = 0; + + if (!clock || !desc || clock->frozen) { + ret = -1; + goto end; + } + + clock->description = g_string_new(desc); + ret = clock->description ? 0 : -1; +end: + return ret; +} + +uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock) +{ + uint64_t ret = -1ULL; + + if (!clock) { + goto end; + } + + ret = clock->frequency; +end: + return ret; +} + +int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq) +{ + int ret = 0; + + if (!clock || clock->frozen) { + ret = -1; + goto end; + } + + clock->frequency = freq; +end: + return ret; +} + +uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock) +{ + uint64_t ret = -1ULL; + + if (!clock) { + goto end; + } + + ret = clock->precision; +end: + return ret; +} + +int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision) +{ + int ret = 0; + + if (!clock || clock->frozen) { + ret = -1; + goto end; + } + + clock->precision = precision; +end: + return ret; +} + +int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s) +{ + int ret = 0; + + if (!clock || !offset_s) { + ret = -1; + goto end; + } + + *offset_s = clock->offset_s; +end: + return ret; +} + +int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s) +{ + int ret = 0; + + if (!clock || clock->frozen) { + ret = -1; + goto end; + } + + clock->offset_s = offset_s; +end: + return ret; +} + +int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset) +{ + int ret = 0; + + if (!clock || !offset) { + ret = -1; + goto end; + } + + *offset = clock->offset; +end: + return ret; +} + +int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset) +{ + int ret = 0; + + if (!clock || clock->frozen) { + ret = -1; + goto end; + } + + clock->offset = offset; +end: + return ret; +} + +int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock) +{ + int ret = -1; + + if (!clock) { + goto end; + } + + ret = clock->absolute; +end: + return ret; +} + +int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute) +{ + int ret = 0; + + if (!clock || clock->frozen) { + ret = -1; + goto end; + } + + clock->absolute = !!is_absolute; +end: + return ret; +} + +const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock) +{ + const unsigned char *ret; + + if (!clock || !clock->uuid_set) { + ret = NULL; + goto end; + } + + ret = clock->uuid; +end: + return ret; +} + +int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid) +{ + int ret = 0; + + if (!clock || !uuid || clock->frozen) { + ret = -1; + goto end; + } + + memcpy(clock->uuid, uuid, sizeof(uuid_t)); + clock->uuid_set = 1; +end: + return ret; +} + +uint64_t ns_from_value(uint64_t frequency, uint64_t value) +{ + uint64_t ns; + + if (frequency == 1000000000) { + ns = value; + } else { + ns = (uint64_t) ((1e9 * (double) value) / (double) frequency); + } + + return ns; +} + +int bt_ctf_clock_get_time(struct bt_ctf_clock *clock, int64_t *time) +{ + int ret = 0; + + if (!clock || !time) { + ret = -1; + goto end; + } + + + if (!clock->has_value) { + /* + * Clock belongs to a non-writer mode trace and thus + * this function is disabled. + */ + goto end; + } + + *time = (int64_t) ns_from_value(clock->frequency, clock->value); + +end: + return ret; +} + +int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time) +{ + int ret = 0; + int64_t value; + + /* Timestamps are strictly monotonic */ + if (!clock) { + ret = -1; + goto end; + } + + + if (!clock->has_value) { + /* + * Clock belongs to a non-writer mode trace and thus + * this function is disabled. + */ + ret = -1; + goto end; + } + + /* Common case where cycles are actually nanoseconds */ + if (clock->frequency == 1000000000) { + value = time; + } else { + value = (uint64_t) (((double) time * + (double) clock->frequency) / 1e9); + } + + ret = bt_ctf_clock_set_value(clock, value); +end: + return ret; +} + +uint64_t bt_ctf_clock_get_value(struct bt_ctf_clock *clock) +{ + uint64_t ret = -1ULL; + + if (!clock) { + goto end; + } + + if (!clock->has_value) { + /* + * Clock belongs to a non-writer mode trace and thus + * this function is disabled. + */ + goto end; + } + + ret = clock->value; +end: + return ret; +} + +int bt_ctf_clock_set_value(struct bt_ctf_clock *clock, uint64_t value) +{ + int ret = 0; + + if (!clock) { + ret = -1; + goto end; + } + + if (!clock->has_value) { + /* + * Clock belongs to a non-writer mode trace and thus + * this function is disabled. + */ + ret = -1; + goto end; + } + + /* Timestamps are strictly monotonic */ + if (value < clock->value) { + ret = -1; + goto end; + } + + clock->value = value; +end: + return ret; +} + +void bt_ctf_clock_get(struct bt_ctf_clock *clock) +{ + bt_get(clock); +} + +void bt_ctf_clock_put(struct bt_ctf_clock *clock) +{ + bt_put(clock); +} + +BT_HIDDEN +void bt_ctf_clock_freeze(struct bt_ctf_clock *clock) +{ + if (!clock) { + return; + } + + clock->frozen = 1; +} + +BT_HIDDEN +void bt_ctf_clock_serialize(struct bt_ctf_clock *clock, + struct metadata_context *context) +{ + unsigned char *uuid; + + if (!clock || !context) { + return; + } + + uuid = clock->uuid; + g_string_append(context->string, "clock {\n"); + g_string_append_printf(context->string, "\tname = %s;\n", + clock->name->str); + g_string_append_printf(context->string, + "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + if (clock->description) { + g_string_append_printf(context->string, "\tdescription = \"%s\";\n", + clock->description->str); + } + + g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", + clock->frequency); + g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", + clock->precision); + g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", + clock->offset_s); + g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", + clock->offset); + g_string_append_printf(context->string, "\tabsolute = %s;\n", + clock->absolute ? "TRUE" : "FALSE"); + g_string_append(context->string, "};\n\n"); +} + +static +void bt_ctf_clock_destroy(struct bt_object *obj) +{ + struct bt_ctf_clock *clock; + + clock = container_of(obj, struct bt_ctf_clock, base); + if (clock->name) { + g_string_free(clock->name, TRUE); + } + + if (clock->description) { + g_string_free(clock->description, TRUE); + } + + g_free(clock); +} + +int64_t bt_ctf_clock_ns_from_value(struct bt_ctf_clock *clock, uint64_t value) +{ + int64_t ns = -1ULL; + + if (!clock) { + goto end; + } + + /* Initialize nanosecond timestamp to clock's offset in seconds */ + ns = clock->offset_s * 1000000000; + + /* Add offset in cycles, converted to nanoseconds */ + ns += ns_from_value(clock->frequency, clock->offset); + + /* Add given value, converter to nanoseconds */ + ns += ns_from_value(clock->frequency, value); + +end: + return ns; +} diff --git a/formats/ctf/ir/event-class.c b/formats/ctf/ir/event-class.c new file mode 100644 index 00000000..750203ae --- /dev/null +++ b/formats/ctf/ir/event-class.c @@ -0,0 +1,671 @@ +/* + * event-class.c + * + * Babeltrace CTF IR - Event class + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_event_class_destroy(struct bt_object *obj); + +struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name) +{ + int ret; + struct bt_value *obj = NULL; + struct bt_ctf_event_class *event_class = NULL; + + if (bt_ctf_validate_identifier(name)) { + goto error; + } + + event_class = g_new0(struct bt_ctf_event_class, 1); + if (!event_class) { + goto error; + } + + bt_object_init(event_class, bt_ctf_event_class_destroy); + event_class->fields = bt_ctf_field_type_structure_create(); + if (!event_class->fields) { + goto error; + } + + event_class->attributes = bt_ctf_attributes_create(); + if (!event_class->attributes) { + goto error; + } + + obj = bt_value_integer_create_init(-1); + if (!obj) { + goto error; + } + + ret = bt_ctf_attributes_set_field_value(event_class->attributes, + "id", obj); + if (ret) { + goto error; + } + + BT_PUT(obj); + + obj = bt_value_string_create_init(name); + if (!obj) { + goto error; + } + + ret = bt_ctf_attributes_set_field_value(event_class->attributes, + "name", obj); + if (ret) { + goto error; + } + + BT_PUT(obj); + + return event_class; + +error: + BT_PUT(event_class); + BT_PUT(obj); + return event_class; +} + +const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class) +{ + struct bt_value *obj = NULL; + const char *name = NULL; + + if (!event_class) { + goto end; + } + + obj = bt_ctf_attributes_get_field_value(event_class->attributes, + BT_CTF_EVENT_CLASS_ATTR_NAME_INDEX); + if (!obj) { + goto end; + } + + if (bt_value_string_get(obj, &name)) { + name = NULL; + } + +end: + BT_PUT(obj); + return name; +} + +int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class) +{ + struct bt_value *obj = NULL; + int64_t ret = 0; + + if (!event_class) { + ret = -1; + goto end; + } + + obj = bt_ctf_attributes_get_field_value(event_class->attributes, + BT_CTF_EVENT_CLASS_ATTR_ID_INDEX); + if (!obj) { + goto end; + } + + if (bt_value_integer_get(obj, &ret)) { + ret = -1; + } + + if (ret < 0) { + /* means ID is not set */ + ret = -1; + goto end; + } + +end: + BT_PUT(obj); + return ret; +} + +int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, + uint32_t id) +{ + int ret = 0; + struct bt_value *obj = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + + + if (!event_class) { + ret = -1; + goto end; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (stream_class) { + /* + * We don't allow changing the id if the event class has already + * been added to a stream class. + */ + ret = -1; + goto end; + } + + obj = bt_ctf_attributes_get_field_value(event_class->attributes, + BT_CTF_EVENT_CLASS_ATTR_ID_INDEX); + if (!obj) { + goto end; + } + + if (bt_value_integer_set(obj, id)) { + ret = -1; + goto end; + } + +end: + BT_PUT(obj); + BT_PUT(stream_class); + return ret; +} + +int bt_ctf_event_class_set_attribute( + struct bt_ctf_event_class *event_class, const char *name, + struct bt_value *value) +{ + int ret = 0; + + if (!event_class || !name || !value || event_class->frozen) { + ret = -1; + goto end; + } + + if (!strcmp(name, "id") || !strcmp(name, "loglevel")) { + if (!bt_value_is_integer(value)) { + ret = -1; + goto end; + } + } else if (!strcmp(name, "name") || !strcmp(name, "model.emf.uri")) { + if (!bt_value_is_string(value)) { + ret = -1; + goto end; + } + } else { + /* unknown attribute */ + ret = -1; + goto end; + } + + /* "id" special case: >= 0 */ + if (!strcmp(name, "id")) { + int64_t val; + + ret = bt_value_integer_get(value, &val); + + if (ret) { + goto end; + } + + if (val < 0) { + ret = -1; + goto end; + } + } + + ret = bt_ctf_attributes_set_field_value(event_class->attributes, + name, value); + +end: + return ret; +} + +int bt_ctf_event_class_get_attribute_count( + struct bt_ctf_event_class *event_class) +{ + int ret = 0; + + if (!event_class) { + ret = -1; + goto end; + } + + ret = bt_ctf_attributes_get_count(event_class->attributes); + +end: + return ret; +} + +const char * +bt_ctf_event_class_get_attribute_name( + struct bt_ctf_event_class *event_class, int index) +{ + const char *ret; + + if (!event_class) { + ret = NULL; + goto end; + } + + ret = bt_ctf_attributes_get_field_name(event_class->attributes, index); + +end: + return ret; +} + +struct bt_value * +bt_ctf_event_class_get_attribute_value(struct bt_ctf_event_class *event_class, + int index) +{ + struct bt_value *ret; + + if (!event_class) { + ret = NULL; + goto end; + } + + ret = bt_ctf_attributes_get_field_value(event_class->attributes, index); + +end: + return ret; +} + +struct bt_value * +bt_ctf_event_class_get_attribute_value_by_name( + struct bt_ctf_event_class *event_class, const char *name) +{ + struct bt_value *ret; + + if (!event_class || !name) { + ret = NULL; + goto end; + } + + ret = bt_ctf_attributes_get_field_value_by_name(event_class->attributes, + name); + +end: + return ret; + +} + +struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class( + struct bt_ctf_event_class *event_class) +{ + return (struct bt_ctf_stream_class *) bt_object_get_parent(event_class); +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_payload_type( + struct bt_ctf_event_class *event_class) +{ + struct bt_ctf_field_type *payload = NULL; + + if (!event_class) { + goto end; + } + + bt_get(event_class->fields); + payload = event_class->fields; +end: + return payload; +} + +int bt_ctf_event_class_set_payload_type(struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *payload) +{ + int ret = 0; + + if (!event_class || !payload || + bt_ctf_field_type_get_type_id(payload) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + bt_get(payload); + bt_put(event_class->fields); + event_class->fields = payload; +end: + return ret; +} + +int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *type, + const char *name) +{ + int ret = 0; + + if (!event_class || !type || bt_ctf_validate_identifier(name) || + event_class->frozen) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_class->fields) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(event_class->fields, + type, name); +end: + return ret; +} + +int bt_ctf_event_class_get_field_count( + struct bt_ctf_event_class *event_class) +{ + int ret; + + if (!event_class) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_class->fields) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_get_field_count(event_class->fields); +end: + return ret; +} + +int bt_ctf_event_class_get_field(struct bt_ctf_event_class *event_class, + const char **field_name, struct bt_ctf_field_type **field_type, + int index) +{ + int ret; + + if (!event_class || index < 0) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_class->fields) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_get_field(event_class->fields, + field_name, field_type, index); +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name( + struct bt_ctf_event_class *event_class, const char *name) +{ + GQuark name_quark; + struct bt_ctf_field_type *field_type = NULL; + + if (!event_class || !name) { + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_class->fields) != + BT_CTF_TYPE_ID_STRUCT) { + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + goto end; + } + + /* + * No need to increment field_type's reference count since getting it + * from the structure already does. + */ + field_type = bt_ctf_field_type_structure_get_field_type_by_name( + event_class->fields, name); +end: + return field_type; +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_context_type( + struct bt_ctf_event_class *event_class) +{ + struct bt_ctf_field_type *context_type = NULL; + + if (!event_class || !event_class->context) { + goto end; + } + + bt_get(event_class->context); + context_type = event_class->context; +end: + return context_type; +} + +int bt_ctf_event_class_set_context_type( + struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *context) +{ + int ret = 0; + + if (!event_class || !context || event_class->frozen) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(context) != BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + bt_get(context); + bt_put(event_class->context); + event_class->context = context; +end: + return ret; + +} + +void bt_ctf_event_class_get(struct bt_ctf_event_class *event_class) +{ + bt_get(event_class); +} + +void bt_ctf_event_class_put(struct bt_ctf_event_class *event_class) +{ + bt_put(event_class); +} + +BT_HIDDEN +int bt_ctf_event_class_set_stream_id(struct bt_ctf_event_class *event_class, + uint32_t stream_id) +{ + int ret = 0; + struct bt_value *obj; + + obj = bt_value_integer_create_init(stream_id); + + if (!obj) { + ret = -1; + goto end; + } + + ret = bt_ctf_attributes_set_field_value(event_class->attributes, + "stream_id", obj); + + if (event_class->frozen) { + bt_ctf_attributes_freeze(event_class->attributes); + } + +end: + BT_PUT(obj); + return ret; +} + +static +void bt_ctf_event_class_destroy(struct bt_object *obj) +{ + struct bt_ctf_event_class *event_class; + + event_class = container_of(obj, struct bt_ctf_event_class, base); + bt_ctf_attributes_destroy(event_class->attributes); + bt_put(event_class->context); + bt_put(event_class->fields); + g_free(event_class); +} + +BT_HIDDEN +void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class) +{ + assert(event_class); + event_class->frozen = 1; + bt_ctf_field_type_freeze(event_class->context); + bt_ctf_field_type_freeze(event_class->fields); + bt_ctf_attributes_freeze(event_class->attributes); +} + +BT_HIDDEN +int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, + struct metadata_context *context) +{ + int i; + int count; + int ret = 0; + struct bt_value *attr_value = NULL; + + assert(event_class); + assert(context); + + context->current_indentation_level = 1; + g_string_assign(context->field_name, ""); + g_string_append(context->string, "event {\n"); + count = bt_ctf_event_class_get_attribute_count(event_class); + + if (count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < count; ++i) { + const char *attr_name = NULL; + + attr_name = bt_ctf_event_class_get_attribute_name( + event_class, i); + attr_value = bt_ctf_event_class_get_attribute_value( + event_class, i); + + if (!attr_name || !attr_value) { + ret = -1; + goto end; + } + + switch (bt_value_get_type(attr_value)) { + case BT_VALUE_TYPE_INTEGER: + { + int64_t value; + + ret = bt_value_integer_get(attr_value, &value); + + if (ret) { + goto end; + } + + g_string_append_printf(context->string, + "\t%s = %" PRId64 ";\n", attr_name, value); + break; + } + + case BT_VALUE_TYPE_STRING: + { + const char *value; + + ret = bt_value_string_get(attr_value, &value); + + if (ret) { + goto end; + } + + g_string_append_printf(context->string, + "\t%s = \"%s\";\n", attr_name, value); + break; + } + + default: + /* should never happen */ + assert(false); + break; + } + + BT_PUT(attr_value); + } + + if (event_class->context) { + g_string_append(context->string, "\tcontext := "); + ret = bt_ctf_field_type_serialize(event_class->context, + context); + if (ret) { + goto end; + } + g_string_append(context->string, ";\n"); + } + + if (event_class->fields) { + g_string_append(context->string, "\tfields := "); + ret = bt_ctf_field_type_serialize(event_class->fields, context); + if (ret) { + goto end; + } + g_string_append(context->string, ";\n"); + } + + g_string_append(context->string, "};\n\n"); +end: + context->current_indentation_level = 0; + BT_PUT(attr_value); + return ret; +} + +void bt_ctf_event_class_set_native_byte_order( + struct bt_ctf_event_class *event_class, + int byte_order) +{ + if (!event_class) { + return; + } + + assert(byte_order == 0 || byte_order == LITTLE_ENDIAN || + byte_order == BIG_ENDIAN); + + bt_ctf_field_type_set_native_byte_order(event_class->context, + byte_order); + bt_ctf_field_type_set_native_byte_order(event_class->fields, + byte_order); +} diff --git a/formats/ctf/ir/event.c b/formats/ctf/ir/event.c new file mode 100644 index 00000000..3ea59eaa --- /dev/null +++ b/formats/ctf/ir/event.c @@ -0,0 +1,879 @@ +/* + * event.c + * + * Babeltrace CTF IR - Event + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_event_destroy(struct bt_object *obj); +static +int set_integer_field_value(struct bt_ctf_field *field, uint64_t value); + +struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class) +{ + int ret; + enum bt_ctf_validation_flag validation_flags = + BT_CTF_VALIDATION_FLAG_STREAM | + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_event *event = NULL; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_field_type *packet_header_type = NULL; + struct bt_ctf_field_type *packet_context_type = NULL; + struct bt_ctf_field_type *event_header_type = NULL; + struct bt_ctf_field_type *stream_event_ctx_type = NULL; + struct bt_ctf_field_type *event_context_type = NULL; + struct bt_ctf_field_type *event_payload_type = NULL; + struct bt_ctf_field *event_header = NULL; + struct bt_ctf_field *stream_event_context = NULL; + struct bt_ctf_field *event_context = NULL; + struct bt_ctf_field *event_payload = NULL; + struct bt_value *environment = NULL; + struct bt_ctf_validation_output validation_output = { 0 }; + int trace_valid = 0; + + if (!event_class) { + goto error; + } + + stream_class = bt_ctf_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) { + goto error; + } + + /* A stream class should always have an existing event header type */ + assert(stream_class->event_header_type); + + /* 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_ctf_stream_class_get_trace(stream_class); + if (trace) { + packet_header_type = bt_ctf_trace_get_packet_header_type(trace); + trace_valid = trace->valid; + assert(trace_valid); + environment = trace->environment; + } + + packet_context_type = bt_ctf_stream_class_get_packet_context_type( + stream_class); + event_header_type = bt_ctf_stream_class_get_event_header_type( + stream_class); + stream_event_ctx_type = bt_ctf_stream_class_get_event_context_type( + stream_class); + event_context_type = bt_ctf_event_class_get_context_type(event_class); + event_payload_type = bt_ctf_event_class_get_payload_type(event_class); + ret = bt_ctf_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. + */ + goto error; + } + + if ((validation_output.valid_flags & validation_flags) != + validation_flags) { + /* Invalid trace/stream class/event class */ + 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_ctf_event, 1); + if (!event) { + goto error; + } + + bt_object_init(event, bt_ctf_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, NULL, g_free); + event_header = + bt_ctf_field_create(validation_output.event_header_type); + if (!event_header) { + goto error; + } + + if (validation_output.stream_event_ctx_type) { + stream_event_context = bt_ctf_field_create( + validation_output.stream_event_ctx_type); + if (!stream_event_context) { + goto error; + } + } + + if (validation_output.event_context_type) { + event_context = bt_ctf_field_create( + validation_output.event_context_type); + if (!event_context) { + goto error; + } + } + + if (validation_output.event_payload_type) { + event_payload = bt_ctf_field_create( + validation_output.event_payload_type); + if (!event_payload) { + 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_ctf_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_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&validation_output); + + /* + * Freeze the stream class since the event header must not be changed + * anymore. + */ + bt_ctf_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); + + return event; + +error: + bt_ctf_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; +} + +struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event) +{ + struct bt_ctf_event_class *event_class = NULL; + + if (!event) { + goto end; + } + + event_class = event->event_class; + bt_get(event_class); +end: + return event_class; +} + +struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event) +{ + struct bt_ctf_stream *stream = NULL; + + if (!event) { + goto end; + } + + /* + * If the event has a parent, then this is its (writer) stream. + * If the event has no parent, then if it has a packet, this + * is its (non-writer) stream. + */ + if (event->base.parent) { + stream = (struct bt_ctf_stream *) bt_object_get_parent(event); + } else { + if (event->packet) { + stream = bt_get(event->packet->stream); + } + } + +end: + return stream; +} + +struct bt_ctf_clock *bt_ctf_event_get_clock(struct bt_ctf_event *event) +{ + struct bt_ctf_clock *clock = NULL; + struct bt_ctf_event_class *event_class; + struct bt_ctf_stream_class *stream_class; + + if (!event) { + goto end; + } + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + goto end; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + goto error_put_event_class; + } + + clock = bt_ctf_stream_class_get_clock(stream_class); + if (!clock) { + goto error_put_stream_class; + } + +error_put_stream_class: + bt_put(stream_class); +error_put_event_class: + bt_put(event_class); +end: + return clock; +} + +int bt_ctf_event_set_payload(struct bt_ctf_event *event, + const char *name, + struct bt_ctf_field *payload) +{ + int ret = 0; + + if (!event || !payload || event->frozen) { + ret = -1; + goto end; + } + + if (name) { + ret = bt_ctf_field_structure_set_field(event->fields_payload, + name, payload); + } else { + struct bt_ctf_field_type *payload_type; + + payload_type = bt_ctf_field_get_type(payload); + + if (bt_ctf_field_type_compare(payload_type, + event->event_class->fields) == 0) { + bt_put(event->fields_payload); + bt_get(payload); + event->fields_payload = payload; + } else { + ret = -1; + } + + bt_put(payload_type); + } +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_event_get_payload_field(struct bt_ctf_event *event) +{ + struct bt_ctf_field *payload = NULL; + + if (!event || !event->fields_payload) { + goto end; + } + + payload = event->fields_payload; + bt_get(payload); +end: + return payload; +} + +int bt_ctf_event_set_payload_field(struct bt_ctf_event *event, + struct bt_ctf_field *payload) +{ + int ret = 0; + struct bt_ctf_field_type *payload_type = NULL; + + if (!event || !payload || event->frozen) { + ret = -1; + goto end; + } + + payload_type = bt_ctf_field_get_type(payload); + if (!payload_type) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(payload_type) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + bt_get(payload); + bt_put(event->fields_payload); + event->fields_payload = payload; + +end: + bt_put(payload_type); + return ret; +} + +struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, + const char *name) +{ + struct bt_ctf_field *field = NULL; + + if (!event) { + goto end; + } + + if (name) { + field = bt_ctf_field_structure_get_field(event->fields_payload, + name); + } else { + field = event->fields_payload; + bt_get(field); + } +end: + return field; +} + +struct bt_ctf_field *bt_ctf_event_get_payload_by_index( + struct bt_ctf_event *event, int index) +{ + struct bt_ctf_field *field = NULL; + + if (!event || index < 0) { + goto end; + } + + field = bt_ctf_field_structure_get_field_by_index(event->fields_payload, + index); +end: + return field; +} + +struct bt_ctf_field *bt_ctf_event_get_header( + struct bt_ctf_event *event) +{ + struct bt_ctf_field *header = NULL; + + if (!event || !event->event_header) { + goto end; + } + + header = event->event_header; + bt_get(header); +end: + return header; +} + +int bt_ctf_event_set_header(struct bt_ctf_event *event, + struct bt_ctf_field *header) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + + if (!event || !header || event->frozen) { + ret = -1; + goto end; + } + + stream_class = (struct bt_ctf_stream_class *) bt_object_get_parent( + event->event_class); + /* + * Ensure the provided header's type matches the one registered to the + * stream class. + */ + field_type = bt_ctf_field_get_type(header); + if (bt_ctf_field_type_compare(field_type, + stream_class->event_header_type)) { + ret = -1; + goto end; + } + + bt_get(header); + bt_put(event->event_header); + event->event_header = header; +end: + bt_put(stream_class); + bt_put(field_type); + return ret; +} + +struct bt_ctf_field *bt_ctf_event_get_event_context( + struct bt_ctf_event *event) +{ + struct bt_ctf_field *context = NULL; + + if (!event || !event->context_payload) { + goto end; + } + + context = event->context_payload; + bt_get(context); +end: + return context; +} + +int bt_ctf_event_set_event_context(struct bt_ctf_event *event, + struct bt_ctf_field *context) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + + if (!event || !context || event->frozen) { + ret = -1; + goto end; + } + + field_type = bt_ctf_field_get_type(context); + if (bt_ctf_field_type_compare(field_type, + event->event_class->context)) { + ret = -1; + goto end; + } + + bt_get(context); + bt_put(event->context_payload); + event->context_payload = context; +end: + bt_put(field_type); + return ret; +} + +struct bt_ctf_field *bt_ctf_event_get_stream_event_context( + struct bt_ctf_event *event) +{ + struct bt_ctf_field *stream_event_context = NULL; + + if (!event || !event->stream_event_context) { + goto end; + } + + stream_event_context = event->stream_event_context; +end: + return bt_get(stream_event_context); +} + +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; +} + +void bt_ctf_event_get(struct bt_ctf_event *event) +{ + bt_get(event); +} + +void bt_ctf_event_put(struct bt_ctf_event *event) +{ + bt_put(event); +} + +void bt_ctf_event_destroy(struct bt_object *obj) +{ + struct bt_ctf_event *event; + + event = container_of(obj, struct bt_ctf_event, base); + if (!event->base.parent) { + /* + * Event was keeping a reference to its class since it shared no + * common ancestor with it to guarantee they would both have the + * same lifetime. + */ + bt_put(event->event_class); + } + g_hash_table_destroy(event->clock_values); + bt_put(event->event_header); + bt_put(event->stream_event_context); + bt_put(event->context_payload); + bt_put(event->fields_payload); + bt_put(event->packet); + g_free(event); +} + +static +int set_integer_field_value(struct bt_ctf_field* field, uint64_t value) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + + if (!field) { + ret = -1; + goto end; + } + + if (!bt_ctf_field_validate(field)) { + /* Payload already set, skip! (not an error) */ + goto end; + } + + field_type = bt_ctf_field_get_type(field); + assert(field_type); + + if (bt_ctf_field_type_get_type_id(field_type) != + BT_CTF_TYPE_ID_INTEGER) { + /* Not an integer and the value is unset, error. */ + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_get_signed(field_type)) { + ret = bt_ctf_field_signed_integer_set_value(field, (int64_t) value); + if (ret) { + /* Value is out of range, error. */ + goto end; + } + } else { + ret = bt_ctf_field_unsigned_integer_set_value(field, value); + if (ret) { + /* Value is out of range, error. */ + goto end; + } + } +end: + bt_put(field_type); + return ret; +} + +BT_HIDDEN +int bt_ctf_event_validate(struct bt_ctf_event *event) +{ + /* Make sure each field's payload has been set */ + int ret; + struct bt_ctf_stream_class *stream_class = NULL; + + assert(event); + ret = bt_ctf_field_validate(event->event_header); + if (ret) { + 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); + if (stream_class->event_context_type) { + ret = bt_ctf_field_validate(event->stream_event_context); + if (ret) { + goto end; + } + } + + ret = bt_ctf_field_validate(event->fields_payload); + if (ret) { + goto end; + } + + if (event->event_class->context) { + ret = bt_ctf_field_validate(event->context_payload); + } +end: + bt_put(stream_class); + return ret; +} + +BT_HIDDEN +int bt_ctf_event_serialize(struct bt_ctf_event *event, + struct ctf_stream_pos *pos) +{ + int ret = 0; + + assert(event); + assert(pos); + if (event->context_payload) { + ret = bt_ctf_field_serialize(event->context_payload, pos); + if (ret) { + goto end; + } + } + + if (event->fields_payload) { + ret = bt_ctf_field_serialize(event->fields_payload, pos); + if (ret) { + goto end; + } + } +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_event_populate_event_header(struct bt_ctf_event *event) +{ + int ret = 0; + struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL; + + if (!event || event->frozen) { + ret = -1; + goto end; + } + + id_field = bt_ctf_field_structure_get_field(event->event_header, "id"); + if (id_field) { + ret = set_integer_field_value(id_field, + (uint64_t) bt_ctf_event_class_get_id( + event->event_class)); + if (ret) { + goto end; + } + } + + timestamp_field = bt_ctf_field_structure_get_field(event->event_header, + "timestamp"); + if (timestamp_field) { + struct bt_ctf_field_type *timestamp_field_type = + bt_ctf_field_get_type(timestamp_field); + struct bt_ctf_clock *mapped_clock; + + assert(timestamp_field_type); + mapped_clock = bt_ctf_field_type_integer_get_mapped_clock( + timestamp_field_type); + bt_put(timestamp_field_type); + if (mapped_clock) { + int64_t timestamp; + + ret = bt_ctf_clock_get_time(mapped_clock, ×tamp); + bt_put(mapped_clock); + if (ret) { + goto end; + } + + ret = set_integer_field_value(timestamp_field, + timestamp); + if (ret) { + goto end; + } + } + } +end: + bt_put(id_field); + bt_put(timestamp_field); + return ret; +} + +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; +} + +BT_HIDDEN +void bt_ctf_event_freeze(struct bt_ctf_event *event) +{ + assert(event); + bt_ctf_packet_freeze(event->packet); + bt_ctf_field_freeze(event->event_header); + bt_ctf_field_freeze(event->stream_event_context); + bt_ctf_field_freeze(event->context_payload); + bt_ctf_field_freeze(event->fields_payload); + event->frozen = 1; +} + +static +void insert_stream_clock_value_into_event_clock_values(gpointer key, + gpointer value, + gpointer data) +{ + struct bt_ctf_event *event = data; + uint64_t *clock_value; + + assert(event); + + /* Copy clock value because it belongs to the hash table */ + clock_value = g_new0(uint64_t, 1); + *clock_value = *((uint64_t *) value); + + /* Insert copy into event clock values */ + g_hash_table_insert(event->clock_values, key, clock_value); +} + +BT_HIDDEN +int bt_ctf_event_register_stream_clock_values(struct bt_ctf_event *event) +{ + int ret = 0; + struct bt_ctf_stream *stream; + + stream = bt_ctf_event_get_stream(event); + assert(stream); + g_hash_table_remove_all(event->clock_values); + g_hash_table_foreach(stream->clock_values, + insert_stream_clock_value_into_event_clock_values, event); + BT_PUT(stream); + + return ret; +} + +uint64_t bt_ctf_event_get_clock_value(struct bt_ctf_event *event, + struct bt_ctf_clock *clock) +{ + uint64_t ret = -1ULL; + uint64_t *clock_value; + + if (!event || !clock) { + goto end; + } + + clock_value = g_hash_table_lookup(event->clock_values, clock); + if (!clock_value) { + goto end; + } + + ret = *clock_value; + +end: + return ret; +} diff --git a/formats/ctf/ir/field-path.c b/formats/ctf/ir/field-path.c new file mode 100644 index 00000000..d7eabf3e --- /dev/null +++ b/formats/ctf/ir/field-path.c @@ -0,0 +1,147 @@ +/* + * field-path.c + * + * Babeltrace CTF IR - Field path + * + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +static +void field_path_destroy(struct bt_object *obj) +{ + struct bt_ctf_field_path *field_path = (struct bt_ctf_field_path *) obj; + + if (!field_path) { + return; + } + + if (field_path->indexes) { + g_array_free(field_path->indexes, TRUE); + } + g_free(field_path); +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_create(void) +{ + struct bt_ctf_field_path *field_path = NULL; + + field_path = g_new0(struct bt_ctf_field_path, 1); + if (!field_path) { + goto error; + } + + bt_object_init(field_path, field_path_destroy); + field_path->root = BT_CTF_SCOPE_UNKNOWN; + field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int)); + if (!field_path->indexes) { + goto error; + } + + return field_path; + +error: + BT_PUT(field_path); + return NULL; +} + +BT_HIDDEN +void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path) +{ + if (field_path->indexes->len > 0) { + g_array_remove_range(field_path->indexes, 0, + field_path->indexes->len); + } +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_copy( + struct bt_ctf_field_path *path) +{ + struct bt_ctf_field_path *new_path = bt_ctf_field_path_create(); + + if (!new_path) { + goto end; + } + + new_path->root = path->root; + g_array_insert_vals(new_path->indexes, 0, + path->indexes->data, path->indexes->len); +end: + return new_path; +} + +enum bt_ctf_scope bt_ctf_field_path_get_root_scope( + const struct bt_ctf_field_path *field_path) +{ + enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN; + + if (!field_path) { + goto end; + } + + scope = field_path->root; + +end: + return scope; +} + +int bt_ctf_field_path_get_index_count( + const struct bt_ctf_field_path *field_path) +{ + int ret = -1; + + if (!field_path) { + goto end; + } + + ret = field_path->indexes->len; + +end: + return ret; +} + +int bt_ctf_field_path_get_index(const struct bt_ctf_field_path *field_path, + int index) +{ + int ret = INT_MIN; + + if (!field_path || index < 0) { + goto end; + } + + if (index >= field_path->indexes->len) { + goto end; + } + + ret = g_array_index(field_path->indexes, int, index); + +end: + return ret; +} diff --git a/formats/ctf/ir/field-types.c b/formats/ctf/ir/field-types.c new file mode 100644 index 00000000..f898d5af --- /dev/null +++ b/formats/ctf/ir/field-types.c @@ -0,0 +1,4143 @@ +/* + * field-types.c + * + * Babeltrace CTF IR - Event Types + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct range_overlap_query { + union { + uint64_t _unsigned; + int64_t _signed; + } range_start; + + union { + uint64_t _unsigned; + int64_t _signed; + } range_end; + int overlaps; + GQuark mapping_name; +}; + +static +void bt_ctf_field_type_destroy(struct bt_object *); +static +void bt_ctf_field_type_integer_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_structure_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_variant_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_array_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_sequence_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_string_destroy(struct bt_ctf_field_type *); + +static +void (* const type_destroy_funcs[])(struct bt_ctf_field_type *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_destroy, + [BT_CTF_TYPE_ID_ENUM] = + bt_ctf_field_type_enumeration_destroy, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_type_floating_point_destroy, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_type_structure_destroy, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_destroy, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_destroy, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_destroy, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_type_string_destroy, +}; + +static +void generic_field_type_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_integer_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *); + +static +type_freeze_func const type_freeze_funcs[] = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_freeze, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_type_enumeration_freeze, + [BT_CTF_TYPE_ID_FLOAT] = generic_field_type_freeze, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_type_structure_freeze, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_freeze, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_freeze, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_freeze, + [BT_CTF_TYPE_ID_STRING] = generic_field_type_freeze, +}; + +static +int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_floating_point_serialize( + struct bt_ctf_field_type *, struct metadata_context *); +static +int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *, + struct metadata_context *); +static +int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *, + struct metadata_context *); + +static +type_serialize_func const type_serialize_funcs[] = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_serialize, + [BT_CTF_TYPE_ID_ENUM] = + bt_ctf_field_type_enumeration_serialize, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_type_floating_point_serialize, + [BT_CTF_TYPE_ID_STRUCT] = + bt_ctf_field_type_structure_serialize, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_serialize, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_serialize, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_serialize, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_type_string_serialize, +}; + +static +void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_enumeration_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_floating_point_set_byte_order( + struct bt_ctf_field_type *, int byte_order, int set_native); +static +void bt_ctf_field_type_structure_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_variant_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_array_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_sequence_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); + +/* The set_native flag only set the byte order if it is set to native */ +static +void (* const set_byte_order_funcs[])(struct bt_ctf_field_type *, + int byte_order, int set_native) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_set_byte_order, + [BT_CTF_TYPE_ID_ENUM] = + bt_ctf_field_type_enumeration_set_byte_order, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_type_floating_point_set_byte_order, + [BT_CTF_TYPE_ID_STRUCT] = + bt_ctf_field_type_structure_set_byte_order, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_set_byte_order, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_set_byte_order, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_set_byte_order, + [BT_CTF_TYPE_ID_STRING] = NULL, +}; + +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy( + struct bt_ctf_field_type *); + +static +struct bt_ctf_field_type *(* const type_copy_funcs[])( + struct bt_ctf_field_type *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_copy, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_type_enumeration_copy, + [BT_CTF_TYPE_ID_FLOAT] = bt_ctf_field_type_floating_point_copy, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_type_structure_copy, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_copy, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_copy, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_copy, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_type_string_copy, +}; + +static +int bt_ctf_field_type_integer_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_floating_point_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_enumeration_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_string_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_structure_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_variant_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_array_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_sequence_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); + +static +int (* const type_compare_funcs[])(struct bt_ctf_field_type *, + struct bt_ctf_field_type *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_compare, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_type_enumeration_compare, + [BT_CTF_TYPE_ID_FLOAT] = bt_ctf_field_type_floating_point_compare, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_type_structure_compare, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_compare, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_compare, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_compare, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_type_string_compare, +}; + +static +int bt_ctf_field_type_integer_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_enumeration_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_structure_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_array_validate(struct bt_ctf_field_type *); +static +int bt_ctf_field_type_sequence_validate(struct bt_ctf_field_type *); + +static +int (* const type_validate_funcs[])(struct bt_ctf_field_type *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_type_integer_validate, + [BT_CTF_TYPE_ID_FLOAT] = NULL, + [BT_CTF_TYPE_ID_STRING] = NULL, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_type_enumeration_validate, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_type_structure_validate, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_type_variant_validate, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_type_array_validate, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_type_sequence_validate, +}; + +static +void destroy_enumeration_mapping(struct enumeration_mapping *mapping) +{ + g_free(mapping); +} + +static +void destroy_structure_field(struct structure_field *field) +{ + bt_put(field->type); + g_free(field); +} + +static +void check_ranges_overlap(gpointer element, gpointer query) +{ + struct enumeration_mapping *mapping = element; + struct range_overlap_query *overlap_query = query; + + if (mapping->range_start._signed <= overlap_query->range_end._signed + && overlap_query->range_start._signed <= + mapping->range_end._signed) { + overlap_query->overlaps = 1; + overlap_query->mapping_name = mapping->string; + } + + overlap_query->overlaps |= + mapping->string == overlap_query->mapping_name; +} + +static +void check_ranges_overlap_unsigned(gpointer element, gpointer query) +{ + struct enumeration_mapping *mapping = element; + struct range_overlap_query *overlap_query = query; + + if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned + && overlap_query->range_start._unsigned <= + mapping->range_end._unsigned) { + overlap_query->overlaps = 1; + overlap_query->mapping_name = mapping->string; + } + + overlap_query->overlaps |= + mapping->string == overlap_query->mapping_name; +} + +static +gint compare_enumeration_mappings_signed(struct enumeration_mapping **a, + struct enumeration_mapping **b) +{ + return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1; +} + +static +gint compare_enumeration_mappings_unsigned(struct enumeration_mapping **a, + struct enumeration_mapping **b) +{ + return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1; +} + +static +void bt_ctf_field_type_init(struct bt_ctf_field_type *type, int init_bo) +{ + enum bt_ctf_type_id type_id = type->declaration->id; + + assert(type && (type_id > BT_CTF_TYPE_ID_UNKNOWN) && + (type_id < BT_CTF_NR_TYPE_IDS)); + + bt_object_init(type, bt_ctf_field_type_destroy); + type->freeze = type_freeze_funcs[type_id]; + type->serialize = type_serialize_funcs[type_id]; + + if (init_bo) { + int ret = bt_ctf_field_type_set_byte_order(type, + BT_CTF_BYTE_ORDER_NATIVE); + assert(!ret); + } + + type->declaration->alignment = 1; +} + +static +int add_structure_field(GPtrArray *fields, + GHashTable *field_name_to_index, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + int ret = 0; + GQuark name_quark = g_quark_from_string(field_name); + struct structure_field *field; + + /* Make sure structure does not contain a field of the same name */ + if (g_hash_table_lookup_extended(field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, NULL)) { + ret = -1; + goto end; + } + + field = g_new0(struct structure_field, 1); + if (!field) { + ret = -1; + goto end; + } + + bt_get(field_type); + field->name = name_quark; + field->type = field_type; + g_hash_table_insert(field_name_to_index, + (gpointer) (unsigned long) name_quark, + (gpointer) (unsigned long) fields->len); + g_ptr_array_add(fields, field); +end: + return ret; +} + +static +void bt_ctf_field_type_destroy(struct bt_object *obj) +{ + struct bt_ctf_field_type *type; + enum bt_ctf_type_id type_id; + + type = container_of(obj, struct bt_ctf_field_type, base); + type_id = type->declaration->id; + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || + type_id >= BT_CTF_NR_TYPE_IDS) { + return; + } + + type_destroy_funcs[type_id](type); +} + +static +int bt_ctf_field_type_integer_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + + struct bt_ctf_field_type_integer *integer = + container_of(type, struct bt_ctf_field_type_integer, + parent); + + if (integer->mapped_clock && integer->declaration.signedness) { + ret = -1; + goto end; + } + +end: + return ret; +} + +static +int bt_ctf_field_type_enumeration_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + + struct bt_ctf_field_type_enumeration *enumeration = + container_of(type, struct bt_ctf_field_type_enumeration, + parent); + struct bt_ctf_field_type *container_type = + bt_ctf_field_type_enumeration_get_container_type(type); + + if (!container_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_validate(container_type); + if (ret) { + goto end; + } + + /* Ensure enum has entries */ + ret = enumeration->entries->len ? 0 : -1; + +end: + BT_PUT(container_type); + return ret; +} + +static +int bt_ctf_field_type_sequence_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *element_type = NULL; + struct bt_ctf_field_type_sequence *sequence = + container_of(type, struct bt_ctf_field_type_sequence, + parent); + + /* Length field name should be set at this point */ + if (sequence->length_field_name->len == 0) { + ret = -1; + goto end; + } + + element_type = bt_ctf_field_type_sequence_get_element_type(type); + if (!element_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_validate(element_type); + +end: + BT_PUT(element_type); + + return ret; +} + +static +int bt_ctf_field_type_array_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *element_type = NULL; + + element_type = bt_ctf_field_type_array_get_element_type(type); + if (!element_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_validate(element_type); + +end: + BT_PUT(element_type); + + return ret; +} + +static +int bt_ctf_field_type_structure_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type *child_type = NULL; + int field_count = bt_ctf_field_type_structure_get_field_count(type); + int i; + + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + ret = bt_ctf_field_type_structure_get_field(type, + NULL, &child_type, i); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_validate(child_type); + if (ret) { + goto end; + } + + BT_PUT(child_type); + } + +end: + BT_PUT(child_type); + + return ret; +} + +static +int bt_ctf_field_type_variant_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + int field_count; + struct bt_ctf_field_type *child_type = NULL; + struct bt_ctf_field_type_variant *variant = + container_of(type, struct bt_ctf_field_type_variant, + parent); + int i; + int tag_mappings_count; + + if (variant->tag_name->len == 0 || !variant->tag) { + ret = -1; + goto end; + } + + tag_mappings_count = + bt_ctf_field_type_enumeration_get_mapping_count( + (struct bt_ctf_field_type *) variant->tag); + + if (tag_mappings_count != variant->fields->len) { + ret = -1; + goto end; + } + + for (i = 0; i < tag_mappings_count; ++i) { + const char *label; + int64_t range_start, range_end; + struct bt_ctf_field_type *ft; + + ret = bt_ctf_field_type_enumeration_get_mapping( + (struct bt_ctf_field_type *) variant->tag, + i, &label, &range_start, &range_end); + if (ret) { + goto end; + } + if (!label) { + ret = -1; + goto end; + } + + ft = bt_ctf_field_type_variant_get_field_type_by_name( + type, label); + if (!ft) { + ret = -1; + goto end; + } + + BT_PUT(ft); + } + + field_count = bt_ctf_field_type_variant_get_field_count(type); + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + ret = bt_ctf_field_type_variant_get_field(type, + NULL, &child_type, i); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_validate(child_type); + if (ret) { + goto end; + } + + BT_PUT(child_type); + } + +end: + BT_PUT(child_type); + + return ret; +} + +/* + * This function validates a given field type without considering + * where this field type is located. It only validates the properties + * of the given field type and the properties of its children if + * applicable. + */ +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + enum bt_ctf_type_id id = bt_ctf_field_type_get_type_id(type); + + if (!type) { + ret = -1; + goto end; + } + + if (type->valid) { + /* Already marked as valid */ + goto end; + } + + if (type_validate_funcs[id]) { + ret = type_validate_funcs[id](type); + } + + if (!ret && type->frozen) { + /* Field type is valid */ + type->valid = 1; + } + +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) +{ + struct bt_ctf_field_type_integer *integer = + g_new0(struct bt_ctf_field_type_integer, 1); + + if (!integer || size == 0 || size > 64) { + return NULL; + } + + integer->parent.declaration = &integer->declaration.p; + integer->parent.declaration->id = BT_CTF_TYPE_ID_INTEGER; + integer->declaration.len = size; + integer->declaration.base = BT_CTF_INTEGER_BASE_DECIMAL; + integer->declaration.encoding = BT_CTF_STRING_ENCODING_NONE; + bt_ctf_field_type_init(&integer->parent, TRUE); + return &integer->parent; +} + +int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = (int) integer->declaration.len; +end: + return ret; +} + +int bt_ctf_field_type_integer_get_signed(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.signedness; +end: + return ret; +} + +int bt_ctf_field_type_integer_set_signed(struct bt_ctf_field_type *type, + int is_signed) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->frozen || + type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + integer->declaration.signedness = !!is_signed; +end: + return ret; +} + +enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base( + struct bt_ctf_field_type *type) +{ + enum bt_ctf_integer_base ret = BT_CTF_INTEGER_BASE_UNKNOWN; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.base; +end: + return ret; +} + +int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *type, + enum bt_ctf_integer_base base) +{ + int ret = 0; + + if (!type || type->frozen || + type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + switch (base) { + case BT_CTF_INTEGER_BASE_BINARY: + case BT_CTF_INTEGER_BASE_OCTAL: + case BT_CTF_INTEGER_BASE_DECIMAL: + case BT_CTF_INTEGER_BASE_HEXADECIMAL: + { + struct bt_ctf_field_type_integer *integer = container_of(type, + struct bt_ctf_field_type_integer, parent); + integer->declaration.base = base; + break; + } + default: + ret = -1; + } +end: + return ret; +} + +enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding( + struct bt_ctf_field_type *type) +{ + enum bt_ctf_string_encoding ret = BT_CTF_STRING_ENCODING_UNKNOWN; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.encoding; +end: + return ret; +} + +int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *type, + enum bt_ctf_string_encoding encoding) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->frozen || + (type->declaration->id != BT_CTF_TYPE_ID_INTEGER) || + (encoding < BT_CTF_STRING_ENCODING_NONE) || + (encoding >= BT_CTF_STRING_ENCODING_UNKNOWN)) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + integer->declaration.encoding = encoding; +end: + return ret; +} + +struct bt_ctf_clock *bt_ctf_field_type_integer_get_mapped_clock( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_integer *integer; + struct bt_ctf_clock *clock = NULL; + + if (!type) { + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + clock = integer->mapped_clock; + bt_get(clock); +end: + return clock; +} + +int bt_ctf_field_type_integer_set_mapped_clock( + struct bt_ctf_field_type *type, + struct bt_ctf_clock *clock) +{ + struct bt_ctf_field_type_integer *integer; + int ret = 0; + + if (!type || type->frozen) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + bt_put(integer->mapped_clock); + bt_get(clock); + integer->mapped_clock = clock; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( + struct bt_ctf_field_type *integer_container_type) +{ + struct bt_ctf_field_type_enumeration *enumeration = NULL; + + if (!integer_container_type) { + goto error; + } + + if (integer_container_type->declaration->id != BT_CTF_TYPE_ID_INTEGER) { + goto error; + } + + enumeration = g_new0(struct bt_ctf_field_type_enumeration, 1); + if (!enumeration) { + goto error; + } + + enumeration->parent.declaration = &enumeration->declaration.p; + enumeration->parent.declaration->id = BT_CTF_TYPE_ID_ENUM; + bt_get(integer_container_type); + enumeration->container = integer_container_type; + enumeration->entries = g_ptr_array_new_with_free_func( + (GDestroyNotify)destroy_enumeration_mapping); + bt_ctf_field_type_init(&enumeration->parent, FALSE); + return &enumeration->parent; +error: + g_free(enumeration); + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *container_type = NULL; + struct bt_ctf_field_type_enumeration *enumeration_type; + + if (!type) { + goto end; + } + + if (type->declaration->id != BT_CTF_TYPE_ID_ENUM) { + goto end; + } + + enumeration_type = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + container_type = enumeration_type->container; + bt_get(container_type); +end: + return container_type; +} + +int bt_ctf_field_type_enumeration_add_mapping( + struct bt_ctf_field_type *type, const char *string, + int64_t range_start, int64_t range_end) +{ + int ret = 0; + GQuark mapping_name; + struct enumeration_mapping *mapping; + struct bt_ctf_field_type_enumeration *enumeration; + struct range_overlap_query query; + char *escaped_string; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ENUM) || + type->frozen || + (range_end < range_start)) { + ret = -1; + goto end; + } + + if (!string || strlen(string) == 0) { + ret = -1; + goto end; + } + + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { + ret = -1; + goto end; + } + + mapping_name = g_quark_from_string(escaped_string); + query = (struct range_overlap_query) { + .range_start._signed = range_start, + .range_end._signed = range_end, + .mapping_name = mapping_name, + .overlaps = 0 }; + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + + /* Check that the range does not overlap with one already present */ + g_ptr_array_foreach(enumeration->entries, check_ranges_overlap, &query); + if (query.overlaps) { + ret = -1; + goto error_free; + } + + mapping = g_new(struct enumeration_mapping, 1); + if (!mapping) { + ret = -1; + goto error_free; + } + + *mapping = (struct enumeration_mapping) { + .range_start._signed = range_start, + .range_end._signed = range_end, .string = mapping_name}; + g_ptr_array_add(enumeration->entries, mapping); + g_ptr_array_sort(enumeration->entries, + (GCompareFunc)compare_enumeration_mappings_signed); +error_free: + free(escaped_string); +end: + return ret; +} + +int bt_ctf_field_type_enumeration_add_mapping_unsigned( + struct bt_ctf_field_type *type, const char *string, + uint64_t range_start, uint64_t range_end) +{ + int ret = 0; + GQuark mapping_name; + struct enumeration_mapping *mapping; + struct bt_ctf_field_type_enumeration *enumeration; + struct range_overlap_query query; + char *escaped_string; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ENUM) || + type->frozen || + (range_end < range_start)) { + ret = -1; + goto end; + } + + if (!string || strlen(string) == 0) { + ret = -1; + goto end; + } + + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { + ret = -1; + goto end; + } + + mapping_name = g_quark_from_string(escaped_string); + query = (struct range_overlap_query) { + .range_start._unsigned = range_start, + .range_end._unsigned = range_end, + .mapping_name = mapping_name, + .overlaps = 0 }; + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + + /* Check that the range does not overlap with one already present */ + g_ptr_array_foreach(enumeration->entries, check_ranges_overlap_unsigned, + &query); + if (query.overlaps) { + ret = -1; + goto error_free; + } + + mapping = g_new(struct enumeration_mapping, 1); + if (!mapping) { + ret = -1; + goto error_free; + } + + *mapping = (struct enumeration_mapping) { + .range_start._unsigned = range_start, + .range_end._unsigned = range_end, .string = mapping_name}; + g_ptr_array_add(enumeration->entries, mapping); + g_ptr_array_sort(enumeration->entries, + (GCompareFunc)compare_enumeration_mappings_unsigned); +error_free: + free(escaped_string); +end: + return ret; +} + +const char *bt_ctf_field_type_enumeration_get_mapping_name_unsigned( + struct bt_ctf_field_type_enumeration *enumeration_type, + uint64_t value) +{ + const char *name = NULL; + struct range_overlap_query query = + (struct range_overlap_query) { + .range_start._unsigned = value, + .range_end._unsigned = value, + .overlaps = 0 }; + + g_ptr_array_foreach(enumeration_type->entries, + check_ranges_overlap_unsigned, + &query); + if (!query.overlaps) { + goto end; + } + + name = g_quark_to_string(query.mapping_name); +end: + return name; +} + +const char *bt_ctf_field_type_enumeration_get_mapping_name_signed( + struct bt_ctf_field_type_enumeration *enumeration_type, + int64_t value) +{ + const char *name = NULL; + struct range_overlap_query query = + (struct range_overlap_query) { + .range_start._signed = value, + .range_end._signed = value, + .overlaps = 0 }; + + g_ptr_array_foreach(enumeration_type->entries, check_ranges_overlap, + &query); + if (!query.overlaps) { + goto end; + } + + name = g_quark_to_string(query.mapping_name); +end: + return name; +} + +int bt_ctf_field_type_enumeration_get_mapping_count( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_enumeration *enumeration; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + ret = (int) enumeration->entries->len; +end: + return ret; +} + +static inline +struct enumeration_mapping *get_enumeration_mapping( + struct bt_ctf_field_type *type, int index) +{ + struct enumeration_mapping *mapping = NULL; + struct bt_ctf_field_type_enumeration *enumeration; + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + if (index >= enumeration->entries->len) { + goto end; + } + + mapping = g_ptr_array_index(enumeration->entries, index); +end: + return mapping; +} + +int bt_ctf_field_type_enumeration_get_mapping( + struct bt_ctf_field_type *type, int index, + const char **string, int64_t *range_start, int64_t *range_end) +{ + struct enumeration_mapping *mapping; + int ret = 0; + + if (!type || index < 0 || !string || !range_start || !range_end || + (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + mapping = get_enumeration_mapping(type, index); + if (!mapping) { + ret = -1; + goto end; + } + + *string = g_quark_to_string(mapping->string); + *range_start = mapping->range_start._signed; + *range_end = mapping->range_end._signed; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_unsigned( + struct bt_ctf_field_type *type, int index, + const char **string, uint64_t *range_start, uint64_t *range_end) +{ + struct enumeration_mapping *mapping; + int ret = 0; + + if (!type || index < 0 || !string || !range_start || !range_end || + (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + mapping = get_enumeration_mapping(type, index); + if (!mapping) { + ret = -1; + goto end; + } + + *string = g_quark_to_string(mapping->string); + *range_start = mapping->range_start._unsigned; + *range_end = mapping->range_end._unsigned; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_name( + struct bt_ctf_field_type *type, const char *name) +{ + GQuark name_quark; + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || !name || + (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (mapping->string == name_quark) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_value( + struct bt_ctf_field_type *type, int64_t value) +{ + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (value >= mapping->range_start._signed && + value <= mapping->range_end._signed) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value( + struct bt_ctf_field_type *type, uint64_t value) +{ + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (value >= mapping->range_start._unsigned && + value <= mapping->range_end._unsigned) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) +{ + struct bt_ctf_field_type_floating_point *floating_point = + g_new0(struct bt_ctf_field_type_floating_point, 1); + + if (!floating_point) { + goto end; + } + + floating_point->declaration.sign = &floating_point->sign; + floating_point->declaration.mantissa = &floating_point->mantissa; + floating_point->declaration.exp = &floating_point->exp; + floating_point->sign.len = 1; + floating_point->parent.declaration = &floating_point->declaration.p; + floating_point->parent.declaration->id = BT_CTF_TYPE_ID_FLOAT; + floating_point->declaration.exp->len = + sizeof(float) * CHAR_BIT - FLT_MANT_DIG; + floating_point->declaration.mantissa->len = FLT_MANT_DIG - 1; + floating_point->sign.p.alignment = 1; + floating_point->mantissa.p.alignment = 1; + floating_point->exp.p.alignment = 1; + + bt_ctf_field_type_init(&floating_point->parent, TRUE); +end: + return floating_point ? &floating_point->parent : NULL; +} + +int bt_ctf_field_type_floating_point_get_exponent_digits( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + ret = (int) floating_point->declaration.exp->len; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_set_exponent_digits( + struct bt_ctf_field_type *type, + unsigned int exponent_digits) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || type->frozen || + (type->declaration->id != BT_CTF_TYPE_ID_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && + (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && + (exponent_digits != + sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { + ret = -1; + goto end; + } + + floating_point->declaration.exp->len = exponent_digits; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_get_mantissa_digits( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + ret = (int) floating_point->mantissa.len + 1; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_set_mantissa_digits( + struct bt_ctf_field_type *type, + unsigned int mantissa_digits) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || type->frozen || + (type->declaration->id != BT_CTF_TYPE_ID_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + + if ((mantissa_digits != FLT_MANT_DIG) && + (mantissa_digits != DBL_MANT_DIG) && + (mantissa_digits != LDBL_MANT_DIG)) { + ret = -1; + goto end; + } + + floating_point->declaration.mantissa->len = mantissa_digits - 1; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) +{ + struct bt_ctf_field_type_structure *structure = + g_new0(struct bt_ctf_field_type_structure, 1); + + if (!structure) { + goto error; + } + + structure->parent.declaration = &structure->declaration.p; + structure->parent.declaration->id = BT_CTF_TYPE_ID_STRUCT; + structure->fields = g_ptr_array_new_with_free_func( + (GDestroyNotify)destroy_structure_field); + structure->field_name_to_index = g_hash_table_new(NULL, NULL); + bt_ctf_field_type_init(&structure->parent, TRUE); + return &structure->parent; +error: + return NULL; +} + +int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + int ret = 0; + struct bt_ctf_field_type_structure *structure; + + if (!type || !field_type || type->frozen || + bt_ctf_validate_identifier(field_name) || + (type->declaration->id != BT_CTF_TYPE_ID_STRUCT)) { + ret = -1; + goto end; + } + + structure = container_of(type, + struct bt_ctf_field_type_structure, parent); + if (add_structure_field(structure->fields, + structure->field_name_to_index, field_type, field_name)) { + ret = -1; + goto end; + } +end: + return ret; +} + +int bt_ctf_field_type_structure_get_field_count( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_structure *structure; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_STRUCT)) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + ret = (int) structure->fields->len; +end: + return ret; +} + +int bt_ctf_field_type_structure_get_field(struct bt_ctf_field_type *type, + const char **field_name, struct bt_ctf_field_type **field_type, + int index) +{ + struct bt_ctf_field_type_structure *structure; + struct structure_field *field; + int ret = 0; + + if (!type || index < 0 || + (type->declaration->id != BT_CTF_TYPE_ID_STRUCT)) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (index >= structure->fields->len) { + ret = -1; + goto end; + } + + field = g_ptr_array_index(structure->fields, index); + if (field_type) { + *field_type = field->type; + bt_get(field->type); + } + if (field_name) { + *field_name = g_quark_to_string(field->name); + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name( + struct bt_ctf_field_type *type, + const char *name) +{ + size_t index; + GQuark name_quark; + struct structure_field *field; + struct bt_ctf_field_type_structure *structure; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !name) { + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + goto end; + } + + field = structure->fields->pdata[index]; + field_type = field->type; + bt_get(field_type); +end: + return field_type; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_create( + struct bt_ctf_field_type *enum_tag, const char *tag_name) +{ + struct bt_ctf_field_type_variant *variant = NULL; + + if (tag_name && bt_ctf_validate_identifier(tag_name)) { + goto error; + } + + variant = g_new0(struct bt_ctf_field_type_variant, 1); + if (!variant) { + goto error; + } + + variant->parent.declaration = &variant->declaration.p; + variant->parent.declaration->id = BT_CTF_TYPE_ID_VARIANT; + variant->tag_name = g_string_new(tag_name); + variant->field_name_to_index = g_hash_table_new(NULL, NULL); + variant->fields = g_ptr_array_new_with_free_func( + (GDestroyNotify) destroy_structure_field); + if (enum_tag) { + bt_get(enum_tag); + variant->tag = container_of(enum_tag, + struct bt_ctf_field_type_enumeration, parent); + } + + bt_ctf_field_type_init(&variant->parent, TRUE); + /* A variant's alignment is undefined */ + variant->parent.declaration->alignment = 0; + return &variant->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant; + struct bt_ctf_field_type *tag_type = NULL; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_VARIANT)) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (!variant->tag) { + goto end; + } + + tag_type = &variant->tag->parent; + bt_get(tag_type); +end: + return tag_type; +} + +const char *bt_ctf_field_type_variant_get_tag_name( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant; + const char *tag_name = NULL; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_VARIANT)) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (variant->tag_name->len == 0) { + goto end; + } + + tag_name = variant->tag_name->str; +end: + return tag_name; +} + +int bt_ctf_field_type_variant_set_tag_name( + struct bt_ctf_field_type *type, const char *name) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || type->frozen || + (type->declaration->id != BT_CTF_TYPE_ID_VARIANT) || + bt_ctf_validate_identifier(name)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + g_string_assign(variant->tag_name, name); +end: + return ret; +} + +int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_type_variant *variant; + GQuark field_name_quark = g_quark_from_string(field_name); + + if (!type || !field_type || type->frozen || + bt_ctf_validate_identifier(field_name) || + (type->declaration->id != BT_CTF_TYPE_ID_VARIANT)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + + /* The user has explicitly provided a tag; validate against it. */ + if (variant->tag) { + int name_found = 0; + + /* Make sure this name is present in the enum tag */ + for (i = 0; i < variant->tag->entries->len; i++) { + struct enumeration_mapping *mapping = + g_ptr_array_index(variant->tag->entries, i); + + if (mapping->string == field_name_quark) { + name_found = 1; + break; + } + } + + if (!name_found) { + /* Validation failed */ + ret = -1; + goto end; + } + } + + if (add_structure_field(variant->fields, variant->field_name_to_index, + field_type, field_name)) { + ret = -1; + goto end; + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name( + struct bt_ctf_field_type *type, + const char *field_name) +{ + size_t index; + GQuark name_quark; + struct structure_field *field; + struct bt_ctf_field_type_variant *variant; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !field_name) { + goto end; + } + + name_quark = g_quark_try_string(field_name); + if (!name_quark) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + goto end; + } + + field = g_ptr_array_index(variant->fields, index); + field_type = field->type; + bt_get(field_type); +end: + return field_type; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag( + struct bt_ctf_field_type *type, + struct bt_ctf_field *tag) +{ + const char *enum_value; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !tag || type->declaration->id != BT_CTF_TYPE_ID_VARIANT) { + goto end; + } + + enum_value = bt_ctf_field_enumeration_get_mapping_name(tag); + if (!enum_value) { + goto end; + } + + /* Already increments field_type's reference count */ + field_type = bt_ctf_field_type_variant_get_field_type_by_name( + type, enum_value); +end: + return field_type; +} + +int bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_VARIANT)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + ret = (int) variant->fields->len; +end: + return ret; + +} + +int bt_ctf_field_type_variant_get_field(struct bt_ctf_field_type *type, + const char **field_name, struct bt_ctf_field_type **field_type, + int index) +{ + struct bt_ctf_field_type_variant *variant; + struct structure_field *field; + int ret = 0; + + if (!type || index < 0 || + (type->declaration->id != BT_CTF_TYPE_ID_VARIANT)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (index >= variant->fields->len) { + ret = -1; + goto end; + } + + field = g_ptr_array_index(variant->fields, index); + if (field_type) { + *field_type = field->type; + bt_get(field->type); + } + if (field_name) { + *field_name = g_quark_to_string(field->name); + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_create( + struct bt_ctf_field_type *element_type, + unsigned int length) +{ + struct bt_ctf_field_type_array *array = NULL; + + if (!element_type || length == 0) { + goto error; + } + + array = g_new0(struct bt_ctf_field_type_array, 1); + if (!array) { + goto error; + } + + array->parent.declaration = &array->declaration.p; + array->parent.declaration->id = BT_CTF_TYPE_ID_ARRAY; + + bt_get(element_type); + array->element_type = element_type; + array->length = length; + bt_ctf_field_type_init(&array->parent, FALSE); + return &array->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *ret = NULL; + struct bt_ctf_field_type_array *array; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ARRAY)) { + goto end; + } + + array = container_of(type, struct bt_ctf_field_type_array, parent); + ret = array->element_type; + bt_get(ret); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_array_set_element_type(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *element_type) +{ + int ret = 0; + struct bt_ctf_field_type_array *array; + + if (!type || !element_type || + (type->declaration->id != BT_CTF_TYPE_ID_ARRAY)) { + ret = -1; + goto end; + } + + array = container_of(type, struct bt_ctf_field_type_array, parent); + + if (array->element_type) { + BT_PUT(array->element_type); + } + + array->element_type = element_type; + bt_get(array->element_type); + +end: + return ret; +} + +int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *type) +{ + int64_t ret; + struct bt_ctf_field_type_array *array; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_ARRAY)) { + ret = -1; + goto end; + } + + array = container_of(type, struct bt_ctf_field_type_array, parent); + ret = (int64_t) array->length; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( + struct bt_ctf_field_type *element_type, + const char *length_field_name) +{ + struct bt_ctf_field_type_sequence *sequence = NULL; + + if (!element_type || bt_ctf_validate_identifier(length_field_name)) { + goto error; + } + + sequence = g_new0(struct bt_ctf_field_type_sequence, 1); + if (!sequence) { + goto error; + } + + sequence->parent.declaration = &sequence->declaration.p; + sequence->parent.declaration->id = BT_CTF_TYPE_ID_SEQUENCE; + bt_get(element_type); + sequence->element_type = element_type; + sequence->length_field_name = g_string_new(length_field_name); + bt_ctf_field_type_init(&sequence->parent, FALSE); + return &sequence->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *ret = NULL; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_SEQUENCE)) { + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + ret = sequence->element_type; + bt_get(ret); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_sequence_set_element_type(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *element_type) +{ + int ret = 0; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || !element_type || + (type->declaration->id != BT_CTF_TYPE_ID_SEQUENCE)) { + ret = -1; + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, parent); + + if (sequence->element_type) { + BT_PUT(sequence->element_type); + } + + sequence->element_type = element_type; + bt_get(sequence->element_type); + +end: + return ret; +} + +const char *bt_ctf_field_type_sequence_get_length_field_name( + struct bt_ctf_field_type *type) +{ + const char *ret = NULL; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_SEQUENCE)) { + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + ret = sequence->length_field_name->str; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) +{ + struct bt_ctf_field_type_string *string = + g_new0(struct bt_ctf_field_type_string, 1); + + if (!string) { + return NULL; + } + + string->parent.declaration = &string->declaration.p; + string->parent.declaration->id = BT_CTF_TYPE_ID_STRING; + bt_ctf_field_type_init(&string->parent, TRUE); + string->declaration.encoding = BT_CTF_STRING_ENCODING_UTF8; + string->parent.declaration->alignment = CHAR_BIT; + return &string->parent; +} + +enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_string *string; + enum bt_ctf_string_encoding ret = BT_CTF_STRING_ENCODING_UNKNOWN; + + if (!type || (type->declaration->id != BT_CTF_TYPE_ID_STRING)) { + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, + parent); + ret = string->declaration.encoding; +end: + return ret; +} + +int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *type, + enum bt_ctf_string_encoding encoding) +{ + int ret = 0; + struct bt_ctf_field_type_string *string; + + if (!type || type->declaration->id != BT_CTF_TYPE_ID_STRING || + (encoding != BT_CTF_STRING_ENCODING_UTF8 && + encoding != BT_CTF_STRING_ENCODING_ASCII)) { + ret = -1; + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, parent); + string->declaration.encoding = encoding; +end: + return ret; +} + +int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *type) +{ + int ret; + enum bt_ctf_type_id type_id; + + if (!type) { + ret = -1; + goto end; + } + + if (type->frozen) { + ret = (int) type->declaration->alignment; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(type); + switch (type_id) { + case BT_CTF_TYPE_ID_SEQUENCE: + { + struct bt_ctf_field_type *element = + bt_ctf_field_type_sequence_get_element_type(type); + + if (!element) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_get_alignment(element); + bt_put(element); + break; + } + case BT_CTF_TYPE_ID_ARRAY: + { + struct bt_ctf_field_type *element = + bt_ctf_field_type_array_get_element_type(type); + + if (!element) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_get_alignment(element); + bt_put(element); + break; + } + case BT_CTF_TYPE_ID_STRUCT: + { + int i, element_count; + + element_count = bt_ctf_field_type_structure_get_field_count( + type); + if (element_count < 0) { + ret = element_count; + goto end; + } + + for (i = 0; i < element_count; i++) { + struct bt_ctf_field_type *field; + int field_alignment; + + ret = bt_ctf_field_type_structure_get_field(type, NULL, + &field, i); + if (ret) { + goto end; + } + + assert(field); + field_alignment = bt_ctf_field_type_get_alignment( + field); + bt_put(field); + if (field_alignment < 0) { + ret = field_alignment; + goto end; + } + + type->declaration->alignment = MAX(field_alignment, + type->declaration->alignment); + } + ret = (int) type->declaration->alignment; + break; + } + case BT_CTF_TYPE_ID_UNKNOWN: + ret = -1; + break; + default: + ret = (int) type->declaration->alignment; + break; + } +end: + return ret; +} + +static inline +int is_power_of_two(unsigned int value) +{ + return ((value & (value - 1)) == 0) && value > 0; +} + +int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, + unsigned int alignment) +{ + int ret = 0; + enum bt_ctf_type_id type_id; + + /* Alignment must be a power of two */ + if (!type || type->frozen || !is_power_of_two(alignment)) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(type); + if (type_id == BT_CTF_TYPE_ID_UNKNOWN) { + ret = -1; + goto end; + } + + if (type->declaration->id == BT_CTF_TYPE_ID_STRING && + alignment != CHAR_BIT) { + ret = -1; + goto end; + } + + if (type_id == BT_CTF_TYPE_ID_VARIANT || + type_id == BT_CTF_TYPE_ID_SEQUENCE || + type_id == BT_CTF_TYPE_ID_ARRAY) { + /* Setting an alignment on these types makes no sense */ + ret = -1; + goto end; + } + + type->declaration->alignment = alignment; + ret = 0; +end: + return ret; +} + +enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( + struct bt_ctf_field_type *type) +{ + enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN; + + if (!type) { + goto end; + } + + switch (type->declaration->id) { + case BT_CTF_TYPE_ID_INTEGER: + { + struct bt_ctf_field_type_integer *integer = container_of( + type, struct bt_ctf_field_type_integer, parent); + ret = integer->user_byte_order; + break; + } + case BT_CTF_TYPE_ID_FLOAT: + { + struct bt_ctf_field_type_floating_point *floating_point = + container_of(type, + struct bt_ctf_field_type_floating_point, + parent); + ret = floating_point->user_byte_order; + break; + } + default: + goto end; + } + + assert(ret == BT_CTF_BYTE_ORDER_NATIVE || + ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN || + ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN || + ret == BT_CTF_BYTE_ORDER_NETWORK); + +end: + return ret; +} + +int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, + enum bt_ctf_byte_order byte_order) +{ + int ret = 0; + int internal_byte_order; + enum bt_ctf_type_id type_id; + + if (!type || type->frozen) { + ret = -1; + goto end; + } + + switch (byte_order) { + case BT_CTF_BYTE_ORDER_NATIVE: + /* Leave unset. Will be initialized by parent. */ + internal_byte_order = 0; + break; + case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: + internal_byte_order = LITTLE_ENDIAN; + break; + case BT_CTF_BYTE_ORDER_BIG_ENDIAN: + case BT_CTF_BYTE_ORDER_NETWORK: + internal_byte_order = BIG_ENDIAN; + break; + default: + ret = -1; + goto end; + } + + type_id = type->declaration->id; + if (set_byte_order_funcs[type_id]) { + set_byte_order_funcs[type_id](type, internal_byte_order, 0); + } +end: + return ret; +} + +enum bt_ctf_type_id bt_ctf_field_type_get_type_id( + struct bt_ctf_field_type *type) +{ + if (!type) { + return BT_CTF_TYPE_ID_UNKNOWN; + } + + return type->declaration->id; +} + +int bt_ctf_field_type_is_integer(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_INTEGER; +} + +int bt_ctf_field_type_is_floating_point(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_FLOAT; +} + +int bt_ctf_field_type_is_enumeration(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_ENUM; +} + +int bt_ctf_field_type_is_string(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_STRING; +} + +int bt_ctf_field_type_is_structure(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_STRUCT; +} + +int bt_ctf_field_type_is_array(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_ARRAY; +} + +int bt_ctf_field_type_is_sequence(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_SEQUENCE; +} + +int bt_ctf_field_type_is_variant(struct bt_ctf_field_type *type) +{ + return bt_ctf_field_type_get_type_id(type) == BT_CTF_TYPE_ID_VARIANT; +} + +void bt_ctf_field_type_get(struct bt_ctf_field_type *type) +{ + bt_get(type); +} + +void bt_ctf_field_type_put(struct bt_ctf_field_type *type) +{ + bt_put(type); +} + +BT_HIDDEN +void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type) +{ + if (!type) { + return; + } + + type->freeze(type); +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_signed( + struct bt_ctf_field_type_variant *variant, + int64_t tag_value) +{ + struct bt_ctf_field_type *type = NULL; + GQuark field_name_quark; + gpointer index; + struct structure_field *field_entry; + struct range_overlap_query query = { + .range_start._signed = tag_value, + .range_end._signed = tag_value, + .mapping_name = 0, .overlaps = 0}; + + g_ptr_array_foreach(variant->tag->entries, check_ranges_overlap, + &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + field_entry = g_ptr_array_index(variant->fields, (size_t) index); + type = field_entry->type; +end: + return type; +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_unsigned( + struct bt_ctf_field_type_variant *variant, + uint64_t tag_value) +{ + struct bt_ctf_field_type *type = NULL; + GQuark field_name_quark; + gpointer index; + struct structure_field *field_entry; + struct range_overlap_query query = { + .range_start._unsigned = tag_value, + .range_end._unsigned = tag_value, + .mapping_name = 0, .overlaps = 0}; + + g_ptr_array_foreach(variant->tag->entries, + check_ranges_overlap_unsigned, + &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + field_entry = g_ptr_array_index(variant->fields, (size_t)index); + type = field_entry->type; +end: + return type; +} + +BT_HIDDEN +int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + int ret; + + if (!type || !context) { + ret = -1; + goto end; + } + + /* Make sure field type is valid before serializing it */ + ret = bt_ctf_field_type_validate(type); + + if (ret) { + goto end; + } + + ret = type->serialize(type, context); +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_field_type_set_native_byte_order(struct bt_ctf_field_type *type, + int byte_order) +{ + if (!type) { + return; + } + + assert(byte_order == LITTLE_ENDIAN || byte_order == BIG_ENDIAN); + if (set_byte_order_funcs[type->declaration->id]) { + set_byte_order_funcs[type->declaration->id](type, + byte_order, 1); + } +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy = NULL; + + if (!type) { + goto end; + } + + copy = type_copy_funcs[type->declaration->id](type); +end: + return copy; +} + +BT_HIDDEN +int bt_ctf_field_type_structure_get_field_name_index( + struct bt_ctf_field_type *type, const char *name) +{ + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_structure *structure; + + if (!type || !name || + bt_ctf_field_type_get_type_id(type) != BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + ret = -1; + goto end; + } + ret = (int) index; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_structure_set_field_index(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field, int index) +{ + int ret = 0; + struct bt_ctf_field_type_structure *structure; + + if (!type || !field || + bt_ctf_field_type_get_type_id(type) != BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (index < 0 || index >= structure->fields->len) { + ret = -1; + goto end; + } + + bt_get(field); + bt_put(((struct structure_field *) + g_ptr_array_index(structure->fields, index))->type); + ((struct structure_field *) structure->fields->pdata[index])->type = + field; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_variant_get_field_name_index( + struct bt_ctf_field_type *type, const char *name) +{ + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_variant *variant; + + if (!type || !name || + bt_ctf_field_type_get_type_id(type) != BT_CTF_TYPE_ID_VARIANT) { + ret = -1; + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + ret = -1; + goto end; + } + ret = (int) index; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_sequence_set_length_field_path( + struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path) +{ + int ret = 0; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || bt_ctf_field_type_get_type_id(type) != + BT_CTF_TYPE_ID_SEQUENCE) { + ret = -1; + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + bt_get(path); + BT_MOVE(sequence->length_field_path, path); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_variant_set_tag_field_path(struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || bt_ctf_field_type_get_type_id(type) != + BT_CTF_TYPE_ID_VARIANT) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + bt_get(path); + BT_MOVE(variant->tag_field_path, path); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_variant_set_tag_field_type(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *tag) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || !tag || + bt_ctf_field_type_get_type_id(tag) != + BT_CTF_TYPE_ID_ENUM) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + bt_get(tag); + if (variant->tag) { + bt_put(&variant->tag->parent); + } + variant->tag = container_of(tag, struct bt_ctf_field_type_enumeration, + parent); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_variant_set_field_index(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field, int index) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || !field || + bt_ctf_field_type_get_type_id(type) != BT_CTF_TYPE_ID_VARIANT) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (index < 0 || index >= variant->fields->len) { + ret = -1; + goto end; + } + + bt_get(field); + bt_put(((struct structure_field *) + g_ptr_array_index(variant->fields, index))->type); + ((struct structure_field *) variant->fields->pdata[index])->type = + field; +end: + return ret; +} + +static +void bt_ctf_field_type_integer_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_integer *integer = + (struct bt_ctf_field_type_integer *) type; + + if (!type) { + return; + } + + bt_put(integer->mapped_clock); + g_free(integer); +} + +static +void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_enumeration *enumeration = + (struct bt_ctf_field_type_enumeration *) type; + + if (!type) { + return; + } + + g_ptr_array_free(enumeration->entries, TRUE); + bt_put(enumeration->container); + g_free(enumeration); +} + +static +void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_floating_point *floating_point = + (struct bt_ctf_field_type_floating_point *) type; + + if (!type) { + return; + } + + g_free(floating_point); +} + +static +void bt_ctf_field_type_structure_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_structure *structure = + (struct bt_ctf_field_type_structure *) type; + + if (!type) { + return; + } + + g_ptr_array_free(structure->fields, TRUE); + g_hash_table_destroy(structure->field_name_to_index); + g_free(structure); +} + +static +void bt_ctf_field_type_variant_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant = + (struct bt_ctf_field_type_variant *) type; + + if (!type) { + return; + } + + g_ptr_array_free(variant->fields, TRUE); + g_hash_table_destroy(variant->field_name_to_index); + g_string_free(variant->tag_name, TRUE); + bt_put(&variant->tag->parent); + BT_PUT(variant->tag_field_path); + g_free(variant); +} + +static +void bt_ctf_field_type_array_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_array *array = + (struct bt_ctf_field_type_array *) type; + + if (!type) { + return; + } + + bt_put(array->element_type); + g_free(array); +} + +static +void bt_ctf_field_type_sequence_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_sequence *sequence = + (struct bt_ctf_field_type_sequence *) type; + + if (!type) { + return; + } + + bt_put(sequence->element_type); + g_string_free(sequence->length_field_name, TRUE); + BT_PUT(sequence->length_field_path); + g_free(sequence); +} + +static +void bt_ctf_field_type_string_destroy(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_string *string = + (struct bt_ctf_field_type_string *) type; + + if (!type) { + return; + } + + g_free(string); +} + +static +void generic_field_type_freeze(struct bt_ctf_field_type *type) +{ + type->frozen = 1; +} + +static +void bt_ctf_field_type_integer_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_integer *integer_type = container_of( + type, struct bt_ctf_field_type_integer, parent); + + if (integer_type->mapped_clock) { + bt_ctf_clock_freeze(integer_type->mapped_clock); + } + + generic_field_type_freeze(type); +} + +static +void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_enumeration *enumeration_type = container_of( + type, struct bt_ctf_field_type_enumeration, parent); + + generic_field_type_freeze(type); + bt_ctf_field_type_freeze(enumeration_type->container); +} + +static +void freeze_structure_field(struct structure_field *field) +{ + bt_ctf_field_type_freeze(field->type); +} + +static +void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_structure *structure_type = container_of( + type, struct bt_ctf_field_type_structure, parent); + + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); + generic_field_type_freeze(type); + g_ptr_array_foreach(structure_type->fields, + (GFunc) freeze_structure_field, NULL); +} + +static +void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant_type = container_of( + type, struct bt_ctf_field_type_variant, parent); + + generic_field_type_freeze(type); + g_ptr_array_foreach(variant_type->fields, + (GFunc) freeze_structure_field, NULL); +} + +static +void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_array *array_type = container_of( + type, struct bt_ctf_field_type_array, parent); + + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); + generic_field_type_freeze(type); + bt_ctf_field_type_freeze(array_type->element_type); +} + +static +void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_sequence *sequence_type = container_of( + type, struct bt_ctf_field_type_sequence, parent); + + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); + generic_field_type_freeze(type); + bt_ctf_field_type_freeze(sequence_type->element_type); +} + +static +const char *get_encoding_string(enum bt_ctf_string_encoding encoding) +{ + const char *encoding_string; + + switch (encoding) { + case BT_CTF_STRING_ENCODING_NONE: + encoding_string = "none"; + break; + case BT_CTF_STRING_ENCODING_ASCII: + encoding_string = "ASCII"; + break; + case BT_CTF_STRING_ENCODING_UTF8: + encoding_string = "UTF8"; + break; + default: + encoding_string = "unknown"; + break; + } + + return encoding_string; +} + +static +const char *get_integer_base_string(enum bt_ctf_integer_base base) +{ + const char *base_string; + + switch (base) { + case BT_CTF_INTEGER_BASE_DECIMAL: + base_string = "decimal"; + break; + case BT_CTF_INTEGER_BASE_HEXADECIMAL: + base_string = "hexadecimal"; + break; + case BT_CTF_INTEGER_BASE_OCTAL: + base_string = "octal"; + break; + case BT_CTF_INTEGER_BASE_BINARY: + base_string = "binary"; + break; + default: + base_string = "unknown"; + break; + } + + return base_string; +} + +static +int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_integer *integer = container_of(type, + struct bt_ctf_field_type_integer, parent); + int ret = 0; + + g_string_append_printf(context->string, + "integer { size = %zu; align = %zu; signed = %s; encoding = %s; base = %s; byte_order = %s", + integer->declaration.len, type->declaration->alignment, + (integer->declaration.signedness ? "true" : "false"), + get_encoding_string(integer->declaration.encoding), + get_integer_base_string(integer->declaration.base), + get_byte_order_string(integer->declaration.byte_order)); + if (integer->mapped_clock) { + const char *clock_name = bt_ctf_clock_get_name( + integer->mapped_clock); + + if (!clock_name) { + ret = -1; + goto end; + } + + g_string_append_printf(context->string, + "; map = clock.%s.value", clock_name); + } + + g_string_append(context->string, "; }"); +end: + return ret; +} + +static +int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + size_t entry; + int ret; + struct bt_ctf_field_type_enumeration *enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + struct bt_ctf_field_type *container_type; + int container_signed; + + container_type = bt_ctf_field_type_enumeration_get_container_type(type); + if (!container_type) { + ret = -1; + goto end; + } + + container_signed = bt_ctf_field_type_integer_get_signed(container_type); + if (container_signed < 0) { + ret = container_signed; + goto error_put_container_type; + } + + g_string_append(context->string, "enum : "); + ret = bt_ctf_field_type_serialize(enumeration->container, context); + if (ret) { + goto error_put_container_type; + } + + g_string_append(context->string, " { "); + for (entry = 0; entry < enumeration->entries->len; entry++) { + struct enumeration_mapping *mapping = + enumeration->entries->pdata[entry]; + + if (container_signed) { + if (mapping->range_start._signed == + mapping->range_end._signed) { + g_string_append_printf(context->string, + "\"%s\" = %" PRId64, + g_quark_to_string(mapping->string), + mapping->range_start._signed); + } else { + g_string_append_printf(context->string, + "\"%s\" = %" PRId64 " ... %" PRId64, + g_quark_to_string(mapping->string), + mapping->range_start._signed, + mapping->range_end._signed); + } + } else { + if (mapping->range_start._unsigned == + mapping->range_end._unsigned) { + g_string_append_printf(context->string, + "\"%s\" = %" PRIu64, + g_quark_to_string(mapping->string), + mapping->range_start._unsigned); + } else { + g_string_append_printf(context->string, + "\"%s\" = %" PRIu64 " ... %" PRIu64, + g_quark_to_string(mapping->string), + mapping->range_start._unsigned, + mapping->range_end._unsigned); + } + } + + g_string_append(context->string, + ((entry != (enumeration->entries->len - 1)) ? + ", " : " }")); + } + + if (context->field_name->len) { + g_string_append_printf(context->string, " %s", + context->field_name->str); + g_string_assign(context->field_name, ""); + } +error_put_container_type: + bt_put(container_type); +end: + return ret; +} + +static +int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_floating_point *floating_point = container_of( + type, struct bt_ctf_field_type_floating_point, parent); + + g_string_append_printf(context->string, + "floating_point { exp_dig = %zu; mant_dig = %zu; byte_order = %s; align = %zu; }", + floating_point->declaration.exp->len, + floating_point->declaration.mantissa->len + 1, + get_byte_order_string(floating_point->declaration.byte_order), + type->declaration->alignment); + return 0; +} + +static +int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + size_t i; + unsigned int indent; + int ret = 0; + struct bt_ctf_field_type_structure *structure = container_of(type, + struct bt_ctf_field_type_structure, parent); + GString *structure_field_name = context->field_name; + + context->field_name = g_string_new(""); + + context->current_indentation_level++; + g_string_append(context->string, "struct {\n"); + + for (i = 0; i < structure->fields->len; i++) { + struct structure_field *field; + + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + field = structure->fields->pdata[i]; + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + ret = bt_ctf_field_type_serialize(field->type, context); + if (ret) { + goto end; + } + + if (context->field_name->len) { + g_string_append_printf(context->string, " %s", + context->field_name->str); + } + g_string_append(context->string, ";\n"); + } + + context->current_indentation_level--; + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_append_printf(context->string, "} align(%zu)", + type->declaration->alignment); +end: + g_string_free(context->field_name, TRUE); + context->field_name = structure_field_name; + return ret; +} + +static +int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + size_t i; + unsigned int indent; + int ret = 0; + struct bt_ctf_field_type_variant *variant = container_of( + type, struct bt_ctf_field_type_variant, parent); + GString *variant_field_name = context->field_name; + + context->field_name = g_string_new(""); + if (variant->tag_name->len > 0) { + g_string_append_printf(context->string, + "variant <%s> {\n", variant->tag_name->str); + } else { + g_string_append(context->string, "variant {\n"); + } + + context->current_indentation_level++; + for (i = 0; i < variant->fields->len; i++) { + struct structure_field *field = variant->fields->pdata[i]; + + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + ret = bt_ctf_field_type_serialize(field->type, context); + if (ret) { + goto end; + } + + if (context->field_name->len) { + g_string_append_printf(context->string, " %s;", + context->field_name->str); + } + + g_string_append_c(context->string, '\n'); + } + + context->current_indentation_level--; + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_append(context->string, "}"); +end: + g_string_free(context->field_name, TRUE); + context->field_name = variant_field_name; + return ret; +} + +static +int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + int ret = 0; + struct bt_ctf_field_type_array *array = container_of(type, + struct bt_ctf_field_type_array, parent); + + ret = bt_ctf_field_type_serialize(array->element_type, context); + if (ret) { + goto end; + } + + if (context->field_name->len) { + g_string_append_printf(context->string, " %s[%u]", + context->field_name->str, array->length); + g_string_assign(context->field_name, ""); + } else { + g_string_append_printf(context->string, "[%u]", array->length); + } +end: + return ret; +} + +static +int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + int ret = 0; + struct bt_ctf_field_type_sequence *sequence = container_of( + type, struct bt_ctf_field_type_sequence, parent); + + ret = bt_ctf_field_type_serialize(sequence->element_type, context); + if (ret) { + goto end; + } + + if (context->field_name->len) { + g_string_append_printf(context->string, " %s[%s]", + context->field_name->str, + sequence->length_field_name->str); + g_string_assign(context->field_name, ""); + } else { + g_string_append_printf(context->string, "[%s]", + sequence->length_field_name->str); + } +end: + return ret; +} + +static +int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_string *string = container_of( + type, struct bt_ctf_field_type_string, parent); + + g_string_append_printf(context->string, + "string { encoding = %s; }", + get_encoding_string(string->declaration.encoding)); + return 0; +} + +static +enum bt_ctf_byte_order get_ctf_ir_byte_order(int byte_order) { + enum bt_ctf_byte_order ret; + + switch (byte_order) { + case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: + case LITTLE_ENDIAN: + ret = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; + break; + case BT_CTF_BYTE_ORDER_BIG_ENDIAN: + case BIG_ENDIAN: + ret = BT_CTF_BYTE_ORDER_BIG_ENDIAN; + break; + case BT_CTF_BYTE_ORDER_NETWORK: + ret = BT_CTF_BYTE_ORDER_NETWORK; + break; + case BT_CTF_BYTE_ORDER_NATIVE: + ret = BT_CTF_BYTE_ORDER_NATIVE; + break; + default: + ret = BT_CTF_BYTE_ORDER_UNKNOWN; + break; + } + + return ret; +} + +static +void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + struct bt_ctf_field_type_integer *integer_type = container_of(type, + struct bt_ctf_field_type_integer, parent); + + if (set_native) { + if (integer_type->user_byte_order == BT_CTF_BYTE_ORDER_NATIVE) { + /* + * User byte order is native, so we can set + * the real byte order. + */ + integer_type->declaration.byte_order = + byte_order; + } + } else { + integer_type->user_byte_order = + get_ctf_ir_byte_order(byte_order); + integer_type->declaration.byte_order = byte_order; + } +} + +static +void bt_ctf_field_type_enumeration_set_byte_order( + struct bt_ctf_field_type *type, int byte_order, int set_native) +{ + struct bt_ctf_field_type_enumeration *enum_type = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + + /* Safe to assume that container is an integer */ + bt_ctf_field_type_integer_set_byte_order(enum_type->container, + byte_order, set_native); +} + +static +void bt_ctf_field_type_floating_point_set_byte_order( + struct bt_ctf_field_type *type, int byte_order, int set_native) +{ + struct bt_ctf_field_type_floating_point *floating_point_type = + container_of(type, struct bt_ctf_field_type_floating_point, + parent); + + if (set_native) { + if (floating_point_type->user_byte_order == + BT_CTF_BYTE_ORDER_NATIVE) { + /* + * User byte order is native, so we can set + * the real byte order. + */ + floating_point_type->declaration.byte_order = + byte_order; + floating_point_type->sign.byte_order = + byte_order; + floating_point_type->mantissa.byte_order = + byte_order; + floating_point_type->exp.byte_order = + byte_order; + } + } else { + floating_point_type->user_byte_order = + get_ctf_ir_byte_order(byte_order); + floating_point_type->declaration.byte_order = byte_order; + floating_point_type->sign.byte_order = byte_order; + floating_point_type->mantissa.byte_order = byte_order; + floating_point_type->exp.byte_order = byte_order; + } +} + +static +void bt_ctf_field_type_structure_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + int i; + struct bt_ctf_field_type_structure *structure_type = + container_of(type, struct bt_ctf_field_type_structure, + parent); + + for (i = 0; i < structure_type->fields->len; i++) { + struct structure_field *field = g_ptr_array_index( + structure_type->fields, i); + struct bt_ctf_field_type *field_type = field->type; + + if (set_byte_order_funcs[field_type->declaration->id]) { + set_byte_order_funcs[field_type->declaration->id]( + field_type, byte_order, set_native); + } + } +} + +static +void bt_ctf_field_type_variant_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + int i; + struct bt_ctf_field_type_variant *variant_type = + container_of(type, struct bt_ctf_field_type_variant, + parent); + + for (i = 0; i < variant_type->fields->len; i++) { + struct structure_field *field = g_ptr_array_index( + variant_type->fields, i); + struct bt_ctf_field_type *field_type = field->type; + + if (set_byte_order_funcs[field_type->declaration->id]) { + set_byte_order_funcs[field_type->declaration->id]( + field_type, byte_order, set_native); + } + } +} + +static +void bt_ctf_field_type_array_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + struct bt_ctf_field_type_array *array_type = + container_of(type, struct bt_ctf_field_type_array, + parent); + + if (set_byte_order_funcs[array_type->element_type->declaration->id]) { + set_byte_order_funcs[array_type->element_type->declaration->id]( + array_type->element_type, byte_order, set_native); + } +} + +static +void bt_ctf_field_type_sequence_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + struct bt_ctf_field_type_sequence *sequence_type = + container_of(type, struct bt_ctf_field_type_sequence, + parent); + + if (set_byte_order_funcs[ + sequence_type->element_type->declaration->id]) { + set_byte_order_funcs[ + sequence_type->element_type->declaration->id]( + sequence_type->element_type, byte_order, set_native); + } +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_integer *integer, *copy_integer; + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + copy = bt_ctf_field_type_integer_create(integer->declaration.len); + if (!copy) { + goto end; + } + + copy_integer = container_of(copy, struct bt_ctf_field_type_integer, + parent); + copy_integer->declaration = integer->declaration; + if (integer->mapped_clock) { + bt_get(integer->mapped_clock); + copy_integer->mapped_clock = integer->mapped_clock; + } + + copy_integer->user_byte_order = integer->user_byte_order; + +end: + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy( + struct bt_ctf_field_type *type) +{ + size_t i; + struct bt_ctf_field_type *copy = NULL, *copy_container; + struct bt_ctf_field_type_enumeration *enumeration, *copy_enumeration; + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + + /* Copy the source enumeration's container */ + copy_container = bt_ctf_field_type_copy(enumeration->container); + if (!copy_container) { + goto end; + } + + copy = bt_ctf_field_type_enumeration_create(copy_container); + if (!copy) { + goto end; + } + copy_enumeration = container_of(copy, + struct bt_ctf_field_type_enumeration, parent); + + /* Copy all enumaration entries */ + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = g_ptr_array_index( + enumeration->entries, i); + struct enumeration_mapping* copy_mapping = g_new0( + struct enumeration_mapping, 1); + + if (!copy_mapping) { + goto error; + } + + *copy_mapping = *mapping; + g_ptr_array_add(copy_enumeration->entries, copy_mapping); + } + + copy_enumeration->declaration = enumeration->declaration; +end: + bt_put(copy_container); + return copy; +error: + bt_put(copy_container); + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_floating_point *floating_point, *copy_float; + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + copy = bt_ctf_field_type_floating_point_create(); + if (!copy) { + goto end; + } + + copy_float = container_of(copy, + struct bt_ctf_field_type_floating_point, parent); + copy_float->declaration = floating_point->declaration; + copy_float->sign = floating_point->sign; + copy_float->mantissa = floating_point->mantissa; + copy_float->exp = floating_point->exp; + copy_float->user_byte_order = floating_point->user_byte_order; + copy_float->declaration.sign = ©_float->sign; + copy_float->declaration.mantissa = ©_float->mantissa; + copy_float->declaration.exp = ©_float->exp; +end: + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy( + struct bt_ctf_field_type *type) +{ + int i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_structure *structure, *copy_structure; + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + copy = bt_ctf_field_type_structure_create(); + if (!copy) { + goto end; + } + + copy_structure = container_of(copy, + struct bt_ctf_field_type_structure, parent); + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, structure->field_name_to_index); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_hash_table_insert(copy_structure->field_name_to_index, + key, value); + } + + for (i = 0; i < structure->fields->len; i++) { + struct structure_field *entry, *copy_entry; + struct bt_ctf_field_type *copy_field; + + copy_entry = g_new0(struct structure_field, 1); + if (!copy_entry) { + goto error; + } + + entry = g_ptr_array_index(structure->fields, i); + copy_field = bt_ctf_field_type_copy(entry->type); + if (!copy_field) { + g_free(copy_entry); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = copy_field; + g_ptr_array_add(copy_structure->fields, copy_entry); + } + + copy_structure->declaration = structure->declaration; +end: + return copy; +error: + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy( + struct bt_ctf_field_type *type) +{ + int i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type *copy = NULL, *copy_tag = NULL; + struct bt_ctf_field_type_variant *variant, *copy_variant; + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (variant->tag) { + copy_tag = bt_ctf_field_type_copy(&variant->tag->parent); + if (!copy_tag) { + goto end; + } + } + + copy = bt_ctf_field_type_variant_create(copy_tag, + variant->tag_name->len ? variant->tag_name->str : NULL); + if (!copy) { + goto end; + } + + copy_variant = container_of(copy, struct bt_ctf_field_type_variant, + parent); + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, variant->field_name_to_index); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_hash_table_insert(copy_variant->field_name_to_index, + key, value); + } + + for (i = 0; i < variant->fields->len; i++) { + struct structure_field *entry, *copy_entry; + struct bt_ctf_field_type *copy_field; + + copy_entry = g_new0(struct structure_field, 1); + if (!copy_entry) { + goto error; + } + + entry = g_ptr_array_index(variant->fields, i); + copy_field = bt_ctf_field_type_copy(entry->type); + if (!copy_field) { + g_free(copy_entry); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = copy_field; + g_ptr_array_add(copy_variant->fields, copy_entry); + } + + copy_variant->declaration = variant->declaration; + if (variant->tag_field_path) { + copy_variant->tag_field_path = bt_ctf_field_path_copy( + variant->tag_field_path); + if (!copy_variant->tag_field_path) { + goto error; + } + } +end: + bt_put(copy_tag); + return copy; +error: + bt_put(copy_tag); + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy = NULL, *copy_element; + struct bt_ctf_field_type_array *array, *copy_array; + + array = container_of(type, struct bt_ctf_field_type_array, + parent); + copy_element = bt_ctf_field_type_copy(array->element_type); + if (!copy_element) { + goto end; + } + + copy = bt_ctf_field_type_array_create(copy_element, array->length); + if (!copy) { + goto end; + } + + copy_array = container_of(copy, struct bt_ctf_field_type_array, + parent); + copy_array->declaration = array->declaration; +end: + bt_put(copy_element); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy = NULL, *copy_element; + struct bt_ctf_field_type_sequence *sequence, *copy_sequence; + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + copy_element = bt_ctf_field_type_copy(sequence->element_type); + if (!copy_element) { + goto end; + } + + copy = bt_ctf_field_type_sequence_create(copy_element, + sequence->length_field_name->len ? + sequence->length_field_name->str : NULL); + if (!copy) { + goto end; + } + + copy_sequence = container_of(copy, struct bt_ctf_field_type_sequence, + parent); + copy_sequence->declaration = sequence->declaration; + if (sequence->length_field_path) { + copy_sequence->length_field_path = bt_ctf_field_path_copy( + sequence->length_field_path); + if (!copy_sequence->length_field_path) { + goto error; + } + } +end: + bt_put(copy_element); + return copy; +error: + BT_PUT(copy); + goto end; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_string *string, *copy_string; + + copy = bt_ctf_field_type_string_create(); + if (!copy) { + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, + parent); + copy_string = container_of(type, struct bt_ctf_field_type_string, + parent); + copy_string->declaration = string->declaration; +end: + return copy; +} + +static +int bt_ctf_field_type_integer_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_integer *integer_a; + struct bt_ctf_field_type_integer *integer_b; + struct declaration_integer *decl_a; + struct declaration_integer *decl_b; + + integer_a = container_of(type_a, struct bt_ctf_field_type_integer, + parent); + integer_b = container_of(type_b, struct bt_ctf_field_type_integer, + parent); + decl_a = &integer_a->declaration; + decl_b = &integer_b->declaration; + + /* Length */ + if (decl_a->len != decl_b->len) { + goto end; + } + + /* + * Compare user byte orders only, not the cached, + * real byte orders. + */ + if (integer_a->user_byte_order != integer_b->user_byte_order) { + goto end; + } + + /* Signedness */ + if (decl_a->signedness != decl_b->signedness) { + goto end; + } + + /* Base */ + if (decl_a->base != decl_b->base) { + goto end; + } + + /* Encoding */ + if (decl_a->encoding != decl_b->encoding) { + goto end; + } + + /* Mapped clock */ + if (integer_a->mapped_clock != integer_b->mapped_clock) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_floating_point_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_floating_point *float_a; + struct bt_ctf_field_type_floating_point *float_b; + + float_a = container_of(type_a, + struct bt_ctf_field_type_floating_point, parent); + float_b = container_of(type_b, + struct bt_ctf_field_type_floating_point, parent); + + /* Sign length */ + if (float_a->sign.len != float_b->sign.len) { + goto end; + } + + /* Exponent length */ + if (float_a->exp.len != float_b->exp.len) { + goto end; + } + + /* Mantissa length */ + if (float_a->mantissa.len != float_b->mantissa.len) { + goto end; + } + + /* + * Compare user byte orders only, not the cached, + * real byte orders. + */ + if (float_a->user_byte_order != float_b->user_byte_order) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_enumeration_mappings(struct enumeration_mapping *mapping_a, + struct enumeration_mapping *mapping_b) +{ + int ret = 1; + + /* Label */ + if (mapping_a->string != mapping_b->string) { + goto end; + } + + /* Range start */ + if (mapping_a->range_start._unsigned != + mapping_b->range_start._unsigned) { + goto end; + } + + /* Range end */ + if (mapping_a->range_end._unsigned != + mapping_b->range_end._unsigned) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_enumeration_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_enumeration *enum_a; + struct bt_ctf_field_type_enumeration *enum_b; + + enum_a = container_of(type_a, + struct bt_ctf_field_type_enumeration, parent); + enum_b = container_of(type_b, + struct bt_ctf_field_type_enumeration, parent); + + /* Container field type */ + ret = bt_ctf_field_type_compare(enum_a->container, enum_b->container); + if (ret) { + goto end; + } + + ret = 1; + + /* Entries */ + if (enum_a->entries->len != enum_b->entries->len) { + goto end; + } + + for (i = 0; i < enum_a->entries->len; ++i) { + struct enumeration_mapping *mapping_a = + g_ptr_array_index(enum_a->entries, i); + struct enumeration_mapping *mapping_b = + g_ptr_array_index(enum_b->entries, i); + + if (compare_enumeration_mappings(mapping_a, mapping_b)) { + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_string_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_string *string_a; + struct bt_ctf_field_type_string *string_b; + + string_a = container_of(type_a, + struct bt_ctf_field_type_string, parent); + string_b = container_of(type_b, + struct bt_ctf_field_type_string, parent); + + /* Encoding */ + if (string_a->declaration.encoding != string_b->declaration.encoding) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_structure_fields(struct structure_field *field_a, + struct structure_field *field_b) +{ + int ret = 1; + + /* Label */ + if (field_a->name != field_b->name) { + goto end; + } + + /* Type */ + ret = bt_ctf_field_type_compare(field_a->type, field_b->type); + +end: + return ret; +} + +static +int bt_ctf_field_type_structure_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_structure *struct_a; + struct bt_ctf_field_type_structure *struct_b; + + struct_a = container_of(type_a, + struct bt_ctf_field_type_structure, parent); + struct_b = container_of(type_b, + struct bt_ctf_field_type_structure, parent); + + /* Alignment */ + if (bt_ctf_field_type_get_alignment(type_a) != + bt_ctf_field_type_get_alignment(type_b)) { + goto end; + } + + /* Fields */ + if (struct_a->fields->len != struct_b->fields->len) { + goto end; + } + + for (i = 0; i < struct_a->fields->len; ++i) { + struct structure_field *field_a = + g_ptr_array_index(struct_a->fields, i); + struct structure_field *field_b = + g_ptr_array_index(struct_b->fields, i); + + ret = compare_structure_fields(field_a, field_b); + if (ret) { + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_variant_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_variant *variant_a; + struct bt_ctf_field_type_variant *variant_b; + + variant_a = container_of(type_a, + struct bt_ctf_field_type_variant, parent); + variant_b = container_of(type_b, + struct bt_ctf_field_type_variant, parent); + + /* Tag name */ + if (strcmp(variant_a->tag_name->str, variant_b->tag_name->str)) { + goto end; + } + + /* Tag type */ + ret = bt_ctf_field_type_compare( + (struct bt_ctf_field_type *) variant_a->tag, + (struct bt_ctf_field_type *) variant_b->tag); + if (ret) { + goto end; + } + + ret = 1; + + /* Fields */ + if (variant_a->fields->len != variant_b->fields->len) { + goto end; + } + + for (i = 0; i < variant_a->fields->len; ++i) { + struct structure_field *field_a = + g_ptr_array_index(variant_a->fields, i); + struct structure_field *field_b = + g_ptr_array_index(variant_b->fields, i); + + ret = compare_structure_fields(field_a, field_b); + if (ret) { + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_array_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_array *array_a; + struct bt_ctf_field_type_array *array_b; + + array_a = container_of(type_a, + struct bt_ctf_field_type_array, parent); + array_b = container_of(type_b, + struct bt_ctf_field_type_array, parent); + + /* Length */ + if (array_a->length != array_b->length) { + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_compare(array_a->element_type, + array_b->element_type); + +end: + return ret; +} + +static +int bt_ctf_field_type_sequence_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = -1; + struct bt_ctf_field_type_sequence *sequence_a; + struct bt_ctf_field_type_sequence *sequence_b; + + sequence_a = container_of(type_a, + struct bt_ctf_field_type_sequence, parent); + sequence_b = container_of(type_b, + struct bt_ctf_field_type_sequence, parent); + + /* Length name */ + if (strcmp(sequence_a->length_field_name->str, + sequence_b->length_field_name->str)) { + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_compare(sequence_a->element_type, + sequence_b->element_type); + +end: + return ret; +} + +int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + + if (type_a == type_b) { + /* Same reference: equal (even if both are NULL) */ + ret = 0; + goto end; + } + + if (!type_a || !type_b) { + ret = -1; + goto end; + } + + if (type_a->declaration->id != type_b->declaration->id) { + /* Different type IDs */ + goto end; + } + + if (type_a->declaration->id == BT_CTF_TYPE_ID_UNKNOWN) { + /* Both have unknown type IDs */ + goto end; + } + + ret = type_compare_funcs[type_a->declaration->id](type_a, type_b); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_get_field_count(struct bt_ctf_field_type *field_type) +{ + int field_count = -1; + enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type); + + switch (type_id) { + case CTF_TYPE_STRUCT: + field_count = + bt_ctf_field_type_structure_get_field_count(field_type); + break; + case CTF_TYPE_VARIANT: + field_count = + bt_ctf_field_type_variant_get_field_count(field_type); + break; + case CTF_TYPE_ARRAY: + case CTF_TYPE_SEQUENCE: + /* + * Array and sequence types always contain a single member + * (the element type). + */ + field_count = 1; + break; + default: + break; + } + + return field_count; +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_get_field_at_index( + struct bt_ctf_field_type *field_type, int index) +{ + struct bt_ctf_field_type *field = NULL; + enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type); + + switch (type_id) { + case CTF_TYPE_STRUCT: + bt_ctf_field_type_structure_get_field(field_type, NULL, &field, + index); + break; + case CTF_TYPE_VARIANT: + { + int ret = bt_ctf_field_type_variant_get_field(field_type, NULL, + &field, index); + if (ret) { + field = NULL; + goto end; + } + break; + } + case CTF_TYPE_ARRAY: + field = bt_ctf_field_type_array_get_element_type(field_type); + break; + case CTF_TYPE_SEQUENCE: + field = bt_ctf_field_type_sequence_get_element_type(field_type); + break; + default: + break; + } +end: + return field; +} + +BT_HIDDEN +int bt_ctf_field_type_get_field_index(struct bt_ctf_field_type *field_type, + const char *name) +{ + int field_index = -1; + enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type); + + switch (type_id) { + case CTF_TYPE_STRUCT: + field_index = bt_ctf_field_type_structure_get_field_name_index( + field_type, name); + break; + case CTF_TYPE_VARIANT: + field_index = bt_ctf_field_type_variant_get_field_name_index( + field_type, name); + break; + default: + break; + } + + return field_index; +} + +struct bt_ctf_field_path *bt_ctf_field_type_variant_get_tag_field_path( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_path *field_path = NULL; + struct bt_ctf_field_type_variant *variant; + + if (!type || !bt_ctf_field_type_is_variant(type)) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + field_path = bt_get(variant->tag_field_path); +end: + return field_path; +} + +struct bt_ctf_field_path *bt_ctf_field_type_sequence_get_length_field_path( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_path *field_path = NULL; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || !bt_ctf_field_type_is_sequence(type)) { + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + field_path = bt_get(sequence->length_field_path); +end: + return field_path; +} diff --git a/formats/ctf/ir/fields.c b/formats/ctf/ir/fields.c new file mode 100644 index 00000000..105dd7a1 --- /dev/null +++ b/formats/ctf/ir/fields.c @@ -0,0 +1,2357 @@ +/* + * fields.c + * + * Babeltrace CTF IR - Event Fields + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#define PACKET_LEN_INCREMENT (getpagesize() * 8 * CHAR_BIT) + +static +struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_enumeration_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_floating_point_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_structure_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_variant_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_array_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_sequence_create( + struct bt_ctf_field_type *); +static +struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *); + +static +void bt_ctf_field_destroy(struct bt_object *); +static +void bt_ctf_field_integer_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_structure_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_variant_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_array_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_sequence_destroy(struct bt_ctf_field *); +static +void bt_ctf_field_string_destroy(struct bt_ctf_field *); + +static +int bt_ctf_field_generic_validate(struct bt_ctf_field *); +static +int bt_ctf_field_structure_validate(struct bt_ctf_field *); +static +int bt_ctf_field_variant_validate(struct bt_ctf_field *); +static +int bt_ctf_field_enumeration_validate(struct bt_ctf_field *); +static +int bt_ctf_field_array_validate(struct bt_ctf_field *); +static +int bt_ctf_field_sequence_validate(struct bt_ctf_field *); + +static +int bt_ctf_field_generic_reset(struct bt_ctf_field *); +static +int bt_ctf_field_structure_reset(struct bt_ctf_field *); +static +int bt_ctf_field_variant_reset(struct bt_ctf_field *); +static +int bt_ctf_field_enumeration_reset(struct bt_ctf_field *); +static +int bt_ctf_field_array_reset(struct bt_ctf_field *); +static +int bt_ctf_field_sequence_reset(struct bt_ctf_field *); +static +int bt_ctf_field_string_reset(struct bt_ctf_field *); + +static +int bt_ctf_field_integer_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_structure_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_variant_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_array_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_sequence_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); +static +int bt_ctf_field_string_serialize(struct bt_ctf_field *, + struct ctf_stream_pos *); + +static +int bt_ctf_field_integer_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_enumeration_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_floating_point_copy(struct bt_ctf_field *, + struct bt_ctf_field *); +static +int bt_ctf_field_structure_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_variant_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_array_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_sequence_copy(struct bt_ctf_field *, struct bt_ctf_field *); +static +int bt_ctf_field_string_copy(struct bt_ctf_field *, struct bt_ctf_field *); + +static +void generic_field_freeze(struct bt_ctf_field *); +static +void bt_ctf_field_enumeration_freeze(struct bt_ctf_field *); +static +void bt_ctf_field_structure_freeze(struct bt_ctf_field *); +static +void bt_ctf_field_variant_freeze(struct bt_ctf_field *); +static +void bt_ctf_field_array_freeze(struct bt_ctf_field *); +static +void bt_ctf_field_sequence_freeze(struct bt_ctf_field *); + +static +int increase_packet_size(struct ctf_stream_pos *pos); + +static +struct bt_ctf_field *(* const field_create_funcs[])( + struct bt_ctf_field_type *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_integer_create, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_create, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_floating_point_create, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_create, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_create, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_create, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_create, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_string_create, +}; + +static +void (* const field_destroy_funcs[])(struct bt_ctf_field *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_integer_destroy, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_destroy, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_floating_point_destroy, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_destroy, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_destroy, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_destroy, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_destroy, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_string_destroy, +}; + +static +int (* const field_validate_funcs[])(struct bt_ctf_field *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_generic_validate, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_validate, + [BT_CTF_TYPE_ID_FLOAT] = bt_ctf_field_generic_validate, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_validate, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_validate, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_validate, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_validate, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_generic_validate, +}; + +static +int (* const field_reset_funcs[])(struct bt_ctf_field *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_generic_reset, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_reset, + [BT_CTF_TYPE_ID_FLOAT] = bt_ctf_field_generic_reset, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_reset, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_reset, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_reset, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_reset, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_string_reset, +}; + +static +int (* const field_serialize_funcs[])(struct bt_ctf_field *, + struct ctf_stream_pos *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_integer_serialize, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_serialize, + [BT_CTF_TYPE_ID_FLOAT] = + bt_ctf_field_floating_point_serialize, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_serialize, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_serialize, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_serialize, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_serialize, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_string_serialize, +}; + +static +int (* const field_copy_funcs[])(struct bt_ctf_field *, + struct bt_ctf_field *) = { + [BT_CTF_TYPE_ID_INTEGER] = bt_ctf_field_integer_copy, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_copy, + [BT_CTF_TYPE_ID_FLOAT] = bt_ctf_field_floating_point_copy, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_copy, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_copy, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_copy, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_copy, + [BT_CTF_TYPE_ID_STRING] = bt_ctf_field_string_copy, +}; + +static +void (* const field_freeze_funcs[])(struct bt_ctf_field *) = { + [BT_CTF_TYPE_ID_INTEGER] = generic_field_freeze, + [BT_CTF_TYPE_ID_FLOAT] = generic_field_freeze, + [BT_CTF_TYPE_ID_STRING] = generic_field_freeze, + [BT_CTF_TYPE_ID_ENUM] = bt_ctf_field_enumeration_freeze, + [BT_CTF_TYPE_ID_STRUCT] = bt_ctf_field_structure_freeze, + [BT_CTF_TYPE_ID_VARIANT] = bt_ctf_field_variant_freeze, + [BT_CTF_TYPE_ID_ARRAY] = bt_ctf_field_array_freeze, + [BT_CTF_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_freeze, +}; + +struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field *field = NULL; + enum bt_ctf_type_id type_id; + int ret; + + if (!type) { + goto error; + } + + type_id = bt_ctf_field_type_get_type_id(type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || + type_id >= BT_CTF_NR_TYPE_IDS) { + goto error; + } + + /* Field class MUST be valid */ + ret = bt_ctf_field_type_validate(type); + + if (ret) { + /* Invalid */ + goto error; + } + + field = field_create_funcs[type_id](type); + if (!field) { + goto error; + } + + /* The type's declaration can't change after this point */ + bt_ctf_field_type_freeze(type); + bt_get(type); + bt_object_init(field, bt_ctf_field_destroy); + field->type = type; +error: + return field; +} + +void bt_ctf_field_get(struct bt_ctf_field *field) +{ + bt_get(field); +} + +void bt_ctf_field_put(struct bt_ctf_field *field) +{ + bt_put(field); +} + +struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!field) { + goto end; + } + + ret = field->type; + bt_get(ret); +end: + return ret; +} + +enum bt_ctf_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field) +{ + enum bt_ctf_type_id ret = BT_CTF_TYPE_ID_UNKNOWN; + + if (!field) { + goto end; + } + + ret = bt_ctf_field_type_get_type_id(field->type); +end: + return ret; +} + +int bt_ctf_field_is_integer(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_INTEGER; +} + +int bt_ctf_field_is_floating_point(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_FLOAT; +} + +int bt_ctf_field_is_enumeration(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_ENUM; +} + +int bt_ctf_field_is_string(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_STRING; +} + +int bt_ctf_field_is_structure(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_STRUCT; +} + +int bt_ctf_field_is_array(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_ARRAY; +} + +int bt_ctf_field_is_sequence(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_SEQUENCE; +} + +int bt_ctf_field_is_variant(struct bt_ctf_field *field) +{ + return bt_ctf_field_get_type_id(field) == BT_CTF_TYPE_ID_VARIANT; +} + +struct bt_ctf_field *bt_ctf_field_sequence_get_length( + struct bt_ctf_field *field) +{ + struct bt_ctf_field *ret = NULL; + struct bt_ctf_field_sequence *sequence; + + if (!field) { + goto end; + } + + if (bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_SEQUENCE) { + goto end; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + ret = sequence->length; + bt_get(ret); +end: + return ret; +} + +int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field, + struct bt_ctf_field *length_field) +{ + int ret = 0; + struct bt_ctf_field_type_integer *length_type; + struct bt_ctf_field_integer *length; + struct bt_ctf_field_sequence *sequence; + uint64_t sequence_length; + + if (!field || !length_field || field->frozen) { + ret = -1; + goto end; + } + if (bt_ctf_field_type_get_type_id(length_field->type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + length_type = container_of(length_field->type, + struct bt_ctf_field_type_integer, parent); + /* The length field must be unsigned */ + if (length_type->declaration.signedness) { + ret = -1; + goto end; + } + + length = container_of(length_field, struct bt_ctf_field_integer, + parent); + sequence_length = length->definition.value._unsigned; + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + if (sequence->elements) { + g_ptr_array_free(sequence->elements, TRUE); + bt_put(sequence->length); + } + + sequence->elements = g_ptr_array_sized_new((size_t)sequence_length); + if (!sequence->elements) { + ret = -1; + goto end; + } + + g_ptr_array_set_free_func(sequence->elements, + (GDestroyNotify) bt_put); + g_ptr_array_set_size(sequence->elements, (size_t) sequence_length); + bt_get(length_field); + sequence->length = length_field; +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_field_structure_get_field( + struct bt_ctf_field *field, const char *name) +{ + struct bt_ctf_field *new_field = NULL; + GQuark field_quark; + struct bt_ctf_field_structure *structure; + struct bt_ctf_field_type *field_type = NULL; + size_t index; + + if (!field || !name || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRUCT) { + goto error; + } + + field_quark = g_quark_from_string(name); + structure = container_of(field, struct bt_ctf_field_structure, parent); + field_type = + bt_ctf_field_type_structure_get_field_type_by_name(field->type, + name); + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(field_quark), NULL, (gpointer *)&index)) { + goto error; + } + + if (structure->fields->pdata[index]) { + new_field = structure->fields->pdata[index]; + goto end; + } + + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + new_field = bt_ctf_field_create(field_type); + if (!new_field) { + goto error; + } + + structure->fields->pdata[index] = new_field; +end: + bt_get(new_field); +error: + if (field_type) { + bt_put(field_type); + } + return new_field; +} + +struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index( + struct bt_ctf_field *field, int index) +{ + int ret; + const char *field_name; + struct bt_ctf_field_structure *structure; + struct bt_ctf_field_type *structure_type; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field *ret_field = NULL; + + if (!field || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRUCT) { + goto end; + } + + structure = container_of(field, struct bt_ctf_field_structure, parent); + if (index >= structure->fields->len) { + goto error; + } + + ret_field = structure->fields->pdata[index]; + if (ret_field) { + goto end; + } + + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + /* Field has not been instanciated yet, create it */ + structure_type = bt_ctf_field_get_type(field); + if (!structure_type) { + goto error; + } + + ret = bt_ctf_field_type_structure_get_field(structure_type, + &field_name, &field_type, index); + bt_put(structure_type); + if (ret) { + goto error; + } + + ret_field = bt_ctf_field_create(field_type); + if (!ret_field) { + goto error; + } + + structure->fields->pdata[index] = ret_field; +end: + bt_get(ret_field); +error: + bt_put(field_type); + return ret_field; +} + +BT_HIDDEN +int bt_ctf_field_structure_set_field(struct bt_ctf_field *field, + const char *name, struct bt_ctf_field *value) +{ + int ret = 0; + GQuark field_quark; + struct bt_ctf_field_structure *structure; + struct bt_ctf_field_type *expected_field_type = NULL; + size_t index; + + if (!field || !name || !value || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + field_quark = g_quark_from_string(name); + structure = container_of(field, struct bt_ctf_field_structure, parent); + expected_field_type = + bt_ctf_field_type_structure_get_field_type_by_name(field->type, + name); + + if (bt_ctf_field_type_compare(expected_field_type, value->type)) { + ret = -1; + goto end; + } + + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(field_quark), NULL, (gpointer *) &index)) { + goto end; + } + + if (structure->fields->pdata[index]) { + bt_put(structure->fields->pdata[index]); + } + + structure->fields->pdata[index] = value; + bt_get(value); +end: + if (expected_field_type) { + bt_put(expected_field_type); + } + return ret; +} + +struct bt_ctf_field *bt_ctf_field_array_get_field(struct bt_ctf_field *field, + uint64_t index) +{ + struct bt_ctf_field *new_field = NULL; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field_array *array; + + if (!field || bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_ARRAY) { + goto end; + } + + array = container_of(field, struct bt_ctf_field_array, parent); + if (index >= array->elements->len) { + goto end; + } + + field_type = bt_ctf_field_type_array_get_element_type(field->type); + if (array->elements->pdata[(size_t)index]) { + new_field = array->elements->pdata[(size_t)index]; + goto end; + } + + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + new_field = bt_ctf_field_create(field_type); + array->elements->pdata[(size_t)index] = new_field; +end: + if (field_type) { + bt_put(field_type); + } + if (new_field) { + bt_get(new_field); + } + return new_field; +} + +struct bt_ctf_field *bt_ctf_field_sequence_get_field(struct bt_ctf_field *field, + uint64_t index) +{ + struct bt_ctf_field *new_field = NULL; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field_sequence *sequence; + + if (!field || bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_SEQUENCE) { + goto end; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + if (!sequence->elements || sequence->elements->len <= index) { + goto end; + } + + field_type = bt_ctf_field_type_sequence_get_element_type(field->type); + if (sequence->elements->pdata[(size_t) index]) { + new_field = sequence->elements->pdata[(size_t) index]; + goto end; + } + + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + new_field = bt_ctf_field_create(field_type); + sequence->elements->pdata[(size_t) index] = new_field; +end: + if (field_type) { + bt_put(field_type); + } + if (new_field) { + bt_get(new_field); + } + return new_field; +} + +struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field, + struct bt_ctf_field *tag_field) +{ + struct bt_ctf_field *new_field = NULL; + struct bt_ctf_field_variant *variant; + struct bt_ctf_field_type_variant *variant_type; + struct bt_ctf_field_type *field_type; + struct bt_ctf_field *tag_enum = NULL; + struct bt_ctf_field_integer *tag_enum_integer; + int64_t tag_enum_value; + + if (!field || !tag_field || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_VARIANT || + bt_ctf_field_type_get_type_id(tag_field->type) != + BT_CTF_TYPE_ID_ENUM) { + goto end; + } + + variant = container_of(field, struct bt_ctf_field_variant, parent); + variant_type = container_of(field->type, + struct bt_ctf_field_type_variant, parent); + tag_enum = bt_ctf_field_enumeration_get_container(tag_field); + if (!tag_enum) { + goto end; + } + + tag_enum_integer = container_of(tag_enum, struct bt_ctf_field_integer, + parent); + + if (bt_ctf_field_validate(tag_field) < 0) { + goto end; + } + + tag_enum_value = tag_enum_integer->definition.value._signed; + + /* + * If the variant currently has a tag and a payload, and if the + * requested tag value is the same as the current one, return + * the current payload instead of creating a fresh one. + */ + if (variant->tag && variant->payload) { + struct bt_ctf_field *cur_tag_container = NULL; + struct bt_ctf_field_integer *cur_tag_enum_integer; + int64_t cur_tag_value; + + cur_tag_container = + bt_ctf_field_enumeration_get_container(variant->tag); + assert(cur_tag_container); + cur_tag_enum_integer = container_of(cur_tag_container, + struct bt_ctf_field_integer, parent); + bt_put(cur_tag_container); + cur_tag_value = cur_tag_enum_integer->definition.value._signed; + + if (cur_tag_value == tag_enum_value) { + new_field = variant->payload; + bt_get(new_field); + goto end; + } + } + + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + field_type = bt_ctf_field_type_variant_get_field_type_signed( + variant_type, tag_enum_value); + if (!field_type) { + goto end; + } + + new_field = bt_ctf_field_create(field_type); + if (!new_field) { + goto end; + } + + bt_put(variant->tag); + bt_put(variant->payload); + bt_get(new_field); + bt_get(tag_field); + variant->tag = tag_field; + variant->payload = new_field; +end: + bt_put(tag_enum); + return new_field; +} + +struct bt_ctf_field *bt_ctf_field_variant_get_current_field( + struct bt_ctf_field *variant_field) +{ + struct bt_ctf_field *current_field = NULL; + struct bt_ctf_field_variant *variant; + + if (!variant_field || + bt_ctf_field_type_get_type_id(variant_field->type) != + BT_CTF_TYPE_ID_VARIANT) { + goto end; + } + + variant = container_of(variant_field, struct bt_ctf_field_variant, + parent); + + if (variant->payload) { + current_field = variant->payload; + bt_get(current_field); + goto end; + } + +end: + return current_field; +} + +struct bt_ctf_field *bt_ctf_field_enumeration_get_container( + struct bt_ctf_field *field) +{ + struct bt_ctf_field *container = NULL; + struct bt_ctf_field_enumeration *enumeration; + + if (!field || bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_ENUM) { + goto end; + } + + enumeration = container_of(field, struct bt_ctf_field_enumeration, + parent); + if (!enumeration->payload) { + /* We don't want to modify this field if it's frozen */ + if (field->frozen) { + goto end; + } + + struct bt_ctf_field_type_enumeration *enumeration_type = + container_of(field->type, + struct bt_ctf_field_type_enumeration, parent); + enumeration->payload = + bt_ctf_field_create(enumeration_type->container); + } + + container = enumeration->payload; + bt_get(container); +end: + return container; +} + +const char *bt_ctf_field_enumeration_get_mapping_name( + struct bt_ctf_field *field) +{ + int ret; + const char *name = NULL; + struct bt_ctf_field *container = NULL; + struct bt_ctf_field_type *container_type = NULL; + struct bt_ctf_field_type_integer *integer_type = NULL; + struct bt_ctf_field_type_enumeration *enumeration_type = NULL; + + container = bt_ctf_field_enumeration_get_container(field); + if (!container) { + goto end; + } + + container_type = bt_ctf_field_get_type(container); + if (!container_type) { + goto error_put_container; + } + + integer_type = container_of(container_type, + struct bt_ctf_field_type_integer, parent); + enumeration_type = container_of(field->type, + struct bt_ctf_field_type_enumeration, parent); + + if (!integer_type->declaration.signedness) { + uint64_t value; + ret = bt_ctf_field_unsigned_integer_get_value(container, + &value); + if (ret) { + goto error_put_container_type; + } + + name = bt_ctf_field_type_enumeration_get_mapping_name_unsigned( + enumeration_type, value); + } else { + int64_t value; + ret = bt_ctf_field_signed_integer_get_value(container, + &value); + if (ret) { + goto error_put_container_type; + } + + name = bt_ctf_field_type_enumeration_get_mapping_name_signed( + enumeration_type, value); + } + +error_put_container_type: + bt_put(container_type); +error_put_container: + bt_put(container); +end: + return name; +} + +int bt_ctf_field_signed_integer_get_value(struct bt_ctf_field *field, + int64_t *value) +{ + int ret = 0; + struct bt_ctf_field_integer *integer; + struct bt_ctf_field_type_integer *integer_type; + + if (!field || !value || !field->payload_set || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer_type = container_of(field->type, + struct bt_ctf_field_type_integer, parent); + if (!integer_type->declaration.signedness) { + ret = -1; + goto end; + } + + integer = container_of(field, + struct bt_ctf_field_integer, parent); + *value = integer->definition.value._signed; +end: + return ret; +} + +int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *field, + int64_t value) +{ + int ret = 0; + struct bt_ctf_field_integer *integer; + struct bt_ctf_field_type_integer *integer_type; + unsigned int size; + int64_t min_value, max_value; + + if (!field || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(field, struct bt_ctf_field_integer, parent); + integer_type = container_of(field->type, + struct bt_ctf_field_type_integer, parent); + if (!integer_type->declaration.signedness) { + ret = -1; + goto end; + } + + size = integer_type->declaration.len; + min_value = -(1ULL << (size - 1)); + max_value = (1ULL << (size - 1)) - 1; + if (value < min_value || value > max_value) { + ret = -1; + goto end; + } + + integer->definition.value._signed = value; + integer->parent.payload_set = 1; +end: + return ret; +} + +int bt_ctf_field_unsigned_integer_get_value(struct bt_ctf_field *field, + uint64_t *value) +{ + int ret = 0; + struct bt_ctf_field_integer *integer; + struct bt_ctf_field_type_integer *integer_type; + + if (!field || !value || !field->payload_set || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer_type = container_of(field->type, + struct bt_ctf_field_type_integer, parent); + if (integer_type->declaration.signedness) { + ret = -1; + goto end; + } + + integer = container_of(field, + struct bt_ctf_field_integer, parent); + *value = integer->definition.value._unsigned; +end: + return ret; +} + +int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *field, + uint64_t value) +{ + int ret = 0; + struct bt_ctf_field_integer *integer; + struct bt_ctf_field_type_integer *integer_type; + unsigned int size; + uint64_t max_value; + + if (!field || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(field, struct bt_ctf_field_integer, parent); + integer_type = container_of(field->type, + struct bt_ctf_field_type_integer, parent); + if (integer_type->declaration.signedness) { + ret = -1; + goto end; + } + + size = integer_type->declaration.len; + max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1; + if (value > max_value) { + ret = -1; + goto end; + } + + integer->definition.value._unsigned = value; + integer->parent.payload_set = 1; +end: + return ret; +} + +int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field, + double *value) +{ + int ret = 0; + struct bt_ctf_field_floating_point *floating_point; + + if (!field || !value || !field->payload_set || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_FLOAT) { + ret = -1; + goto end; + } + + floating_point = container_of(field, + struct bt_ctf_field_floating_point, parent); + *value = floating_point->definition.value; +end: + return ret; +} + +int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field, + double value) +{ + int ret = 0; + struct bt_ctf_field_floating_point *floating_point; + + if (!field || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_FLOAT) { + ret = -1; + goto end; + } + floating_point = container_of(field, struct bt_ctf_field_floating_point, + parent); + floating_point->definition.value = value; + floating_point->parent.payload_set = 1; +end: + return ret; +} + +const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field) +{ + const char *ret = NULL; + struct bt_ctf_field_string *string; + + if (!field || !field->payload_set || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRING) { + goto end; + } + + string = container_of(field, + struct bt_ctf_field_string, parent); + ret = string->payload->str; +end: + return ret; +} + +int bt_ctf_field_string_set_value(struct bt_ctf_field *field, + const char *value) +{ + int ret = 0; + struct bt_ctf_field_string *string; + + if (!field || !value || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRING) { + ret = -1; + goto end; + } + + string = container_of(field, struct bt_ctf_field_string, parent); + if (string->payload) { + g_string_assign(string->payload, value); + } else { + string->payload = g_string_new(value); + } + + string->parent.payload_set = 1; +end: + return ret; +} + +int bt_ctf_field_string_append(struct bt_ctf_field *field, + const char *value) +{ + int ret = 0; + struct bt_ctf_field_string *string_field; + + if (!field || !value || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRING) { + ret = -1; + goto end; + } + + string_field = container_of(field, struct bt_ctf_field_string, parent); + + if (string_field->payload) { + g_string_append(string_field->payload, value); + } else { + string_field->payload = g_string_new(value); + } + + string_field->parent.payload_set = 1; + +end: + return ret; +} + +int bt_ctf_field_string_append_len(struct bt_ctf_field *field, + const char *value, unsigned int length) +{ + int i; + int ret = 0; + unsigned int effective_length = length; + struct bt_ctf_field_string *string_field; + + if (!field || !value || field->frozen || + bt_ctf_field_type_get_type_id(field->type) != + BT_CTF_TYPE_ID_STRING) { + ret = -1; + goto end; + } + + string_field = container_of(field, struct bt_ctf_field_string, parent); + + /* make sure no null bytes are appended */ + for (i = 0; i < length; ++i) { + if (value[i] == '\0') { + effective_length = i; + break; + } + } + + if (string_field->payload) { + g_string_append_len(string_field->payload, value, + effective_length); + } else { + string_field->payload = g_string_new_len(value, + effective_length); + } + + string_field->parent.payload_set = 1; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_validate(struct bt_ctf_field *field) +{ + int ret = 0; + enum bt_ctf_type_id type_id; + + if (!field) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(field->type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || type_id >= BT_CTF_NR_TYPE_IDS) { + ret = -1; + goto end; + } + + ret = field_validate_funcs[type_id](field); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_reset(struct bt_ctf_field *field) +{ + int ret = 0; + enum bt_ctf_type_id type_id; + + if (!field) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(field->type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || type_id >= BT_CTF_NR_TYPE_IDS) { + ret = -1; + goto end; + } + + ret = field_reset_funcs[type_id](field); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + int ret = 0; + enum bt_ctf_type_id type_id; + + if (!field || !pos) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(field->type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || type_id >= BT_CTF_NR_TYPE_IDS) { + ret = -1; + goto end; + } + + ret = field_serialize_funcs[type_id](field, pos); +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field) +{ + int ret; + struct bt_ctf_field *copy = NULL; + enum bt_ctf_type_id type_id; + + if (!field) { + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(field->type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || type_id >= BT_CTF_NR_TYPE_IDS) { + goto end; + } + + copy = bt_ctf_field_create(field->type); + if (!copy) { + goto end; + } + + copy->payload_set = field->payload_set; + ret = field_copy_funcs[type_id](field, copy); + if (ret) { + bt_put(copy); + copy = NULL; + } +end: + return copy; +} + +static +struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_integer *integer_type = container_of(type, + struct bt_ctf_field_type_integer, parent); + struct bt_ctf_field_integer *integer = g_new0( + struct bt_ctf_field_integer, 1); + + if (integer) { + integer->definition.declaration = &integer_type->declaration; + } + + return integer ? &integer->parent : NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_enumeration_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_enumeration *enumeration = g_new0( + struct bt_ctf_field_enumeration, 1); + + return enumeration ? &enumeration->parent : NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_floating_point_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_floating_point *floating_point; + struct bt_ctf_field_type_floating_point *floating_point_type; + + floating_point = g_new0(struct bt_ctf_field_floating_point, 1); + if (!floating_point) { + goto end; + } + + floating_point_type = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + floating_point->definition.declaration = container_of( + type->declaration, struct declaration_float, p); + + + floating_point->definition.sign = &floating_point->sign; + floating_point->sign.declaration = &floating_point_type->sign; + floating_point->definition.sign->p.declaration = + &floating_point_type->sign.p; + + floating_point->definition.mantissa = &floating_point->mantissa; + floating_point->mantissa.declaration = &floating_point_type->mantissa; + floating_point->definition.mantissa->p.declaration = + &floating_point_type->mantissa.p; + + floating_point->definition.exp = &floating_point->exp; + floating_point->exp.declaration = &floating_point_type->exp; + floating_point->definition.exp->p.declaration = + &floating_point_type->exp.p; + +end: + return floating_point ? &floating_point->parent : NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_structure_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_structure *structure_type = container_of(type, + struct bt_ctf_field_type_structure, parent); + struct bt_ctf_field_structure *structure = g_new0( + struct bt_ctf_field_structure, 1); + struct bt_ctf_field *field = NULL; + + if (!structure) { + goto end; + } + + structure->field_name_to_index = structure_type->field_name_to_index; + structure->fields = g_ptr_array_new_with_free_func( + (GDestroyNotify)bt_ctf_field_put); + g_ptr_array_set_size(structure->fields, + g_hash_table_size(structure->field_name_to_index)); + field = &structure->parent; +end: + return field; +} + +static +struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_variant *variant = g_new0( + struct bt_ctf_field_variant, 1); + return variant ? &variant->parent : NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_array *array = g_new0(struct bt_ctf_field_array, 1); + struct bt_ctf_field_type_array *array_type; + unsigned int array_length; + + if (!array || !type) { + goto error; + } + + array_type = container_of(type, struct bt_ctf_field_type_array, parent); + array_length = array_type->length; + array->elements = g_ptr_array_sized_new(array_length); + if (!array->elements) { + goto error; + } + + g_ptr_array_set_free_func(array->elements, + (GDestroyNotify)bt_ctf_field_put); + g_ptr_array_set_size(array->elements, array_length); + return &array->parent; +error: + g_free(array); + return NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_sequence_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_sequence *sequence = g_new0( + struct bt_ctf_field_sequence, 1); + return sequence ? &sequence->parent : NULL; +} + +static +struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_string *string = g_new0( + struct bt_ctf_field_string, 1); + return string ? &string->parent : NULL; +} + +static +void bt_ctf_field_destroy(struct bt_object *obj) +{ + struct bt_ctf_field *field; + struct bt_ctf_field_type *type; + enum bt_ctf_type_id type_id; + + field = container_of(obj, struct bt_ctf_field, base); + type = field->type; + type_id = bt_ctf_field_type_get_type_id(type); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || + type_id >= BT_CTF_NR_TYPE_IDS) { + return; + } + + field_destroy_funcs[type_id](field); + bt_put(type); +} + +static +void bt_ctf_field_integer_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_integer *integer; + + if (!field) { + return; + } + + integer = container_of(field, struct bt_ctf_field_integer, parent); + g_free(integer); +} + +static +void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_enumeration *enumeration; + + if (!field) { + return; + } + + enumeration = container_of(field, struct bt_ctf_field_enumeration, + parent); + bt_put(enumeration->payload); + g_free(enumeration); +} + +static +void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_floating_point *floating_point; + + if (!field) { + return; + } + + floating_point = container_of(field, struct bt_ctf_field_floating_point, + parent); + g_free(floating_point); +} + +static +void bt_ctf_field_structure_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_structure *structure; + + if (!field) { + return; + } + + structure = container_of(field, struct bt_ctf_field_structure, parent); + g_ptr_array_free(structure->fields, TRUE); + g_free(structure); +} + +static +void bt_ctf_field_variant_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_variant *variant; + + if (!field) { + return; + } + + variant = container_of(field, struct bt_ctf_field_variant, parent); + bt_put(variant->tag); + bt_put(variant->payload); + g_free(variant); +} + +static +void bt_ctf_field_array_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_array *array; + + if (!field) { + return; + } + + array = container_of(field, struct bt_ctf_field_array, parent); + g_ptr_array_free(array->elements, TRUE); + g_free(array); +} + +static +void bt_ctf_field_sequence_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_sequence *sequence; + + if (!field) { + return; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + if (sequence->elements) { + g_ptr_array_free(sequence->elements, TRUE); + } + bt_put(sequence->length); + g_free(sequence); +} + +static +void bt_ctf_field_string_destroy(struct bt_ctf_field *field) +{ + struct bt_ctf_field_string *string; + if (!field) { + return; + } + + string = container_of(field, struct bt_ctf_field_string, parent); + if (string->payload) { + g_string_free(string->payload, TRUE); + } + g_free(string); +} + +static +int bt_ctf_field_generic_validate(struct bt_ctf_field *field) +{ + return (field && field->payload_set) ? 0 : -1; +} + +static +int bt_ctf_field_enumeration_validate(struct bt_ctf_field *field) +{ + int ret; + struct bt_ctf_field_enumeration *enumeration; + + if (!field) { + ret = -1; + goto end; + } + + enumeration = container_of(field, struct bt_ctf_field_enumeration, + parent); + if (!enumeration->payload) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_validate(enumeration->payload); +end: + return ret; +} + +static +int bt_ctf_field_structure_validate(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_structure *structure; + + if (!field) { + ret = -1; + goto end; + } + + structure = container_of(field, struct bt_ctf_field_structure, parent); + for (i = 0; i < structure->fields->len; i++) { + ret = bt_ctf_field_validate(structure->fields->pdata[i]); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_variant_validate(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_variant *variant; + + if (!field) { + ret = -1; + goto end; + } + + variant = container_of(field, struct bt_ctf_field_variant, parent); + ret = bt_ctf_field_validate(variant->payload); +end: + return ret; +} + +static +int bt_ctf_field_array_validate(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_array *array; + + if (!field) { + ret = -1; + goto end; + } + + array = container_of(field, struct bt_ctf_field_array, parent); + for (i = 0; i < array->elements->len; i++) { + ret = bt_ctf_field_validate(array->elements->pdata[i]); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_sequence_validate(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_sequence *sequence; + + if (!field) { + ret = -1; + goto end; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + for (i = 0; i < sequence->elements->len; i++) { + ret = bt_ctf_field_validate(sequence->elements->pdata[i]); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_generic_reset(struct bt_ctf_field *field) +{ + int ret = 0; + + if (!field) { + ret = -1; + goto end; + } + + field->payload_set = 0; +end: + return ret; +} + +static +int bt_ctf_field_enumeration_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_enumeration *enumeration; + + if (!field) { + ret = -1; + goto end; + } + + enumeration = container_of(field, struct bt_ctf_field_enumeration, + parent); + if (!enumeration->payload) { + goto end; + } + + ret = bt_ctf_field_reset(enumeration->payload); +end: + return ret; +} + +static +int bt_ctf_field_structure_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_structure *structure; + + if (!field) { + ret = -1; + goto end; + } + + structure = container_of(field, struct bt_ctf_field_structure, parent); + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field *member = structure->fields->pdata[i]; + + if (!member) { + /* + * Structure members are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_variant_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_variant *variant; + + if (!field) { + ret = -1; + goto end; + } + + variant = container_of(field, struct bt_ctf_field_variant, parent); + if (variant->payload) { + ret = bt_ctf_field_reset(variant->payload); + } +end: + return ret; +} + +static +int bt_ctf_field_array_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_array *array; + + if (!field) { + ret = -1; + goto end; + } + + array = container_of(field, struct bt_ctf_field_array, parent); + for (i = 0; i < array->elements->len; i++) { + struct bt_ctf_field *member = array->elements->pdata[i]; + + if (!member) { + /* + * Array elements are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_sequence_reset(struct bt_ctf_field *field) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_sequence *sequence; + + if (!field) { + ret = -1; + goto end; + } + + sequence = container_of(field, struct bt_ctf_field_sequence, parent); + for (i = 0; i < sequence->elements->len; i++) { + struct bt_ctf_field *member = sequence->elements->pdata[i]; + + if (!member) { + /* + * Sequence elements are lazily initialized; skip if + * this member has not been allocated yet. + */ + continue; + } + + ret = bt_ctf_field_reset(member); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_string_reset(struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_string *string; + + if (!field) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_generic_reset(field); + if (ret) { + goto end; + } + + string = container_of(field, struct bt_ctf_field_string, parent); + if (string->payload) { + g_string_truncate(string->payload, 0); + } +end: + return ret; +} + +static +int bt_ctf_field_integer_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + int ret = 0; + struct bt_ctf_field_integer *integer = container_of(field, + struct bt_ctf_field_integer, parent); + +retry: + ret = ctf_integer_write(&pos->parent, &integer->definition.p); + if (ret == -EFAULT) { + /* + * The field is too large to fit in the current packet's + * remaining space. Bump the packet size and retry. + */ + ret = increase_packet_size(pos); + if (ret) { + goto end; + } + goto retry; + } +end: + return ret; +} + +static +int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + struct bt_ctf_field_enumeration *enumeration = container_of( + field, struct bt_ctf_field_enumeration, parent); + + return bt_ctf_field_serialize(enumeration->payload, pos); +} + +static +int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + int ret = 0; + struct bt_ctf_field_floating_point *floating_point = container_of(field, + struct bt_ctf_field_floating_point, parent); + +retry: + ret = ctf_float_write(&pos->parent, &floating_point->definition.p); + if (ret == -EFAULT) { + /* + * The field is too large to fit in the current packet's + * remaining space. Bump the packet size and retry. + */ + ret = increase_packet_size(pos); + if (ret) { + goto end; + } + goto retry; + } +end: + return ret; +} + +static +int bt_ctf_field_structure_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_structure *structure = container_of( + field, struct bt_ctf_field_structure, parent); + + while (!ctf_pos_access_ok(pos, + offset_align(pos->offset, + field->type->declaration->alignment))) { + ret = increase_packet_size(pos); + if (ret) { + goto end; + } + } + + if (!ctf_align_pos(pos, field->type->declaration->alignment)) { + ret = -1; + goto end; + } + + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field *field = g_ptr_array_index( + structure->fields, i); + + ret = bt_ctf_field_serialize(field, pos); + if (ret) { + break; + } + } +end: + return ret; +} + +static +int bt_ctf_field_variant_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + struct bt_ctf_field_variant *variant = container_of( + field, struct bt_ctf_field_variant, parent); + + return bt_ctf_field_serialize(variant->payload, pos); +} + +static +int bt_ctf_field_array_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_array *array = container_of( + field, struct bt_ctf_field_array, parent); + + for (i = 0; i < array->elements->len; i++) { + ret = bt_ctf_field_serialize( + g_ptr_array_index(array->elements, i), pos); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_sequence_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_sequence *sequence = container_of( + field, struct bt_ctf_field_sequence, parent); + + for (i = 0; i < sequence->elements->len; i++) { + ret = bt_ctf_field_serialize( + g_ptr_array_index(sequence->elements, i), pos); + if (ret) { + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_string_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_string *string = container_of(field, + struct bt_ctf_field_string, parent); + struct bt_ctf_field_type *character_type = + get_field_type(FIELD_TYPE_ALIAS_UINT8_T); + struct bt_ctf_field *character = bt_ctf_field_create(character_type); + + for (i = 0; i < string->payload->len + 1; i++) { + ret = bt_ctf_field_unsigned_integer_set_value(character, + (uint64_t) string->payload->str[i]); + if (ret) { + goto end; + } + + ret = bt_ctf_field_integer_serialize(character, pos); + if (ret) { + goto end; + } + } +end: + bt_put(character); + bt_put(character_type); + return ret; +} + +static +int bt_ctf_field_integer_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + struct bt_ctf_field_integer *integer_src, *integer_dst; + + integer_src = container_of(src, struct bt_ctf_field_integer, parent); + integer_dst = container_of(dst, struct bt_ctf_field_integer, parent); + + memcpy(&integer_dst->definition, &integer_src->definition, + sizeof(struct definition_integer)); + return 0; +} + +static +int bt_ctf_field_enumeration_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0; + struct bt_ctf_field_enumeration *enum_src, *enum_dst; + + enum_src = container_of(src, struct bt_ctf_field_enumeration, parent); + enum_dst = container_of(dst, struct bt_ctf_field_enumeration, parent); + + if (enum_src->payload) { + enum_dst->payload = bt_ctf_field_copy(enum_src->payload); + if (!enum_dst->payload) { + ret = -1; + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_floating_point_copy( + struct bt_ctf_field *src, struct bt_ctf_field *dst) +{ + struct bt_ctf_field_floating_point *float_src, *float_dst; + + float_src = container_of(src, struct bt_ctf_field_floating_point, + parent); + float_dst = container_of(dst, struct bt_ctf_field_floating_point, + parent); + + memcpy(&float_dst->definition, &float_src->definition, + sizeof(struct definition_float)); + memcpy(&float_dst->sign, &float_src->sign, + sizeof(struct definition_integer)); + memcpy(&float_dst->mantissa, &float_src->mantissa, + sizeof(struct definition_integer)); + memcpy(&float_dst->exp, &float_src->exp, + sizeof(struct definition_integer)); + return 0; +} + +static +int bt_ctf_field_structure_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0, i; + struct bt_ctf_field_structure *struct_src, *struct_dst; + + struct_src = container_of(src, struct bt_ctf_field_structure, parent); + struct_dst = container_of(dst, struct bt_ctf_field_structure, parent); + + /* This field_name_to_index HT is owned by the structure field type */ + struct_dst->field_name_to_index = struct_src->field_name_to_index; + g_ptr_array_set_size(struct_dst->fields, struct_src->fields->len); + + for (i = 0; i < struct_src->fields->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(struct_src->fields, i); + struct bt_ctf_field *field_copy = NULL; + + if (field) { + field_copy = bt_ctf_field_copy(field); + + if (!field_copy) { + ret = -1; + goto end; + } + } + + g_ptr_array_index(struct_dst->fields, i) = field_copy; + } +end: + return ret; +} + +static +int bt_ctf_field_variant_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0; + struct bt_ctf_field_variant *variant_src, *variant_dst; + + variant_src = container_of(src, struct bt_ctf_field_variant, parent); + variant_dst = container_of(dst, struct bt_ctf_field_variant, parent); + + if (variant_src->tag) { + variant_dst->tag = bt_ctf_field_copy(variant_src->tag); + if (!variant_dst->tag) { + ret = -1; + goto end; + } + } + if (variant_src->payload) { + variant_dst->payload = bt_ctf_field_copy(variant_src->payload); + if (!variant_dst->payload) { + ret = -1; + goto end; + } + } +end: + return ret; +} + +static +int bt_ctf_field_array_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0, i; + struct bt_ctf_field_array *array_src, *array_dst; + + array_src = container_of(src, struct bt_ctf_field_array, parent); + array_dst = container_of(dst, struct bt_ctf_field_array, parent); + + g_ptr_array_set_size(array_dst->elements, array_src->elements->len); + for (i = 0; i < array_src->elements->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(array_src->elements, i); + struct bt_ctf_field *field_copy = NULL; + + if (field) { + field_copy = bt_ctf_field_copy(field); + + if (!field_copy) { + ret = -1; + goto end; + } + } + + g_ptr_array_index(array_dst->elements, i) = field_copy; + } +end: + return ret; +} + +static +int bt_ctf_field_sequence_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0, i; + struct bt_ctf_field_sequence *sequence_src, *sequence_dst; + struct bt_ctf_field *src_length; + struct bt_ctf_field *dst_length; + + sequence_src = container_of(src, struct bt_ctf_field_sequence, parent); + sequence_dst = container_of(dst, struct bt_ctf_field_sequence, parent); + + src_length = bt_ctf_field_sequence_get_length(src); + + if (!src_length) { + /* no length set yet: keep destination sequence empty */ + goto end; + } + + /* copy source length */ + dst_length = bt_ctf_field_copy(src_length); + bt_put(src_length); + + if (!dst_length) { + ret = -1; + goto end; + } + + /* this will initialize the destination sequence's internal array */ + ret = bt_ctf_field_sequence_set_length(dst, dst_length); + bt_put(dst_length); + + if (ret) { + goto end; + } + + assert(sequence_dst->elements->len == sequence_src->elements->len); + + for (i = 0; i < sequence_src->elements->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(sequence_src->elements, i); + struct bt_ctf_field *field_copy = NULL; + + if (field) { + field_copy = bt_ctf_field_copy(field); + + if (!field_copy) { + ret = -1; + goto end; + } + } + + g_ptr_array_index(sequence_dst->elements, i) = field_copy; + } +end: + return ret; +} + +static +int bt_ctf_field_string_copy(struct bt_ctf_field *src, + struct bt_ctf_field *dst) +{ + int ret = 0; + struct bt_ctf_field_string *string_src, *string_dst; + + string_src = container_of(src, struct bt_ctf_field_string, parent); + string_dst = container_of(dst, struct bt_ctf_field_string, parent); + + if (string_src->payload) { + string_dst->payload = g_string_new(string_src->payload->str); + if (!string_dst->payload) { + ret = -1; + goto end; + } + } +end: + return ret; +} + +static +int increase_packet_size(struct ctf_stream_pos *pos) +{ + int ret; + + assert(pos); + ret = munmap_align(pos->base_mma); + if (ret) { + goto end; + } + + pos->packet_size += PACKET_LEN_INCREMENT; + do { + ret = bt_posix_fallocate(pos->fd, pos->mmap_offset, + pos->packet_size / CHAR_BIT); + } while (ret == EINTR); + if (ret) { + errno = EINTR; + ret = -1; + goto end; + } + + pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot, + pos->flags, pos->fd, pos->mmap_offset); + if (pos->base_mma == MAP_FAILED) { + ret = -1; + } +end: + return ret; +} + +static +void generic_field_freeze(struct bt_ctf_field *field) +{ + field->frozen = 1; +} + +static +void bt_ctf_field_enumeration_freeze(struct bt_ctf_field *field) +{ + struct bt_ctf_field_enumeration *enum_field = + container_of(field, struct bt_ctf_field_enumeration, parent); + + bt_ctf_field_freeze(enum_field->payload); + generic_field_freeze(field); +} + +static +void bt_ctf_field_structure_freeze(struct bt_ctf_field *field) +{ + int i; + struct bt_ctf_field_structure *structure_field = + container_of(field, struct bt_ctf_field_structure, parent); + + for (i = 0; i < structure_field->fields->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(structure_field->fields, i); + + bt_ctf_field_freeze(field); + } + + generic_field_freeze(field); +} + +static +void bt_ctf_field_variant_freeze(struct bt_ctf_field *field) +{ + struct bt_ctf_field_variant *variant_field = + container_of(field, struct bt_ctf_field_variant, parent); + + bt_ctf_field_freeze(variant_field->tag); + bt_ctf_field_freeze(variant_field->payload); + generic_field_freeze(field); +} + +static +void bt_ctf_field_array_freeze(struct bt_ctf_field *field) +{ + int i; + struct bt_ctf_field_array *array_field = + container_of(field, struct bt_ctf_field_array, parent); + + for (i = 0; i < array_field->elements->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(array_field->elements, i); + + bt_ctf_field_freeze(field); + } + + generic_field_freeze(field); +} + +static +void bt_ctf_field_sequence_freeze(struct bt_ctf_field *field) +{ + int i; + struct bt_ctf_field_sequence *sequence_field = + container_of(field, struct bt_ctf_field_sequence, parent); + + bt_ctf_field_freeze(sequence_field->length); + + for (i = 0; i < sequence_field->elements->len; i++) { + struct bt_ctf_field *field = + g_ptr_array_index(sequence_field->elements, i); + + bt_ctf_field_freeze(field); + } + + generic_field_freeze(field); +} + +BT_HIDDEN +void bt_ctf_field_freeze(struct bt_ctf_field *field) +{ + enum bt_ctf_type_id type_id; + + if (!field) { + goto end; + } + + type_id = bt_ctf_field_get_type_id(field); + if (type_id <= BT_CTF_TYPE_ID_UNKNOWN || + type_id >= BT_CTF_NR_TYPE_IDS) { + goto end; + } + + field_freeze_funcs[type_id](field); +end: + return; +} diff --git a/formats/ctf/ir/packet.c b/formats/ctf/ir/packet.c new file mode 100644 index 00000000..59e193fc --- /dev/null +++ b/formats/ctf/ir/packet.c @@ -0,0 +1,197 @@ +/* + * packet.c + * + * Babeltrace CTF IR - Stream packet + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bt_ctf_stream *bt_ctf_packet_get_stream(struct bt_ctf_packet *packet) +{ + return packet ? bt_get(packet->stream) : NULL; +} + +struct bt_ctf_field *bt_ctf_packet_get_header( + struct bt_ctf_packet *packet) +{ + return packet ? bt_get(packet->header) : NULL; +} + +int bt_ctf_packet_set_header(struct bt_ctf_packet *packet, + struct bt_ctf_field *header) +{ + int ret = 0; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_field_type *header_field_type = NULL; + struct bt_ctf_field_type *expected_header_field_type = NULL; + + if (!packet || !header || packet->frozen) { + ret = -1; + goto end; + } + + stream_class = bt_ctf_stream_get_class(packet->stream); + assert(stream_class); + trace = bt_ctf_stream_class_get_trace(stream_class); + assert(trace); + header_field_type = bt_ctf_field_get_type(header); + assert(header_field_type); + expected_header_field_type = bt_ctf_trace_get_packet_header_type(trace); + + if (bt_ctf_field_type_compare(header_field_type, + expected_header_field_type)) { + ret = -1; + goto end; + } + + bt_put(packet->header); + packet->header = bt_get(header); + +end: + BT_PUT(trace); + BT_PUT(stream_class); + BT_PUT(header_field_type); + BT_PUT(expected_header_field_type); + + return ret; +} + +struct bt_ctf_field *bt_ctf_packet_get_context( + struct bt_ctf_packet *packet) +{ + return packet ? bt_get(packet->context) : NULL; +} + +int bt_ctf_packet_set_context(struct bt_ctf_packet *packet, + struct bt_ctf_field *context) +{ + int ret = 0; + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_field_type *context_field_type = NULL; + struct bt_ctf_field_type *expected_context_field_type = NULL; + + if (!packet || !context || packet->frozen) { + ret = -1; + goto end; + } + + stream_class = bt_ctf_stream_get_class(packet->stream); + assert(stream_class); + context_field_type = bt_ctf_field_get_type(context); + assert(context_field_type); + expected_context_field_type = + bt_ctf_stream_class_get_packet_context_type(stream_class); + + if (bt_ctf_field_type_compare(context_field_type, + expected_context_field_type)) { + ret = -1; + goto end; + } + + bt_put(packet->context); + packet->context = bt_get(context); + +end: + BT_PUT(stream_class); + BT_PUT(context_field_type); + BT_PUT(expected_context_field_type); + + return ret; +} + +BT_HIDDEN +void bt_ctf_packet_freeze(struct bt_ctf_packet *packet) +{ + if (!packet) { + return; + } + + bt_ctf_field_freeze(packet->header); + bt_ctf_field_freeze(packet->context); + packet->frozen = 1; +} + +static +void bt_ctf_packet_destroy(struct bt_object *obj) +{ + struct bt_ctf_packet *packet; + + packet = container_of(obj, struct bt_ctf_packet, base); + bt_put(packet->header); + bt_put(packet->context); + bt_put(packet->stream); + g_free(packet); +} + +struct bt_ctf_packet *bt_ctf_packet_create( + struct bt_ctf_stream *stream) +{ + struct bt_ctf_packet *packet = NULL; + struct bt_ctf_stream_class *stream_class = NULL; + struct bt_ctf_trace *trace = NULL; + + if (!stream || stream->pos.fd >= 0) { + goto end; + } + + stream_class = bt_ctf_stream_get_class(stream); + assert(stream_class); + trace = bt_ctf_stream_class_get_trace(stream_class); + assert(trace); + packet = g_new0(struct bt_ctf_packet, 1); + if (!packet) { + goto end; + } + + bt_object_init(packet, bt_ctf_packet_destroy); + packet->stream = bt_get(stream); + packet->header = bt_ctf_field_create(trace->packet_header_type); + if (!packet->header) { + BT_PUT(packet); + goto end; + } + + packet->context = bt_ctf_field_create( + stream->stream_class->packet_context_type); + if (!packet->context) { + BT_PUT(packet); + goto end; + } + +end: + BT_PUT(trace); + BT_PUT(stream_class); + + return packet; +} diff --git a/formats/ctf/ir/resolve.c b/formats/ctf/ir/resolve.c new file mode 100644 index 00000000..4bc4130f --- /dev/null +++ b/formats/ctf/ir/resolve.c @@ -0,0 +1,1193 @@ +/* + * resolve.c + * + * Babeltrace - CTF IR: Type resolving internal + * + * Copyright 2015 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * Authors: Jérémie Galarneau + * Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _printf_error(fmt, args...) \ + printf_verbose("[resolving] " fmt, ## args) + +typedef GPtrArray type_stack; + +/* + * A stack frame. + * + * `type` contains a compound field type (structure, variant, array, + * or sequence) and `index` indicates the index of the field type in + * the upper frame (-1 for array and sequence field types). + * + * `type` is owned by the stack frame. + */ +struct type_stack_frame { + struct bt_ctf_field_type *type; + int index; +}; + +/* + * The current context of the resolving engine. + * + * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2) + * in the following order: + * + * * Packet header + * * Packet context + * * Event header + * * Stream event context + * * Event context + * * Event payload + */ +struct resolve_context { + struct bt_value *environment; + struct bt_ctf_field_type *scopes[6]; + + /* Root scope being visited */ + enum bt_ctf_scope root_scope; + type_stack *type_stack; + struct bt_ctf_field_type *cur_field_type; +}; + +/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */ +static const char * const absolute_path_prefixes[] = { + [BT_CTF_SCOPE_ENV] = "env.", + [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = "trace.packet.header.", + [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = "stream.packet.context.", + [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = "stream.event.header.", + [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = "stream.event.context.", + [BT_CTF_SCOPE_EVENT_CONTEXT] = "event.context.", + [BT_CTF_SCOPE_EVENT_FIELDS] = "event.fields.", +}; + +/* Number of path tokens used for the absolute prefixes */ +static const int absolute_path_prefix_ptoken_counts[] = { + [BT_CTF_SCOPE_ENV] = 1, + [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = 3, + [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = 3, + [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = 3, + [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = 3, + [BT_CTF_SCOPE_EVENT_CONTEXT] = 2, + [BT_CTF_SCOPE_EVENT_FIELDS] = 2, +}; + +/* + * Destroys a type stack frame. + */ +static +void type_stack_destroy_notify(gpointer data) +{ + struct type_stack_frame *frame = data; + + BT_PUT(frame->type); + g_free(frame); +} + +/* + * Creates a type stack. + * + * Return value is owned by the caller. + */ +static +type_stack *type_stack_create(void) +{ + return g_ptr_array_new_with_free_func(type_stack_destroy_notify); +} + +/* + * Destroys a type stack. + */ +static +void type_stack_destroy(type_stack *stack) +{ + g_ptr_array_free(stack, TRUE); +} + +/* + * Pushes a field type onto a type stack. + * + * `type` is owned by the caller (stack frame gets a new reference). + */ +static +int type_stack_push(type_stack *stack, struct bt_ctf_field_type *type) +{ + int ret = 0; + struct type_stack_frame *frame = NULL; + + if (!stack || !type) { + ret = -1; + goto end; + } + + frame = g_new0(struct type_stack_frame, 1); + if (!frame) { + ret = -1; + goto end; + } + + frame->type = bt_get(type); + g_ptr_array_add(stack, frame); + +end: + return ret; +} + +/* + * Checks whether or not `stack` is empty. + */ +static +bool type_stack_empty(type_stack *stack) +{ + return stack->len == 0; +} + +/* + * Returns the number of frames in `stack`. + */ +static +size_t type_stack_size(type_stack *stack) +{ + return stack->len; +} + +/* + * Returns the top frame of `stack`. + * + * Return value is owned by `stack`. + */ +static +struct type_stack_frame *type_stack_peek(type_stack *stack) +{ + struct type_stack_frame *entry = NULL; + + if (!stack || type_stack_empty(stack)) { + goto end; + } + + entry = g_ptr_array_index(stack, stack->len - 1); +end: + return entry; +} + +/* + * Returns the frame at index `index` in `stack`. + * + * Return value is owned by `stack`. + */ +static +struct type_stack_frame *type_stack_at(type_stack *stack, + size_t index) +{ + struct type_stack_frame *entry = NULL; + + if (!stack || index >= stack->len) { + goto end; + } + + entry = g_ptr_array_index(stack, index); + +end: + return entry; +} + +/* + * Removes the top frame of `stack`. + */ +static +void type_stack_pop(type_stack *stack) +{ + if (!type_stack_empty(stack)) { + /* + * This will call the frame's destructor and free it, as + * well as put its contained field type. + */ + g_ptr_array_set_size(stack, stack->len - 1); + } +} + +/* + * Returns the scope field type of `scope` in the context `ctx`. + * + * Return value is owned by `ctx` on success. + */ +static +struct bt_ctf_field_type *get_type_from_ctx(struct resolve_context *ctx, + enum bt_ctf_scope scope) +{ + assert(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER && + scope <= BT_CTF_SCOPE_EVENT_FIELDS); + + return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER]; +} + +/* + * Returns the CTF scope from a path string. May return + * CTF_NODE_UNKNOWN if the path is found to be relative. + */ +static +enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr) +{ + enum bt_ctf_scope scope; + enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN; + const size_t prefixes_count = sizeof(absolute_path_prefixes) / + sizeof(*absolute_path_prefixes); + + for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV + + prefixes_count; scope++) { + /* + * Chech if path string starts with a known absolute + * path prefix. + * + * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES. + */ + if (strncmp(pathstr, absolute_path_prefixes[scope], + strlen(absolute_path_prefixes[scope]))) { + /* Prefix does not match: try the next one */ + continue; + } + + /* Found it! */ + ret = scope; + goto end; + } + +end: + return ret; +} + +/* + * Destroys a path token. + */ +static +void ptokens_destroy_func(gpointer ptoken, gpointer data) +{ + g_string_free(ptoken, TRUE); +} + +/* + * Destroys a path token list. + */ +static +void ptokens_destroy(GList *ptokens) +{ + if (!ptokens) { + return; + } + + g_list_foreach(ptokens, ptokens_destroy_func, NULL); + g_list_free(ptokens); +} + +/* + * Returns the string contained in a path token. + */ +static +const char *ptoken_get_string(GList *ptoken) +{ + GString *tokenstr = (GString *) ptoken->data; + + return tokenstr->str; +} + +/* + * Converts a path string to a path token list, that is, splits the + * individual words of a path string into a list of individual + * strings. + * + * Return value is owned by the caller on success. + */ +static +GList *pathstr_to_ptokens(const char *pathstr) +{ + const char *at = pathstr; + const char *last = at; + GList *ptokens = NULL; + + for (;;) { + if (*at == '.' || *at == '\0') { + GString *tokenstr; + + if (at == last) { + /* Error: empty token */ + _printf_error("Empty token in path string at position %d\n", + (int) (at - pathstr)); + goto error; + } + + tokenstr = g_string_new(NULL); + g_string_append_len(tokenstr, last, at - last); + ptokens = g_list_append(ptokens, tokenstr); + last = at + 1; + } + + if (*at == '\0') { + break; + } + + at++; + } + + return ptokens; + +error: + ptokens_destroy(ptokens); + return NULL; +} + +/* + * Converts a path token list to a field path object. The path token + * list is relative from `type`. The index of the source looking for + * its target within `type` is indicated by `src_index`. This can be + * `INT_MAX` if the source is contained in `type`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. `type` is owned by the + * caller. + */ +static +int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path, + struct bt_ctf_field_type *type, int src_index) +{ + int ret = 0; + GList *cur_ptoken = ptokens; + bool first_level_done = false; + + /* Get our own reference */ + bt_get(type); + + /* Locate target */ + while (cur_ptoken) { + int child_index; + struct bt_ctf_field_type *child_type; + const char *field_name = ptoken_get_string(cur_ptoken); + enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type); + + /* Find to which index corresponds the current path token */ + if (type_id == CTF_TYPE_ARRAY || type_id == CTF_TYPE_SEQUENCE) { + child_index = -1; + } else { + child_index = bt_ctf_field_type_get_field_index(type, + field_name); + if (child_index < 0) { + /* + * Error: field name does not exist or + * wrong current type. + */ + _printf_error("Cannot get index of field type named \"%s\"\n", + field_name); + ret = -1; + goto end; + } else if (child_index > src_index && + !first_level_done) { + _printf_error("Child type is located after source index (%d)\n", + src_index); + ret = -1; + goto end; + } + + /* Next path token */ + cur_ptoken = g_list_next(cur_ptoken); + first_level_done = true; + } + + /* Create new field path entry */ + g_array_append_val(field_path->indexes, child_index); + + /* Get child field type */ + child_type = bt_ctf_field_type_get_field_at_index(type, + child_index); + if (!child_type) { + _printf_error("Cannot get child type at index %d (field \"%s\")\n", + child_index, field_name); + ret = -1; + goto end; + } + + /* Move child type to current type */ + BT_MOVE(type, child_type); + } + +end: + bt_put(type); + return ret; +} + +/* + * Converts a known absolute path token list to a field path object + * within the resolving context `ctx`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. + */ +static +int absolute_ptokens_to_field_path(GList *ptokens, + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + GList *cur_ptoken; + struct bt_ctf_field_type *type; + + /* Skip absolute path tokens */ + cur_ptoken = g_list_nth(ptokens, + absolute_path_prefix_ptoken_counts[field_path->root]); + + /* Start with root type */ + type = get_type_from_ctx(ctx, field_path->root); + if (!type) { + /* Error: root type is not available */ + _printf_error("Root type with scope type %d is not available\n", + field_path->root); + ret = -1; + goto end; + } + + /* Locate target */ + ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX); + +end: + return ret; +} + +/* + * Converts a known relative path token list to a field path object + * within the resolving context `ctx`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. + */ +static +int relative_ptokens_to_field_path(GList *ptokens, + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + int parent_pos_in_stack; + struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create(); + + if (!tail_field_path) { + _printf_error("Cannot create field path\n"); + ret = -1; + goto end; + } + + parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1; + + while (parent_pos_in_stack >= 0) { + struct bt_ctf_field_type *parent_type = + type_stack_at(ctx->type_stack, + parent_pos_in_stack)->type; + int cur_index = type_stack_at(ctx->type_stack, + parent_pos_in_stack)->index; + + /* Locate target from current parent type */ + ret = ptokens_to_field_path(ptokens, tail_field_path, + parent_type, cur_index); + if (ret) { + /* Not found... yet */ + bt_ctf_field_path_clear(tail_field_path); + } else { + /* Found: stitch tail field path to head field path */ + int i = 0; + int tail_field_path_len = + tail_field_path->indexes->len; + + while (true) { + struct bt_ctf_field_type *cur_type = + type_stack_at(ctx->type_stack, i)->type; + int index = type_stack_at( + ctx->type_stack, i)->index; + + if (cur_type == parent_type) { + break; + } + + g_array_append_val(field_path->indexes, + index); + i++; + } + + for (i = 0; i < tail_field_path_len; i++) { + int index = g_array_index( + tail_field_path->indexes, + int, i); + + g_array_append_val(field_path->indexes, + index); + } + break; + } + + parent_pos_in_stack--; + } + + if (parent_pos_in_stack < 0) { + /* Not found: look in previous scopes */ + field_path->root--; + + while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) { + struct bt_ctf_field_type *root_type; + bt_ctf_field_path_clear(field_path); + + root_type = get_type_from_ctx(ctx, field_path->root); + if (!root_type) { + field_path->root--; + continue; + } + + /* Locate target in previous scope */ + ret = ptokens_to_field_path(ptokens, field_path, + root_type, INT_MAX); + if (ret) { + /* Not found yet */ + field_path->root--; + continue; + } + + /* Found */ + break; + } + } + +end: + BT_PUT(tail_field_path); + return ret; +} + +/* + * Converts a path string to a field path object within the resolving + * context `ctx`. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr, + struct resolve_context *ctx) +{ + int ret; + enum bt_ctf_scope root_scope; + GList *ptokens = NULL; + struct bt_ctf_field_path *field_path = NULL; + + /* Create field path */ + field_path = bt_ctf_field_path_create(); + if (!field_path) { + _printf_error("Cannot create field path\n"); + ret = -1; + goto end; + } + + /* Convert path string to path tokens */ + ptokens = pathstr_to_ptokens(pathstr); + if (!ptokens) { + _printf_error("Cannot convert path string \"%s\" to path tokens\n", + pathstr); + ret = -1; + goto end; + } + + /* Absolute or relative path? */ + root_scope = get_root_scope_from_absolute_pathstr(pathstr); + + if (root_scope == BT_CTF_SCOPE_UNKNOWN) { + /* Relative path: start with current root scope */ + field_path->root = ctx->root_scope; + ret = relative_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + _printf_error("Cannot get relative field path of path string \"%s\"\n", + pathstr); + _printf_error(" Starting at root scope %d, finished at root scope %d\n", + ctx->root_scope, field_path->root); + goto end; + } + } else if (root_scope == BT_CTF_SCOPE_ENV) { + _printf_error("Sequence field types referring the trace environment are not supported as of this version\n"); + ret = -1; + goto end; + } else { + /* Absolute path: use found root scope */ + field_path->root = root_scope; + ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + _printf_error("Cannot get absolute field path of path string \"%s\"\n", + pathstr); + _printf_error(" Looking in root scope %d\n", root_scope); + goto end; + } + } + +end: + if (ret) { + BT_PUT(field_path); + } + + ptokens_destroy(ptokens); + + return field_path; +} + +/* + * Retrieves a field type by following the field path `field_path` in + * the resolving context `ctx`. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_type *field_path_to_field_type( + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int i; + struct bt_ctf_field_type *type; + + /* Start with root type */ + type = get_type_from_ctx(ctx, field_path->root); + bt_get(type); + if (!type) { + /* Error: root type is not available */ + _printf_error("Root type with scope type %d is not available\n", + field_path->root); + goto error; + } + + /* Locate target */ + for (i = 0; i < field_path->indexes->len; i++) { + struct bt_ctf_field_type *child_type; + int child_index = + g_array_index(field_path->indexes, int, i); + + /* Get child field type */ + child_type = bt_ctf_field_type_get_field_at_index(type, + child_index); + if (!child_type) { + _printf_error("Cannot get field type field at index %d\n", + child_index); + goto error; + } + + /* Move child type to current type */ + BT_MOVE(type, child_type); + } + + return type; + +error: + BT_PUT(type); + return type; +} + +/* + * Returns the equivalent field path object of the context type stack. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx) +{ + int i; + struct bt_ctf_field_path *field_path; + + /* Create field path */ + field_path = bt_ctf_field_path_create(); + if (!field_path) { + _printf_error("Cannot create field path\n"); + goto error; + } + + field_path->root = ctx->root_scope; + + for (i = 0; i < type_stack_size(ctx->type_stack); i++) { + struct type_stack_frame *frame; + + frame = type_stack_at(ctx->type_stack, i); + g_array_append_val(field_path->indexes, frame->index); + } + + return field_path; + +error: + BT_PUT(field_path); + return field_path; +} + +/* + * Returns the lowest common ancestor of two field path objects + * having the same root scope. + * + * `field_path1` and `field_path2` are owned by the caller. + */ +int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1, + struct bt_ctf_field_path *field_path2) +{ + int lca_index = 0; + int field_path1_len, field_path2_len; + + /* + * Start from both roots and find the first mismatch. + */ + assert(field_path1->root == field_path2->root); + field_path1_len = field_path1->indexes->len; + field_path2_len = field_path2->indexes->len; + + while (true) { + int target_index, ctx_index; + + if (lca_index == field_path2_len || + lca_index == field_path1_len) { + /* + * This means that both field paths never split. + * This is invalid because the target cannot be + * an ancestor of the source. + */ + _printf_error("In source and target: one is an ancestor of the other\n"); + lca_index = -1; + break; + } + + target_index = g_array_index(field_path1->indexes, int, + lca_index); + ctx_index = g_array_index(field_path2->indexes, int, + lca_index); + + if (target_index != ctx_index) { + /* LCA index is the previous */ + break; + } + + lca_index++; + } + + return lca_index; +} + +/* + * Validates a target field path. + * + * `target_field_path` and `target_type` are owned by the caller. + */ +static +int validate_target_field_path(struct bt_ctf_field_path *target_field_path, + struct bt_ctf_field_type *target_type, + struct resolve_context *ctx) +{ + int ret = 0; + struct bt_ctf_field_path *ctx_field_path; + int target_field_path_len = target_field_path->indexes->len; + int lca_index; + int ctx_cur_field_type_id; + int target_type_id; + + /* Get context field path */ + ctx_field_path = get_ctx_stack_field_path(ctx); + if (!ctx_field_path) { + _printf_error("Cannot get source field path\n"); + ret = -1; + goto end; + } + + /* + * Make sure the target is not a root. + */ + if (target_field_path_len == 0) { + _printf_error("Target field path's length is 0 (targeting the root)\n"); + ret = -1; + goto end; + } + + /* + * Make sure the root of the target field path is not located + * after the context field path's root. + */ + if (target_field_path->root > ctx_field_path->root) { + _printf_error("Target is located after source\n"); + ret = -1; + goto end; + } + + if (target_field_path->root == ctx_field_path->root) { + int target_index, ctx_index; + + /* + * Find the index of the lowest common ancestor of both field + * paths. + */ + lca_index = get_field_paths_lca_index(target_field_path, + ctx_field_path); + if (lca_index < 0) { + _printf_error("Cannot get least common ancestor\n"); + ret = -1; + goto end; + } + + /* + * Make sure the target field path is located before the + * context field path. + */ + target_index = g_array_index(target_field_path->indexes, + int, lca_index); + ctx_index = g_array_index(ctx_field_path->indexes, + int, lca_index); + + if (target_index >= ctx_index) { + _printf_error("Target index (%d) is greater or equal to source index (%d) in LCA\n", + target_index, ctx_index); + ret = -1; + goto end; + } + } + + /* + * Make sure the target type has the right type and properties. + */ + ctx_cur_field_type_id = bt_ctf_field_type_get_type_id( + ctx->cur_field_type); + target_type_id = bt_ctf_field_type_get_type_id(target_type); + + if (ctx_cur_field_type_id == CTF_TYPE_VARIANT) { + if (target_type_id != CTF_TYPE_ENUM) { + _printf_error("Variant type's tag field type is not an enumeration\n"); + ret = -1; + goto end; + } + } else if (ctx_cur_field_type_id == CTF_TYPE_SEQUENCE) { + if (target_type_id != CTF_TYPE_INTEGER || + bt_ctf_field_type_integer_get_signed( + target_type)) { + _printf_error("Sequence type's length field type is not an unsigned integer\n"); + ret = -1; + goto end; + } + } else { + assert(false); + } + +end: + BT_PUT(ctx_field_path); + return ret; +} + +/* + * Resolves a variant or sequence field type `type`. + * + * `type` is owned by the caller. + */ +static +int resolve_sequence_or_variant_type(struct bt_ctf_field_type *type, + struct resolve_context *ctx) +{ + int ret = 0; + const char *pathstr; + int type_id = bt_ctf_field_type_get_type_id(type); + struct bt_ctf_field_path *target_field_path = NULL; + struct bt_ctf_field_type *target_type = NULL; + + /* Get path string */ + switch (type_id) { + case CTF_TYPE_SEQUENCE: + pathstr = + bt_ctf_field_type_sequence_get_length_field_name(type); + break; + case CTF_TYPE_VARIANT: + pathstr = + bt_ctf_field_type_variant_get_tag_name(type); + break; + default: + assert(false); + ret = -1; + goto end; + } + + /* Get target field path out of path string */ + target_field_path = pathstr_to_field_path(pathstr, ctx); + if (!target_field_path) { + _printf_error("Cannot get target field path for path string \"%s\"\n", + pathstr); + ret = -1; + goto end; + } + + /* Get target field type */ + target_type = field_path_to_field_type(target_field_path, ctx); + if (!target_type) { + _printf_error("Cannot get target field type for path string \"%s\"\n", + pathstr); + ret = -1; + goto end; + } + + ret = validate_target_field_path(target_field_path, target_type, ctx); + if (ret) { + _printf_error("Invalid target field path for path string \"%s\"\n", + pathstr); + goto end; + } + + /* Set target field path and target field type */ + if (type_id == CTF_TYPE_SEQUENCE) { + ret = bt_ctf_field_type_sequence_set_length_field_path( + type, target_field_path); + if (ret) { + _printf_error("Cannot set sequence field type's length field path\n"); + goto end; + } + } else if (type_id == CTF_TYPE_VARIANT) { + ret = bt_ctf_field_type_variant_set_tag_field_path( + type, target_field_path); + if (ret) { + _printf_error("Cannot set variant field type's tag field path\n"); + goto end; + } + + ret = bt_ctf_field_type_variant_set_tag_field_type( + type, target_type); + if (ret) { + _printf_error("Cannot set variant field type's tag field type\n"); + goto end; + } + } else { + assert(false); + } + +end: + BT_PUT(target_field_path); + BT_PUT(target_type); + return ret; +} + +/* + * Resolves a field type `type`. + * + * `type` is owned by the caller. + */ +static +int resolve_type(struct bt_ctf_field_type *type, struct resolve_context *ctx) +{ + int ret = 0; + int type_id; + + if (!type) { + /* Type is not available; still valid */ + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(type); + ctx->cur_field_type = type; + + /* Resolve sequence/variant field type */ + switch (type_id) { + case CTF_TYPE_SEQUENCE: + case CTF_TYPE_VARIANT: + ret = resolve_sequence_or_variant_type(type, ctx); + if (ret) { + _printf_error("Cannot resolve sequence or variant field type's length/tag\n"); + goto end; + } + break; + default: + break; + } + + /* Recurse into compound types */ + switch (type_id) { + case CTF_TYPE_STRUCT: + case CTF_TYPE_VARIANT: + case CTF_TYPE_SEQUENCE: + case CTF_TYPE_ARRAY: + { + int field_count, f_index; + + ret = type_stack_push(ctx->type_stack, type); + if (ret) { + _printf_error("Cannot push field type on type stack\n"); + _printf_error(" Stack size: %zu\n", + type_stack_size(ctx->type_stack)); + goto end; + } + + field_count = bt_ctf_field_type_get_field_count(type); + if (field_count < 0) { + _printf_error("Cannot get field type field count\n"); + ret = field_count; + goto end; + } + + for (f_index = 0; f_index < field_count; f_index++) { + struct bt_ctf_field_type *child_type = + bt_ctf_field_type_get_field_at_index(type, + f_index); + + if (!child_type) { + _printf_error("Cannot get field type field at index %d/%d\n", + f_index, field_count); + ret = -1; + goto end; + } + + if (type_id == CTF_TYPE_ARRAY || + type_id == CTF_TYPE_SEQUENCE) { + type_stack_peek(ctx->type_stack)->index = -1; + } else { + type_stack_peek(ctx->type_stack)->index = + f_index; + } + + ret = resolve_type(child_type, ctx); + BT_PUT(child_type); + if (ret) { + goto end; + } + } + + type_stack_pop(ctx->type_stack); + break; + } + default: + break; + } + +end: + return ret; +} + +/* + * Resolves the root field type corresponding to the scope `root_scope`. + */ +static +int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx) +{ + int ret; + + assert(type_stack_size(ctx->type_stack) == 0); + ctx->root_scope = root_scope; + ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx); + ctx->root_scope = BT_CTF_SCOPE_UNKNOWN; + + return ret; +} + +BT_HIDDEN +int bt_ctf_resolve_types( + struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *event_payload_type, + enum bt_ctf_resolve_flag flags) +{ + int ret = 0; + struct resolve_context ctx = { + .environment = environment, + .scopes = { + packet_header_type, + packet_context_type, + event_header_type, + stream_event_ctx_type, + event_context_type, + event_payload_type, + }, + .root_scope = BT_CTF_SCOPE_UNKNOWN, + }; + + /* Initialize type stack */ + ctx.type_stack = type_stack_create(); + if (!ctx.type_stack) { + printf_error("Cannot create type stack\n"); + ret = -1; + goto end; + } + + /* Resolve packet header type */ + if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) { + ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx); + if (ret) { + _printf_error("Cannot resolve trace packet header type\n"); + goto end; + } + } + + /* Resolve packet context type */ + if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx); + if (ret) { + _printf_error("Cannot resolve stream packet context type\n"); + goto end; + } + } + + /* Resolve event header type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx); + if (ret) { + _printf_error("Cannot resolve stream event header type\n"); + goto end; + } + } + + /* Resolve stream event context type */ + if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx); + if (ret) { + _printf_error("Cannot resolve stream event context type\n"); + goto end; + } + } + + /* Resolve event context type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) { + ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx); + if (ret) { + _printf_error("Cannot resolve event context type\n"); + goto end; + } + } + + /* Resolve event payload type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) { + ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx); + if (ret) { + _printf_error("Cannot resolve event payload type\n"); + goto end; + } + } + +end: + type_stack_destroy(ctx.type_stack); + + return ret; +} diff --git a/formats/ctf/ir/stream-class.c b/formats/ctf/ir/stream-class.c new file mode 100644 index 00000000..326e759e --- /dev/null +++ b/formats/ctf/ir/stream-class.c @@ -0,0 +1,918 @@ +/* + * stream-class.c + * + * Babeltrace CTF IR - Stream Class + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_stream_class_destroy(struct bt_object *obj); +static +int init_event_header(struct bt_ctf_stream_class *stream_class); +static +int init_packet_context(struct bt_ctf_stream_class *stream_class); + +struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) +{ + int ret; + struct bt_ctf_stream_class *stream_class = NULL; + + if (name && bt_ctf_validate_identifier(name)) { + goto error; + } + + stream_class = g_new0(struct bt_ctf_stream_class, 1); + if (!stream_class) { + goto error; + } + + stream_class->name = g_string_new(name); + stream_class->event_classes = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_object_release); + if (!stream_class->event_classes) { + goto error; + } + + ret = init_event_header(stream_class); + if (ret) { + goto error; + } + + ret = init_packet_context(stream_class); + if (ret) { + goto error; + } + + bt_object_init(stream_class, bt_ctf_stream_class_destroy); + return stream_class; + +error: + BT_PUT(stream_class); + return stream_class; +} + +struct bt_ctf_trace *bt_ctf_stream_class_get_trace( + struct bt_ctf_stream_class *stream_class) +{ + return (struct bt_ctf_trace *) bt_object_get_parent( + stream_class); +} + +const char *bt_ctf_stream_class_get_name( + struct bt_ctf_stream_class *stream_class) +{ + const char *name = NULL; + + if (!stream_class) { + goto end; + } + + name = stream_class->name->str; +end: + return name; +} + +int bt_ctf_stream_class_set_name(struct bt_ctf_stream_class *stream_class, + const char *name) +{ + int ret = 0; + + if (!stream_class || stream_class->frozen) { + ret = -1; + goto end; + } + + g_string_assign(stream_class->name, name); +end: + return ret; +} + +struct bt_ctf_clock *bt_ctf_stream_class_get_clock( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_clock *clock = NULL; + + if (!stream_class || !stream_class->clock) { + goto end; + } + + clock = stream_class->clock; + bt_get(clock); +end: + return clock; +} + +int bt_ctf_stream_class_set_clock(struct bt_ctf_stream_class *stream_class, + struct bt_ctf_clock *clock) +{ + int ret = 0; + struct bt_ctf_field_type *timestamp_field = NULL; + + if (!stream_class || !clock || stream_class->frozen) { + ret = -1; + goto end; + } + + /* + * Look for a "timestamp" field in the stream class' event header type + * and map the stream's clock to that field if no current mapping is + * currently set. + */ + timestamp_field = bt_ctf_field_type_structure_get_field_type_by_name( + stream_class->event_header_type, "timestamp"); + if (timestamp_field) { + struct bt_ctf_clock *mapped_clock; + + mapped_clock = bt_ctf_field_type_integer_get_mapped_clock( + timestamp_field); + if (mapped_clock) { + bt_put(mapped_clock); + goto end; + } + + ret = bt_ctf_field_type_integer_set_mapped_clock( + timestamp_field, clock); + if (ret) { + goto end; + } + } + + if (stream_class->clock) { + bt_put(stream_class->clock); + } + + stream_class->clock = clock; + bt_get(clock); +end: + if (timestamp_field) { + bt_put(timestamp_field); + } + return ret; +} + +int64_t bt_ctf_stream_class_get_id(struct bt_ctf_stream_class *stream_class) +{ + int64_t ret; + + if (!stream_class || !stream_class->id_set) { + ret = -1; + goto end; + } + + ret = (int64_t) stream_class->id; +end: + return ret; +} + +BT_HIDDEN +int _bt_ctf_stream_class_set_id( + struct bt_ctf_stream_class *stream_class, uint32_t id) +{ + stream_class->id = id; + stream_class->id_set = 1; + return 0; +} + +struct event_class_set_stream_id_data { + uint32_t stream_id; + int ret; +}; + +static +void event_class_set_stream_id(gpointer event_class, gpointer data) +{ + struct event_class_set_stream_id_data *typed_data = data; + + typed_data->ret |= bt_ctf_event_class_set_stream_id(event_class, + typed_data->stream_id); +} + +BT_HIDDEN +int bt_ctf_stream_class_set_id_no_check( + struct bt_ctf_stream_class *stream_class, uint32_t id) +{ + int ret = 0; + struct event_class_set_stream_id_data data = + { .stream_id = id, .ret = 0 }; + + /* + * Make sure all event classes have their "stream_id" attribute + * set to this value. + */ + g_ptr_array_foreach(stream_class->event_classes, + event_class_set_stream_id, &data); + ret = data.ret; + if (ret) { + goto end; + } + + ret = _bt_ctf_stream_class_set_id(stream_class, id); + if (ret) { + goto end; + } +end: + return ret; +} + +int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, + uint32_t id) +{ + int ret = 0; + + if (!stream_class || stream_class->frozen) { + ret = -1; + goto end; + } + + ret = bt_ctf_stream_class_set_id_no_check(stream_class, id); +end: + return ret; +} + +static +void event_class_exists(gpointer element, gpointer query) +{ + struct bt_ctf_event_class *event_class_a = element; + struct search_query *search_query = query; + struct bt_ctf_event_class *event_class_b = search_query->value; + int64_t id_a, id_b; + + if (search_query->value == element) { + search_query->found = 1; + goto end; + } + + /* + * Two event classes cannot share the same name in a given + * stream class. + */ + if (!strcmp(bt_ctf_event_class_get_name(event_class_a), + bt_ctf_event_class_get_name(event_class_b))) { + search_query->found = 1; + goto end; + } + + /* + * Two event classes cannot share the same ID in a given + * stream class. + */ + id_a = bt_ctf_event_class_get_id(event_class_a); + id_b = bt_ctf_event_class_get_id(event_class_b); + + if (id_a < 0 || id_b < 0) { + /* at least one ID is not set: will be automatically set later */ + goto end; + } + + if (id_a == id_b) { + search_query->found = 1; + goto end; + } + +end: + return; +} + +int bt_ctf_stream_class_add_event_class( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class) +{ + int ret = 0; + int64_t event_id; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_stream_class *old_stream_class = NULL; + struct bt_ctf_validation_output validation_output = { 0 }; + struct bt_ctf_field_type *packet_header_type = NULL; + struct bt_ctf_field_type *packet_context_type = NULL; + struct bt_ctf_field_type *event_header_type = NULL; + struct bt_ctf_field_type *stream_event_ctx_type = NULL; + struct bt_ctf_field_type *event_context_type = NULL; + struct bt_ctf_field_type *event_payload_type = NULL; + const enum bt_ctf_validation_flag validation_flags = + BT_CTF_VALIDATION_FLAG_EVENT; + + if (!stream_class || !event_class) { + ret = -1; + goto end; + } + + /* Check for duplicate event classes */ + struct search_query query = { .value = event_class, .found = 0 }; + g_ptr_array_foreach(stream_class->event_classes, event_class_exists, + &query); + if (query.found) { + ret = -1; + goto end; + } + + old_stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (old_stream_class) { + /* Event class is already associated to a stream class. */ + ret = -1; + goto end; + } + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (trace) { + /* + * If the stream class is associated with a trace, then + * both those objects are frozen. Also, this event class + * is about to be frozen. + * + * Therefore the event class must be validated here. + * The trace and stream class should be valid at this + * point. + */ + assert(trace->valid); + assert(stream_class->valid); + packet_header_type = + bt_ctf_trace_get_packet_header_type(trace); + packet_context_type = + bt_ctf_stream_class_get_packet_context_type( + stream_class); + event_header_type = + bt_ctf_stream_class_get_event_header_type(stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_get_event_context_type( + stream_class); + event_context_type = + bt_ctf_event_class_get_context_type(event_class); + event_payload_type = + bt_ctf_event_class_get_payload_type(event_class); + ret = bt_ctf_validate_class_types( + trace->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. + */ + goto end; + } + + if ((validation_output.valid_flags & validation_flags) != + validation_flags) { + /* Invalid event class */ + ret = -1; + goto end; + } + } + + /* Only set an event ID if none was explicitly set before */ + event_id = bt_ctf_event_class_get_id(event_class); + if (event_id < 0) { + if (bt_ctf_event_class_set_id(event_class, + stream_class->next_event_id++)) { + ret = -1; + goto end; + } + } + + ret = bt_ctf_event_class_set_stream_id(event_class, stream_class->id); + if (ret) { + goto end; + } + + bt_object_set_parent(event_class, stream_class); + + if (trace) { + /* + * At this point we know that the function will be + * successful. Therefore we can replace the event + * class's field types with what's in the validation + * output structure and mark this event class as valid. + */ + bt_ctf_validation_replace_types(NULL, NULL, event_class, + &validation_output, validation_flags); + event_class->valid = 1; + + /* + * Put what was not moved in + * bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&validation_output); + } + + /* Add to the event classes of the stream class */ + g_ptr_array_add(stream_class->event_classes, event_class); + + /* Freeze the event class */ + bt_ctf_event_class_freeze(event_class); + + if (stream_class->byte_order) { + /* + * Only set native byte order if it has been initialized + * when the stream class was added to a trace. + * + * If not set here, this will be set when the stream + * class is added to a trace. + */ + bt_ctf_event_class_set_native_byte_order(event_class, + stream_class->byte_order); + } + +end: + BT_PUT(trace); + BT_PUT(old_stream_class); + bt_ctf_validation_output_put_types(&validation_output); + 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 ret; +} + +int bt_ctf_stream_class_get_event_class_count( + struct bt_ctf_stream_class *stream_class) +{ + int ret; + + if (!stream_class) { + ret = -1; + goto end; + } + + ret = (int) stream_class->event_classes->len; +end: + return ret; +} + +struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class( + struct bt_ctf_stream_class *stream_class, int index) +{ + struct bt_ctf_event_class *event_class = NULL; + + if (!stream_class || index < 0 || + index >= stream_class->event_classes->len) { + goto end; + } + + event_class = g_ptr_array_index(stream_class->event_classes, index); + bt_get(event_class); +end: + return event_class; +} + +struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_name( + struct bt_ctf_stream_class *stream_class, const char *name) +{ + size_t i; + struct bt_ctf_event_class *event_class = NULL; + + if (!stream_class || !name) { + goto end; + } + + for (i = 0; i < stream_class->event_classes->len; i++) { + struct bt_ctf_event_class *cur_event_class = + g_ptr_array_index(stream_class->event_classes, i); + const char *cur_event_class_name = + bt_ctf_event_class_get_name(cur_event_class); + + if (!strcmp(name, cur_event_class_name)) { + event_class = cur_event_class; + bt_get(event_class); + goto end; + } + } +end: + return event_class; +} + +struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id( + struct bt_ctf_stream_class *stream_class, uint32_t id) +{ + size_t i; + struct bt_ctf_event_class *event_class = NULL; + + if (!stream_class) { + goto end; + } + + for (i = 0; i < stream_class->event_classes->len; i++) { + struct bt_ctf_event_class *current_event_class = + g_ptr_array_index(stream_class->event_classes, i); + + if (bt_ctf_event_class_get_id(current_event_class) == id) { + event_class = current_event_class; + bt_get(event_class); + goto end; + } + } +end: + return event_class; +} + +struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!stream_class) { + goto end; + } + + assert(stream_class->packet_context_type); + bt_get(stream_class->packet_context_type); + ret = stream_class->packet_context_type; +end: + return ret; +} + +int bt_ctf_stream_class_set_packet_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type) +{ + int ret = 0; + + if (!stream_class || !packet_context_type || stream_class->frozen) { + ret = -1; + goto end; + } + + assert(stream_class->packet_context_type); + if (stream_class->packet_context_type == packet_context_type) { + goto end; + } + if (bt_ctf_field_type_get_type_id(packet_context_type) != + BT_CTF_TYPE_ID_STRUCT) { + /* A packet context must be a structure */ + ret = -1; + goto end; + } + + bt_put(stream_class->packet_context_type); + bt_get(packet_context_type); + stream_class->packet_context_type = packet_context_type; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_stream_class_get_event_header_type( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!stream_class || !stream_class->event_header_type) { + goto end; + } + + assert(stream_class->event_header_type); + bt_get(stream_class->event_header_type); + ret = stream_class->event_header_type; +end: + return ret; +} + +int bt_ctf_stream_class_set_event_header_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_header_type) +{ + int ret = 0; + + if (!stream_class || !event_header_type || stream_class->frozen) { + ret = -1; + goto end; + } + + assert(stream_class->event_header_type); + if (stream_class->event_header_type == event_header_type) { + goto end; + } + if (bt_ctf_field_type_get_type_id(event_header_type) != + BT_CTF_TYPE_ID_STRUCT) { + /* An event header must be a structure */ + ret = -1; + goto end; + } + + bt_put(stream_class->event_header_type); + bt_get(event_header_type); + stream_class->event_header_type = event_header_type; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_stream_class_get_event_context_type( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_field_type *ret = NULL; + + if (!stream_class || !stream_class->event_context_type) { + goto end; + } + + assert(stream_class->event_context_type); + bt_get(stream_class->event_context_type); + ret = stream_class->event_context_type; +end: + return ret; +} + +int bt_ctf_stream_class_set_event_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_context_type) +{ + int ret = 0; + + if (!stream_class || !event_context_type || stream_class->frozen) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_get_type_id(event_context_type) != + BT_CTF_TYPE_ID_STRUCT) { + /* A packet context must be a structure */ + ret = -1; + goto end; + } + + bt_put(stream_class->event_context_type); + bt_get(event_context_type); + stream_class->event_context_type = event_context_type; +end: + return ret; +} + +void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class) +{ + bt_get(stream_class); +} + +void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class) +{ + bt_put(stream_class); +} + +BT_HIDDEN +void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class) +{ + if (!stream_class) { + return; + } + + stream_class->frozen = 1; + bt_ctf_field_type_freeze(stream_class->event_header_type); + bt_ctf_field_type_freeze(stream_class->packet_context_type); + bt_ctf_field_type_freeze(stream_class->event_context_type); + bt_ctf_clock_freeze(stream_class->clock); +} + +BT_HIDDEN +void bt_ctf_stream_class_set_byte_order( + struct bt_ctf_stream_class *stream_class, int byte_order) +{ + int i; + + assert(stream_class); + assert(byte_order == LITTLE_ENDIAN || byte_order == BIG_ENDIAN); + stream_class->byte_order = byte_order; + + /* Set native byte order to little or big endian */ + bt_ctf_field_type_set_native_byte_order( + stream_class->event_header_type, byte_order); + bt_ctf_field_type_set_native_byte_order( + stream_class->packet_context_type, byte_order); + bt_ctf_field_type_set_native_byte_order( + stream_class->event_context_type, byte_order); + + /* Set all events' native byte order */ + for (i = 0; i < stream_class->event_classes->len; i++) { + struct bt_ctf_event_class *event_class = + g_ptr_array_index(stream_class->event_classes, i); + + bt_ctf_event_class_set_native_byte_order(event_class, + byte_order); + } +} + +BT_HIDDEN +int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, + struct metadata_context *context) +{ + int64_t ret = 0; + size_t i; + + g_string_assign(context->field_name, ""); + context->current_indentation_level = 1; + if (!stream_class->id_set) { + ret = -1; + goto end; + } + + g_string_append_printf(context->string, + "stream {\n\tid = %" PRIu32 ";\n\tevent.header := ", + stream_class->id); + ret = bt_ctf_field_type_serialize(stream_class->event_header_type, + context); + if (ret) { + goto end; + } + + g_string_append(context->string, ";\n\n\tpacket.context := "); + ret = bt_ctf_field_type_serialize(stream_class->packet_context_type, + context); + if (ret) { + goto end; + } + + if (stream_class->event_context_type) { + g_string_append(context->string, ";\n\n\tevent.context := "); + ret = bt_ctf_field_type_serialize( + stream_class->event_context_type, context); + if (ret) { + goto end; + } + } + + g_string_append(context->string, ";\n};\n\n"); + for (i = 0; i < stream_class->event_classes->len; i++) { + struct bt_ctf_event_class *event_class = + stream_class->event_classes->pdata[i]; + + ret = bt_ctf_event_class_serialize(event_class, context); + if (ret) { + goto end; + } + } +end: + context->current_indentation_level = 0; + return ret; +} + +static +void bt_ctf_stream_class_destroy(struct bt_object *obj) +{ + struct bt_ctf_stream_class *stream_class; + + stream_class = container_of(obj, struct bt_ctf_stream_class, base); + bt_put(stream_class->clock); + + if (stream_class->event_classes) { + g_ptr_array_free(stream_class->event_classes, TRUE); + } + + if (stream_class->name) { + g_string_free(stream_class->name, TRUE); + } + + bt_put(stream_class->event_header_type); + bt_put(stream_class->packet_context_type); + bt_put(stream_class->event_context_type); + g_free(stream_class); +} + +static +int init_event_header(struct bt_ctf_stream_class *stream_class) +{ + int ret = 0; + struct bt_ctf_field_type *event_header_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *_uint32_t = + get_field_type(FIELD_TYPE_ALIAS_UINT32_T); + struct bt_ctf_field_type *_uint64_t = + get_field_type(FIELD_TYPE_ALIAS_UINT64_T); + + if (!event_header_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(event_header_type, + _uint32_t, "id"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(event_header_type, + _uint64_t, "timestamp"); + if (ret) { + goto end; + } + + if (stream_class->event_header_type) { + bt_put(stream_class->event_header_type); + } + stream_class->event_header_type = event_header_type; +end: + if (ret) { + bt_put(event_header_type); + } + + bt_put(_uint32_t); + bt_put(_uint64_t); + return ret; +} + +static +int init_packet_context(struct bt_ctf_stream_class *stream_class) +{ + int ret = 0; + struct bt_ctf_field_type *packet_context_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *_uint64_t = + get_field_type(FIELD_TYPE_ALIAS_UINT64_T); + + if (!packet_context_type) { + ret = -1; + goto end; + } + + /* + * We create a stream packet context as proposed in the CTF + * specification. + */ + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "timestamp_begin"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "timestamp_end"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "content_size"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "packet_size"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "events_discarded"); + if (ret) { + goto end; + } + + bt_put(stream_class->packet_context_type); + stream_class->packet_context_type = packet_context_type; +end: + if (ret) { + bt_put(packet_context_type); + goto end; + } + + bt_put(_uint64_t); + return ret; +} diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c new file mode 100644 index 00000000..56abfcea --- /dev/null +++ b/formats/ctf/ir/stream.c @@ -0,0 +1,1086 @@ +/* + * stream.c + * + * Babeltrace CTF IR - Stream + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_stream_destroy(struct bt_object *obj); +static +int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); + +static +int set_packet_header_magic(struct bt_ctf_stream *stream) +{ + int ret = 0; + struct bt_ctf_field_type *magic_field_type = NULL; + struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field( + stream->packet_header, "magic"); + + if (!magic_field) { + /* No magic field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(magic_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + magic_field_type = bt_ctf_field_get_type(magic_field); + assert(magic_field_type); + + if (bt_ctf_field_type_get_type_id(magic_field_type) != + BT_CTF_TYPE_ID_INTEGER) { + /* Magic field is not an integer. Not an error, skip. */ + goto end; + } + + if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) { + /* + * Magic field is not of the expected size. + * Not an error, skip. + */ + goto end; + } + + ret = bt_ctf_field_type_integer_get_signed(magic_field_type); + assert(ret >= 0); + if (ret) { + ret = bt_ctf_field_signed_integer_set_value(magic_field, + (int64_t) 0xC1FC1FC1); + } else { + ret = bt_ctf_field_unsigned_integer_set_value(magic_field, + (uint64_t) 0xC1FC1FC1); + } +end: + bt_put(magic_field); + bt_put(magic_field_type); + return ret; +} + +static +int set_packet_header_uuid(struct bt_ctf_stream *stream) +{ + int i, ret = 0; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_field_type *uuid_field_type = NULL; + struct bt_ctf_field_type *element_field_type = NULL; + struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field( + stream->packet_header, "uuid"); + + if (!uuid_field) { + /* No uuid field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(uuid_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + uuid_field_type = bt_ctf_field_get_type(uuid_field); + assert(uuid_field_type); + if (bt_ctf_field_type_get_type_id(uuid_field_type) != + BT_CTF_TYPE_ID_ARRAY) { + /* UUID field is not an array. Not an error, skip. */ + goto end; + } + + if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) { + /* + * UUID field is not of the expected size. + * Not an error, skip. + */ + goto end; + } + + element_field_type = bt_ctf_field_type_array_get_element_type( + uuid_field_type); + assert(element_field_type); + if (bt_ctf_field_type_get_type_id(element_field_type) != + BT_CTF_TYPE_ID_INTEGER) { + /* UUID array elements are not integers. Not an error, skip */ + goto end; + } + + trace = (struct bt_ctf_trace *) bt_object_get_parent(stream); + for (i = 0; i < 16; i++) { + struct bt_ctf_field *uuid_element = + bt_ctf_field_array_get_field(uuid_field, i); + + ret = bt_ctf_field_type_integer_get_signed(element_field_type); + assert(ret >= 0); + + if (ret) { + ret = bt_ctf_field_signed_integer_set_value( + uuid_element, (int64_t) trace->uuid[i]); + } else { + ret = bt_ctf_field_unsigned_integer_set_value( + uuid_element, + (uint64_t) trace->uuid[i]); + } + bt_put(uuid_element); + if (ret) { + goto end; + } + } + +end: + bt_put(uuid_field); + bt_put(uuid_field_type); + bt_put(element_field_type); + BT_PUT(trace); + return ret; +} +static +int set_packet_header_stream_id(struct bt_ctf_stream *stream) +{ + int ret = 0; + uint32_t stream_id; + struct bt_ctf_field_type *stream_id_field_type = NULL; + struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field( + stream->packet_header, "stream_id"); + + if (!stream_id_field) { + /* No stream_id field found. Not an error, skip. */ + goto end; + } + + if (!bt_ctf_field_validate(stream_id_field)) { + /* Value already set. Not an error, skip. */ + goto end; + } + + stream_id_field_type = bt_ctf_field_get_type(stream_id_field); + assert(stream_id_field_type); + if (bt_ctf_field_type_get_type_id(stream_id_field_type) != + BT_CTF_TYPE_ID_INTEGER) { + /* stream_id field is not an integer. Not an error, skip. */ + goto end; + } + + stream_id = stream->stream_class->id; + ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type); + assert(ret >= 0); + if (ret) { + ret = bt_ctf_field_signed_integer_set_value(stream_id_field, + (int64_t) stream_id); + } else { + ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field, + (uint64_t) stream_id); + } +end: + bt_put(stream_id_field); + bt_put(stream_id_field_type); + return ret; +} + +static +int set_packet_header(struct bt_ctf_stream *stream) +{ + int ret; + + ret = set_packet_header_magic(stream); + if (ret) { + goto end; + } + + ret = set_packet_header_uuid(stream); + if (ret) { + goto end; + } + + ret = set_packet_header_stream_id(stream); + if (ret) { + goto end; + } +end: + return ret; +} + +static +void release_event(struct bt_ctf_event *event) +{ + if (bt_object_get_ref_count(event)) { + /* + * The event is being orphaned, but it must guarantee the + * existence of its event class for the duration of its + * lifetime. + */ + bt_get(event->event_class); + BT_PUT(event->base.parent); + } else { + bt_object_release(event); + } +} + +static +int create_stream_file(struct bt_ctf_writer *writer, + struct bt_ctf_stream *stream) +{ + int fd; + GString *filename = g_string_new(stream->stream_class->name->str); + + if (stream->stream_class->name->len == 0) { + int64_t ret; + + ret = bt_ctf_stream_class_get_id(stream->stream_class); + if (ret < 0) { + fd = -1; + goto error; + } + + g_string_printf(filename, "stream_%" PRId64, ret); + } + + g_string_append_printf(filename, "_%" PRIu32, stream->id); + fd = openat(writer->trace_dir_fd, filename->str, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +error: + g_string_free(filename, TRUE); + return fd; +} + +static +int set_stream_fd(struct bt_ctf_stream *stream, int fd) +{ + int ret = 0; + + if (stream->pos.fd != -1) { + ret = -1; + goto end; + } + + ctf_init_pos(&stream->pos, NULL, fd, O_RDWR); + stream->pos.fd = fd; +end: + 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; +} + +struct bt_ctf_stream_class *bt_ctf_stream_get_class( + struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream_class *stream_class = NULL; + + if (!stream) { + goto end; + } + + stream_class = stream->stream_class; + bt_get(stream_class); +end: + return stream_class; +} + +int bt_ctf_stream_get_discarded_events_count( + struct bt_ctf_stream *stream, uint64_t *count) +{ + int64_t ret = 0; + int field_signed; + struct bt_ctf_field *events_discarded_field = NULL; + struct bt_ctf_field_type *events_discarded_field_type = NULL; + + if (!stream || !count || !stream->packet_context || + stream->pos.fd < 0) { + ret = -1; + goto end; + } + + events_discarded_field = bt_ctf_field_structure_get_field( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + ret = -1; + goto end; + } + + events_discarded_field_type = bt_ctf_field_get_type( + events_discarded_field); + if (!events_discarded_field_type) { + ret = -1; + goto end; + } + + field_signed = bt_ctf_field_type_integer_get_signed( + events_discarded_field_type); + if (field_signed < 0) { + ret = field_signed; + goto end; + } + + if (field_signed) { + int64_t signed_count; + + ret = bt_ctf_field_signed_integer_get_value( + events_discarded_field, &signed_count); + if (ret) { + goto end; + } + if (signed_count < 0) { + /* Invalid value */ + ret = -1; + goto end; + } + *count = (uint64_t) signed_count; + } else { + ret = bt_ctf_field_unsigned_integer_get_value( + events_discarded_field, count); + if (ret) { + goto end; + } + } +end: + bt_put(events_discarded_field); + bt_put(events_discarded_field_type); + return ret; +} + +void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, + uint64_t event_count) +{ + int ret; + int field_signed; + uint64_t previous_count; + uint64_t new_count; + struct bt_ctf_field *events_discarded_field = NULL; + struct bt_ctf_field_type *events_discarded_field_type = NULL; + + if (!stream || !stream->packet_context || stream->pos.fd < 0) { + goto end; + } + + ret = bt_ctf_stream_get_discarded_events_count(stream, + &previous_count); + if (ret) { + goto end; + } + + events_discarded_field = bt_ctf_field_structure_get_field( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + goto end; + } + + events_discarded_field_type = bt_ctf_field_get_type( + events_discarded_field); + if (!events_discarded_field_type) { + goto end; + } + + field_signed = bt_ctf_field_type_integer_get_signed( + events_discarded_field_type); + if (field_signed < 0) { + goto end; + } + + new_count = previous_count + event_count; + if (field_signed) { + ret = bt_ctf_field_signed_integer_set_value( + events_discarded_field, (int64_t) new_count); + if (ret) { + goto end; + } + } else { + ret = bt_ctf_field_unsigned_integer_set_value( + events_discarded_field, new_count); + if (ret) { + goto end; + } + } + +end: + bt_put(events_discarded_field); + bt_put(events_discarded_field_type); +} + +int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, + struct bt_ctf_event *event) +{ + int ret = 0; + + if (!stream || !event || stream->pos.fd < 0) { + ret = -1; + goto end; + } + + /* + * The event is not supposed to have a parent stream at this + * point. The only other way an event can have a parent stream + * is if it was assigned when setting a packet to the event, + * in which case the packet's stream is not a writer stream, + * and thus the user is trying to append an event which belongs + * to another stream. + */ + if (event->base.parent) { + ret = -1; + goto end; + } + + bt_object_set_parent(event, stream); + ret = bt_ctf_event_populate_event_header(event); + if (ret) { + goto error; + } + + /* Make sure the various scopes of the event are set */ + ret = bt_ctf_event_validate(event); + if (ret) { + goto error; + } + + /* Save the new event and freeze it */ + bt_ctf_event_freeze(event); + g_ptr_array_add(stream->events, event); + + /* + * Event had to hold a reference to its event class as long as it wasn't + * part of the same trace hierarchy. From now on, the event and its + * class share the same lifetime guarantees and the reference is no + * longer needed. + */ + bt_put(event->event_class); + +end: + return ret; + +error: + /* + * Orphan the event; we were not successful in associating it to + * a stream. + */ + bt_object_set_parent(event, NULL); + + return ret; +} + +struct bt_ctf_field *bt_ctf_stream_get_packet_context( + struct bt_ctf_stream *stream) +{ + struct bt_ctf_field *packet_context = NULL; + + if (!stream || stream->pos.fd < 0) { + goto end; + } + + packet_context = stream->packet_context; + if (packet_context) { + bt_get(packet_context); + } +end: + return packet_context; +} + +int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream, + struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_type *field_type; + + if (!stream || !field || stream->pos.fd < 0) { + ret = -1; + goto end; + } + + field_type = bt_ctf_field_get_type(field); + if (bt_ctf_field_type_compare(field_type, + stream->stream_class->packet_context_type)) { + ret = -1; + goto end; + } + + bt_put(field_type); + bt_get(field); + bt_put(stream->packet_context); + stream->packet_context = field; +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_stream_get_packet_header( + struct bt_ctf_stream *stream) +{ + struct bt_ctf_field *packet_header = NULL; + + if (!stream || stream->pos.fd < 0) { + goto end; + } + + packet_header = stream->packet_header; + if (packet_header) { + bt_get(packet_header); + } +end: + return packet_header; +} + +int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream, + struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_field_type *field_type = NULL; + + if (!stream || !field || stream->pos.fd < 0) { + ret = -1; + goto end; + } + + trace = (struct bt_ctf_trace *) bt_object_get_parent(stream); + field_type = bt_ctf_field_get_type(field); + if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) { + ret = -1; + goto end; + } + + bt_get(field); + bt_put(stream->packet_header); + stream->packet_header = field; +end: + BT_PUT(trace); + bt_put(field_type); + return ret; +} + +static +int get_event_header_timestamp(struct bt_ctf_field *event_header, uint64_t *timestamp) +{ + int ret = 0; + struct bt_ctf_field *timestamp_field = NULL; + struct bt_ctf_field_type *timestamp_field_type = NULL; + + timestamp_field = bt_ctf_field_structure_get_field(event_header, + "timestamp"); + if (!timestamp_field) { + ret = -1; + goto end; + } + + timestamp_field_type = bt_ctf_field_get_type(timestamp_field); + assert(timestamp_field_type); + if (bt_ctf_field_type_get_type_id(timestamp_field_type) != + BT_CTF_TYPE_ID_INTEGER) { + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_get_signed(timestamp_field_type)) { + int64_t val; + + ret = bt_ctf_field_signed_integer_get_value(timestamp_field, + &val); + if (ret) { + goto end; + } + *timestamp = (uint64_t) val; + } else { + ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field, + timestamp); + if (ret) { + goto end; + } + } +end: + bt_put(timestamp_field); + bt_put(timestamp_field_type); + return ret; +} + +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 (event->stream_event_context) { + ret = bt_ctf_field_serialize( + event->stream_event_context, &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); + stream->flushed_packet_count++; +end: + bt_put(integer); + return ret; +} + +void bt_ctf_stream_get(struct bt_ctf_stream *stream) +{ + bt_get(stream); +} + +void bt_ctf_stream_put(struct bt_ctf_stream *stream) +{ + bt_put(stream); +} + +static +void bt_ctf_stream_destroy(struct bt_object *obj) +{ + struct bt_ctf_stream *stream; + + stream = container_of(obj, struct bt_ctf_stream, base); + ctf_fini_pos(&stream->pos); + if (stream->pos.fd >= 0 && close(stream->pos.fd)) { + perror("close"); + } + + if (stream->events) { + g_ptr_array_free(stream->events, TRUE); + } + + if (stream->name) { + g_string_free(stream->name, TRUE); + } + + if (stream->clock_values) { + g_hash_table_destroy(stream->clock_values); + } + + bt_put(stream->packet_header); + bt_put(stream->packet_context); + g_free(stream); +} + +static +int set_structure_field_integer(struct bt_ctf_field *structure, char *name, + uint64_t value) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field *integer = + bt_ctf_field_structure_get_field(structure, name); + + if (!structure || !name) { + ret = -1; + goto end; + } + + if (!integer) { + /* Field not found, not an error. */ + goto end; + } + + /* Make sure the payload has not already been set. */ + if (!bt_ctf_field_validate(integer)) { + /* Payload already set, not an error */ + goto end; + } + + field_type = bt_ctf_field_get_type(integer); + /* Something is serioulsly wrong */ + assert(field_type); + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) { + /* + * The user most likely meant for us to populate this field + * automatically. However, we can only do this if the field + * is an integer. Return an error. + */ + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_get_signed(field_type)) { + ret = bt_ctf_field_signed_integer_set_value(integer, + (int64_t) value); + } else { + ret = bt_ctf_field_unsigned_integer_set_value(integer, value); + } +end: + bt_put(integer); + bt_put(field_type); + return ret; +} + +const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream) +{ + const char *name = NULL; + + if (!stream) { + goto end; + } + + name = stream->name ? stream->name->str : NULL; + +end: + return name; +} + +BT_HIDDEN +void bt_ctf_stream_update_clock_value(struct bt_ctf_stream *stream, + struct bt_ctf_field *value_field) +{ + struct bt_ctf_field_type *value_type = NULL; + struct bt_ctf_clock *clock = NULL; + uint64_t requested_new_value; + uint64_t requested_new_value_mask; + uint64_t *cur_value; + uint64_t cur_value_masked; + int requested_new_value_size; + int ret; + + assert(stream); + assert(clock); + assert(value_field); + value_type = bt_ctf_field_get_type(value_field); + assert(value_type); + clock = bt_ctf_field_type_integer_get_mapped_clock(value_type); + assert(clock); + requested_new_value_size = + bt_ctf_field_type_integer_get_size(value_type); + assert(requested_new_value_size > 0); + ret = bt_ctf_field_unsigned_integer_get_value(value_field, + &requested_new_value); + assert(!ret); + cur_value = g_hash_table_lookup(stream->clock_values, clock); + + if (!cur_value) { + /* + * Updating the value of a clock which is not registered + * yet, so register it with the new value as its initial + * value. + */ + uint64_t *requested_new_value_ptr = g_new0(uint64_t, 1); + + *requested_new_value_ptr = requested_new_value; + g_hash_table_insert(stream->clock_values, clock, + requested_new_value_ptr); + goto end; + } + + /* + * Special case for a 64-bit new value, which is the limit + * of a clock value as of this version: overwrite the + * current value directly. + */ + if (requested_new_value_size == 64) { + *cur_value = requested_new_value; + goto end; + } + + requested_new_value_mask = (1ULL << requested_new_value_size) - 1; + cur_value_masked = *cur_value & requested_new_value_mask; + + if (requested_new_value < cur_value_masked) { + /* + * It looks like a wrap happened on the number of bits + * of the requested new value. Assume that the clock + * value wrapped only one time. + */ + *cur_value += requested_new_value_mask + 1; + } + + /* Clear the low bits of the current clock value */ + *cur_value &= ~requested_new_value_mask; + + /* Set the low bits of the current clock value */ + *cur_value |= requested_new_value; + +end: + bt_put(clock); + bt_put(value_type); +} diff --git a/formats/ctf/ir/trace.c b/formats/ctf/ir/trace.c new file mode 100644 index 00000000..4d9e97f9 --- /dev/null +++ b/formats/ctf/ir/trace.c @@ -0,0 +1,1120 @@ +/* + * trace.c + * + * Babeltrace CTF IR - Trace + * + * Copyright 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_IDENTIFIER_SIZE 128 +#define DEFAULT_METADATA_STRING_SIZE 4096 + +static +void bt_ctf_trace_destroy(struct bt_object *obj); +static +int init_trace_packet_header(struct bt_ctf_trace *trace); +static +void bt_ctf_trace_freeze(struct bt_ctf_trace *trace); + +static +const unsigned int field_type_aliases_alignments[] = { + [FIELD_TYPE_ALIAS_UINT5_T] = 1, + [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, + [FIELD_TYPE_ALIAS_UINT27_T] = 1, + [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, +}; + +static +const unsigned int field_type_aliases_sizes[] = { + [FIELD_TYPE_ALIAS_UINT5_T] = 5, + [FIELD_TYPE_ALIAS_UINT8_T] = 8, + [FIELD_TYPE_ALIAS_UINT16_T] = 16, + [FIELD_TYPE_ALIAS_UINT27_T] = 27, + [FIELD_TYPE_ALIAS_UINT32_T] = 32, + [FIELD_TYPE_ALIAS_UINT64_T] = 64, +}; + +struct bt_ctf_trace *bt_ctf_trace_create(void) +{ + struct bt_ctf_trace *trace = NULL; + + trace = g_new0(struct bt_ctf_trace, 1); + if (!trace) { + goto error; + } + + bt_ctf_trace_set_byte_order(trace, BT_CTF_BYTE_ORDER_NATIVE); + bt_object_init(trace, bt_ctf_trace_destroy); + trace->clocks = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_put); + trace->streams = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_object_release); + trace->stream_classes = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_object_release); + if (!trace->clocks || !trace->stream_classes || !trace->streams) { + goto error; + } + + /* Generate a trace UUID */ + uuid_generate(trace->uuid); + if (init_trace_packet_header(trace)) { + goto error; + } + + /* Create the environment array object */ + trace->environment = bt_ctf_attributes_create(); + if (!trace->environment) { + goto error; + } + + return trace; + +error: + BT_PUT(trace); + return trace; +} + +void bt_ctf_trace_destroy(struct bt_object *obj) +{ + struct bt_ctf_trace *trace; + + trace = container_of(obj, struct bt_ctf_trace, base); + if (trace->environment) { + bt_ctf_attributes_destroy(trace->environment); + } + + if (trace->clocks) { + g_ptr_array_free(trace->clocks, TRUE); + } + + if (trace->streams) { + g_ptr_array_free(trace->streams, TRUE); + } + + if (trace->stream_classes) { + g_ptr_array_free(trace->stream_classes, TRUE); + } + + bt_put(trace->packet_header_type); + g_free(trace); +} + +int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace, + const char *name, struct bt_value *value) +{ + int ret = 0; + + if (!trace || !name || !value || + bt_ctf_validate_identifier(name) || + !(bt_value_is_integer(value) || bt_value_is_string(value))) { + ret = -1; + goto end; + } + + if (strchr(name, ' ')) { + ret = -1; + goto end; + } + + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + * + * The object passed is frozen like all other attributes. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + + bt_value_freeze(value); + } + + ret = bt_ctf_attributes_set_field_value(trace->environment, name, + value); + +end: + return ret; +} + +int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace, + const char *name, const char *value) +{ + int ret = 0; + struct bt_value *env_value_string_obj = NULL; + + if (!trace || !name || !value) { + ret = -1; + goto end; + } + + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + } + + env_value_string_obj = bt_value_string_create_init(value); + + if (!env_value_string_obj) { + ret = -1; + goto end; + } + + if (trace->frozen) { + bt_value_freeze(env_value_string_obj); + } + ret = bt_ctf_trace_set_environment_field(trace, name, + env_value_string_obj); + +end: + BT_PUT(env_value_string_obj); + return ret; +} + +int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace, + const char *name, int64_t value) +{ + int ret = 0; + struct bt_value *env_value_integer_obj = NULL; + + if (!trace || !name) { + ret = -1; + goto end; + } + + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + */ + struct bt_value *attribute = + bt_ctf_attributes_get_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_PUT(attribute); + ret = -1; + goto end; + } + } + + env_value_integer_obj = bt_value_integer_create_init(value); + if (!env_value_integer_obj) { + ret = -1; + goto end; + } + + ret = bt_ctf_trace_set_environment_field(trace, name, + env_value_integer_obj); + if (trace->frozen) { + bt_value_freeze(env_value_integer_obj); + } +end: + BT_PUT(env_value_integer_obj); + 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 = bt_ctf_attributes_get_count(trace->environment); + +end: + return ret; +} + +const char * +bt_ctf_trace_get_environment_field_name(struct bt_ctf_trace *trace, + int index) +{ + const char *ret = NULL; + + if (!trace) { + goto end; + } + + ret = bt_ctf_attributes_get_field_name(trace->environment, index); + +end: + return ret; +} + +struct bt_value *bt_ctf_trace_get_environment_field_value( + struct bt_ctf_trace *trace, int index) +{ + struct bt_value *ret = NULL; + + if (!trace) { + goto end; + } + + ret = bt_ctf_attributes_get_field_value(trace->environment, index); + +end: + return ret; +} + +struct bt_value *bt_ctf_trace_get_environment_field_value_by_name( + struct bt_ctf_trace *trace, const char *name) +{ + struct bt_value *ret = NULL; + + if (!trace || !name) { + goto end; + } + + ret = bt_ctf_attributes_get_field_value_by_name(trace->environment, + name); + +end: + return ret; +} + +int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace, + struct bt_ctf_clock *clock) +{ + int ret = 0; + struct search_query query = { .value = clock, .found = 0 }; + + if (!trace || !clock) { + ret = -1; + goto end; + } + + /* Check for duplicate clocks */ + g_ptr_array_foreach(trace->clocks, value_exists, &query); + if (query.found) { + ret = -1; + goto end; + } + + bt_get(clock); + g_ptr_array_add(trace->clocks, clock); + + if (!trace->is_created_by_writer) { + /* + * Non-writer mode trace: disable clock value functions + * because clock values are per-stream in that + * situation. + */ + clock->has_value = 0; + } + + if (trace->frozen) { + bt_ctf_clock_freeze(clock); + } +end: + return ret; +} + +int bt_ctf_trace_get_clock_count(struct bt_ctf_trace *trace) +{ + int ret = -1; + + if (!trace) { + goto end; + } + + ret = trace->clocks->len; +end: + return ret; +} + +struct bt_ctf_clock *bt_ctf_trace_get_clock(struct bt_ctf_trace *trace, + int index) +{ + struct bt_ctf_clock *clock = NULL; + + if (!trace || index < 0 || index >= trace->clocks->len) { + goto end; + } + + clock = g_ptr_array_index(trace->clocks, index); + bt_get(clock); +end: + 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; + struct bt_ctf_validation_output trace_sc_validation_output = { 0 }; + struct bt_ctf_validation_output *ec_validation_outputs = NULL; + const enum bt_ctf_validation_flag trace_sc_validation_flags = + BT_CTF_VALIDATION_FLAG_TRACE | + BT_CTF_VALIDATION_FLAG_STREAM; + const enum bt_ctf_validation_flag ec_validation_flags = + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_field_type *packet_header_type = NULL; + struct bt_ctf_field_type *packet_context_type = NULL; + struct bt_ctf_field_type *event_header_type = NULL; + struct bt_ctf_field_type *stream_event_ctx_type = NULL; + int event_class_count; + struct bt_ctf_clock *clock_to_add_to_trace = NULL; + + if (!trace || !stream_class) { + ret = -1; + goto end; + } + + event_class_count = + bt_ctf_stream_class_get_event_class_count(stream_class); + assert(event_class_count >= 0); + + /* Check for duplicate stream classes */ + for (i = 0; i < trace->stream_classes->len; i++) { + if (trace->stream_classes->pdata[i] == stream_class) { + /* Stream class already registered to the trace */ + ret = -1; + goto end; + } + } + + /* + * If the stream class has a clock, register this clock to this + * trace if not already done. + */ + if (stream_class->clock) { + const char *clock_name = + bt_ctf_clock_get_name(stream_class->clock); + struct bt_ctf_clock *trace_clock; + + assert(clock_name); + trace_clock = bt_ctf_trace_get_clock_by_name(trace, clock_name); + bt_put(trace_clock); + if (trace_clock) { + if (trace_clock != stream_class->clock) { + /* + * Error: two different clocks in the + * trace would share the same name. + */ + ret = -1; + goto end; + } + } else { + clock_to_add_to_trace = bt_get(stream_class->clock); + } + } + + /* + * We're about to freeze both the trace and the stream class. + * Also, each event class contained in this stream class are + * already frozen. + * + * This trace, this stream class, and all its event classes + * should be valid at this point. + * + * Validate trace and stream class first, then each event + * class of this stream class can be validated individually. + */ + packet_header_type = + bt_ctf_trace_get_packet_header_type(trace); + packet_context_type = + bt_ctf_stream_class_get_packet_context_type(stream_class); + event_header_type = + bt_ctf_stream_class_get_event_header_type(stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_get_event_context_type(stream_class); + ret = bt_ctf_validate_class_types(trace->environment, + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, NULL, NULL, trace->valid, + stream_class->valid, 1, &trace_sc_validation_output, + trace_sc_validation_flags); + BT_PUT(packet_header_type); + BT_PUT(packet_context_type); + BT_PUT(event_header_type); + BT_PUT(stream_event_ctx_type); + + if (ret) { + /* + * This means something went wrong during the validation + * process, not that the objects are invalid. + */ + goto end; + } + + if ((trace_sc_validation_output.valid_flags & + trace_sc_validation_flags) != + trace_sc_validation_flags) { + /* Invalid trace/stream class */ + ret = -1; + goto end; + } + + if (event_class_count > 0) { + ec_validation_outputs = g_new0(struct bt_ctf_validation_output, + event_class_count); + if (!ec_validation_outputs) { + ret = -1; + goto end; + } + } + + /* Validate each event class individually */ + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class *event_class = + bt_ctf_stream_class_get_event_class(stream_class, i); + struct bt_ctf_field_type *event_context_type = NULL; + struct bt_ctf_field_type *event_payload_type = NULL; + + event_context_type = + bt_ctf_event_class_get_context_type(event_class); + event_payload_type = + bt_ctf_event_class_get_payload_type(event_class); + + /* + * It is important to use the field types returned by + * the previous trace and stream class validation here + * because copies could have been made. + */ + ret = bt_ctf_validate_class_types(trace->environment, + trace_sc_validation_output.packet_header_type, + trace_sc_validation_output.packet_context_type, + trace_sc_validation_output.event_header_type, + trace_sc_validation_output.stream_event_ctx_type, + event_context_type, event_payload_type, + 1, 1, event_class->valid, &ec_validation_outputs[i], + ec_validation_flags); + BT_PUT(event_context_type); + BT_PUT(event_payload_type); + BT_PUT(event_class); + + if (ret) { + goto end; + } + + if ((ec_validation_outputs[i].valid_flags & + ec_validation_flags) != ec_validation_flags) { + /* Invalid event 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_no_check(stream_class, + stream_id)) { + /* TODO Should retry with a different stream id */ + ret = -1; + goto end; + } + } + + bt_object_set_parent(stream_class, trace); + g_ptr_array_add(trace->stream_classes, stream_class); + + /* + * At this point we know that the function will be successful. + * Therefore we can replace the trace and stream class field + * types with what's in their validation output structure and + * mark them as valid. We can also replace the field types of + * all the event classes of the stream class and mark them as + * valid. + */ + bt_ctf_validation_replace_types(trace, stream_class, NULL, + &trace_sc_validation_output, trace_sc_validation_flags); + trace->valid = 1; + stream_class->valid = 1; + + /* + * Put what was not moved in bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class *event_class = + bt_ctf_stream_class_get_event_class(stream_class, i); + + bt_ctf_validation_replace_types(NULL, NULL, event_class, + &ec_validation_outputs[i], ec_validation_flags); + event_class->valid = 1; + BT_PUT(event_class); + + /* + * Put what was not moved in + * bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&ec_validation_outputs[i]); + } + + /* + * 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); + bt_ctf_stream_class_set_byte_order(stream_class, trace->byte_order); + + /* Add stream class's clock if it exists */ + if (clock_to_add_to_trace) { + int add_clock_ret = + bt_ctf_trace_add_clock(trace, clock_to_add_to_trace); + assert(add_clock_ret == 0); + } + + /* + * Freeze the trace and the stream class. + */ + bt_ctf_stream_class_freeze(stream_class); + bt_ctf_trace_freeze(trace); + +end: + if (ret) { + bt_object_set_parent(stream_class, NULL); + + if (ec_validation_outputs) { + for (i = 0; i < event_class_count; i++) { + bt_ctf_validation_output_put_types( + &ec_validation_outputs[i]); + } + } + } + + g_free(ec_validation_outputs); + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + BT_PUT(clock_to_add_to_trace); + assert(!packet_header_type); + assert(!packet_context_type); + assert(!event_header_type); + assert(!stream_event_ctx_type); + + 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_get(stream_class); +end: + return stream_class; +} + +struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id( + struct bt_ctf_trace *trace, uint32_t id) +{ + int i; + struct bt_ctf_stream_class *stream_class = NULL; + + if (!trace) { + goto end; + } + + for (i = 0; i < trace->stream_classes->len; i++) { + struct bt_ctf_stream_class *stream_class_candidate; + + stream_class_candidate = + g_ptr_array_index(trace->stream_classes, i); + + if (bt_ctf_stream_class_get_id(stream_class_candidate) == + (int64_t) id) { + stream_class = stream_class_candidate; + bt_get(stream_class); + goto end; + } + } + +end: + return stream_class; +} + +struct bt_ctf_clock *bt_ctf_trace_get_clock_by_name( + struct bt_ctf_trace *trace, const char *name) +{ + size_t i; + struct bt_ctf_clock *clock = NULL; + + if (!trace || !name) { + goto end; + } + + for (i = 0; i < trace->clocks->len; i++) { + struct bt_ctf_clock *cur_clk = + g_ptr_array_index(trace->clocks, i); + const char *cur_clk_name = bt_ctf_clock_get_name(cur_clk); + + if (!cur_clk_name) { + goto end; + } + + if (!strcmp(cur_clk_name, name)) { + clock = cur_clk; + bt_get(clock); + goto end; + } + } + +end: + return clock; +} + +BT_HIDDEN +const char *get_byte_order_string(int byte_order) +{ + const char *string; + + switch (byte_order) { + case LITTLE_ENDIAN: + string = "le"; + break; + case BIG_ENDIAN: + string = "be"; + break; + default: + string = "unknown"; + break; + } + + return string; +} + +static +int append_trace_metadata(struct bt_ctf_trace *trace, + struct metadata_context *context) +{ + unsigned char *uuid = trace->uuid; + int ret; + + g_string_append(context->string, "trace {\n"); + + g_string_append(context->string, "\tmajor = 1;\n"); + g_string_append(context->string, "\tminor = 8;\n"); + + g_string_append_printf(context->string, + "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + g_string_append_printf(context->string, "\tbyte_order = %s;\n", + get_byte_order_string(trace->byte_order)); + + g_string_append(context->string, "\tpacket.header := "); + context->current_indentation_level++; + g_string_assign(context->field_name, ""); + ret = bt_ctf_field_type_serialize(trace->packet_header_type, + context); + if (ret) { + goto end; + } + context->current_indentation_level--; + + g_string_append(context->string, ";\n};\n\n"); +end: + return ret; +} + +static +void append_env_metadata(struct bt_ctf_trace *trace, + struct metadata_context *context) +{ + int i; + int env_size; + + env_size = bt_ctf_attributes_get_count(trace->environment); + + if (env_size <= 0) { + return; + } + + g_string_append(context->string, "env {\n"); + + for (i = 0; i < env_size; i++) { + struct bt_value *env_field_value_obj = NULL; + const char *entry_name; + + entry_name = bt_ctf_attributes_get_field_name( + trace->environment, i); + env_field_value_obj = bt_ctf_attributes_get_field_value( + trace->environment, i); + + if (!entry_name || !env_field_value_obj) { + goto loop_next; + } + + switch (bt_value_get_type(env_field_value_obj)) { + case BT_VALUE_TYPE_INTEGER: + { + int ret; + int64_t int_value; + + ret = bt_value_integer_get(env_field_value_obj, + &int_value); + + if (ret) { + goto loop_next; + } + + g_string_append_printf(context->string, + "\t%s = %" PRId64 ";\n", entry_name, + int_value); + break; + } + case BT_VALUE_TYPE_STRING: + { + int ret; + const char *str_value; + char *escaped_str = NULL; + + ret = bt_value_string_get(env_field_value_obj, + &str_value); + + if (ret) { + goto loop_next; + } + + escaped_str = g_strescape(str_value, NULL); + + if (!escaped_str) { + goto loop_next; + } + + g_string_append_printf(context->string, + "\t%s = \"%s\";\n", entry_name, escaped_str); + free(escaped_str); + break; + } + + default: + goto loop_next; + } + +loop_next: + BT_PUT(env_field_value_obj); + } + + g_string_append(context->string, "};\n\n"); +} + +char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace) +{ + char *metadata = NULL; + struct metadata_context *context = NULL; + int err = 0; + size_t i; + + if (!trace) { + goto end; + } + + context = g_new0(struct metadata_context, 1); + if (!context) { + goto end; + } + + context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE); + context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE); + g_string_append(context->string, "/* CTF 1.8 */\n\n"); + if (append_trace_metadata(trace, context)) { + goto error; + } + append_env_metadata(trace, context); + g_ptr_array_foreach(trace->clocks, + (GFunc)bt_ctf_clock_serialize, context); + + for (i = 0; i < trace->stream_classes->len; i++) { + err = bt_ctf_stream_class_serialize( + trace->stream_classes->pdata[i], context); + if (err) { + goto error; + } + } + + metadata = context->string->str; +error: + g_string_free(context->string, err ? TRUE : FALSE); + g_string_free(context->field_name, TRUE); + g_free(context); +end: + 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) +{ + int ret = 0; + int internal_byte_order; + + if (!trace || trace->frozen) { + ret = -1; + goto end; + } + + switch (byte_order) { + case BT_CTF_BYTE_ORDER_NATIVE: + /* + * 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: + internal_byte_order = LITTLE_ENDIAN; + break; + case BT_CTF_BYTE_ORDER_BIG_ENDIAN: + case BT_CTF_BYTE_ORDER_NETWORK: + internal_byte_order = BIG_ENDIAN; + break; + default: + ret = -1; + goto end; + } + + trace->byte_order = internal_byte_order; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type( + struct bt_ctf_trace *trace) +{ + struct bt_ctf_field_type *field_type = NULL; + + if (!trace) { + goto end; + } + + bt_get(trace->packet_header_type); + field_type = trace->packet_header_type; +end: + return field_type; +} + +int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace, + struct bt_ctf_field_type *packet_header_type) +{ + int ret = 0; + + if (!trace || !packet_header_type || trace->frozen) { + ret = -1; + goto end; + } + + /* packet_header_type must be a structure */ + if (bt_ctf_field_type_get_type_id(packet_header_type) != + BT_CTF_TYPE_ID_STRUCT) { + ret = -1; + goto end; + } + + bt_get(packet_header_type); + bt_put(trace->packet_header_type); + trace->packet_header_type = packet_header_type; +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) +{ + int ret; + unsigned int alignment, size; + struct bt_ctf_field_type *field_type = NULL; + + if (alias >= NR_FIELD_TYPE_ALIAS) { + goto end; + } + + alignment = field_type_aliases_alignments[alias]; + size = field_type_aliases_sizes[alias]; + field_type = bt_ctf_field_type_integer_create(size); + ret = bt_ctf_field_type_set_alignment(field_type, alignment); + if (ret) { + BT_PUT(field_type); + } +end: + return field_type; +} + +static +void bt_ctf_trace_freeze(struct bt_ctf_trace *trace) +{ + int i; + + bt_ctf_field_type_freeze(trace->packet_header_type); + bt_ctf_attributes_freeze(trace->environment); + + for (i = 0; i < trace->clocks->len; i++) { + struct bt_ctf_clock *clock = + g_ptr_array_index(trace->clocks, i); + + bt_ctf_clock_freeze(clock); + } + + trace->frozen = 1; +} + +static +int init_trace_packet_header(struct bt_ctf_trace *trace) +{ + int ret = 0; + struct bt_ctf_field *magic = NULL, *uuid_array = NULL; + struct bt_ctf_field_type *_uint32_t = + get_field_type(FIELD_TYPE_ALIAS_UINT32_T); + struct bt_ctf_field_type *_uint8_t = + get_field_type(FIELD_TYPE_ALIAS_UINT8_T); + struct bt_ctf_field_type *trace_packet_header_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *uuid_array_type = + bt_ctf_field_type_array_create(_uint8_t, 16); + + if (!trace_packet_header_type || !uuid_array_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + _uint32_t, "magic"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + uuid_array_type, "uuid"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + _uint32_t, "stream_id"); + if (ret) { + goto end; + } + + ret = bt_ctf_trace_set_packet_header_type(trace, + trace_packet_header_type); + if (ret) { + goto end; + } +end: + bt_put(uuid_array_type); + bt_put(_uint32_t); + bt_put(_uint8_t); + bt_put(magic); + bt_put(uuid_array); + bt_put(trace_packet_header_type); + return ret; +} diff --git a/formats/ctf/ir/utils.c b/formats/ctf/ir/utils.c new file mode 100644 index 00000000..318b12da --- /dev/null +++ b/formats/ctf/ir/utils.c @@ -0,0 +1,106 @@ +/* + * utils.c + * + * Babeltrace CTF IR - Utilities + * + * Copyright 2015 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +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 GHashTable *reserved_keywords_set; +static int init_done; +static int global_data_refcount; + +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); + } +} + +int bt_ctf_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; +} diff --git a/formats/ctf/ir/validation.c b/formats/ctf/ir/validation.c new file mode 100644 index 00000000..f3a2c71e --- /dev/null +++ b/formats/ctf/ir/validation.c @@ -0,0 +1,594 @@ +/* + * validation.c + * + * Babeltrace - CTF IR: Validation of trace, stream class, and event class + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _printf_error(fmt, args...) \ + printf_verbose("[validation] " fmt, ## args) + +/* + * This function resolves and validates the field types of an event + * class. Only `event_context_type` and `event_payload_type` are + * resolved and validated; the other field types are used as eventual + * resolving targets. + * + * All parameters are owned by the caller. + */ +static +int validate_event_class_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *event_payload_type) +{ + int ret = 0; + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + packet_context_type, event_header_type, stream_event_ctx_type, + event_context_type, event_payload_type, + BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT | + BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD); + if (ret) { + _printf_error("Cannot resolve event class types\n"); + goto end; + } + + /* Validate field types individually */ + if (event_context_type) { + ret = bt_ctf_field_type_validate(event_context_type); + if (ret) { + _printf_error("Invalid event context type\n"); + goto end; + } + } + + if (event_payload_type) { + ret = bt_ctf_field_type_validate(event_payload_type); + if (ret) { + _printf_error("Invalid event payload type\n"); + goto end; + } + } + +end: + return ret; +} + +/* + * This function resolves and validates the field types of a stream + * class. Only `packet_context_type`, `event_header_type`, and + * `stream_event_ctx_type` are resolved and validated; the other field + * type is used as an eventual resolving target. + * + * All parameters are owned by the caller. + */ +static +int validate_stream_class_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type) +{ + int ret = 0; + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + packet_context_type, event_header_type, stream_event_ctx_type, + NULL, NULL, + BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT | + BT_CTF_RESOLVE_FLAG_EVENT_HEADER | + BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX); + if (ret) { + _printf_error("Cannot resolve stream class types\n"); + goto end; + } + + /* Validate field types individually */ + if (packet_context_type) { + ret = bt_ctf_field_type_validate(packet_context_type); + if (ret) { + _printf_error("Invalid stream packet context type\n"); + goto end; + } + } + + if (event_header_type) { + ret = bt_ctf_field_type_validate(event_header_type); + if (ret) { + _printf_error("Invalid stream event header type\n"); + goto end; + } + } + + if (stream_event_ctx_type) { + ret = bt_ctf_field_type_validate( + stream_event_ctx_type); + if (ret) { + _printf_error("Invalid stream event context type\n"); + goto end; + } + } + +end: + return ret; +} + +/* + * This function resolves and validates the field types of a trace. + * + * All parameters are owned by the caller. + */ +static +int validate_trace_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type) +{ + int ret = 0; + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + NULL, NULL, NULL, NULL, NULL, + BT_CTF_RESOLVE_FLAG_PACKET_HEADER); + if (ret) { + _printf_error("Cannot resolve trace types\n"); + goto end; + } + + /* Validate field types individually */ + if (packet_header_type) { + ret = bt_ctf_field_type_validate(packet_header_type); + if (ret) { + _printf_error("Invalid trace packet header type\n"); + goto end; + } + } + +end: + return ret; +} + +/* + * Checks whether or not `field_type` contains a variant or a sequence + * field type, recursively. Returns 1 if it's the case. + * + * `field_type` is owned by the caller. + */ +static +int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type *type) +{ + int ret = 0; + enum bt_ctf_type_id type_id = bt_ctf_field_type_get_type_id(type); + + switch (type_id) { + case BT_CTF_TYPE_ID_SEQUENCE: + case BT_CTF_TYPE_ID_VARIANT: + ret = 1; + goto end; + case BT_CTF_TYPE_ID_ARRAY: + case BT_CTF_TYPE_ID_STRUCT: + { + int i; + int field_count = bt_ctf_field_type_get_field_count(type); + + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + struct bt_ctf_field_type *child_type = + bt_ctf_field_type_get_field_at_index(type, i); + + ret = field_type_contains_sequence_or_variant_ft( + child_type); + BT_PUT(child_type); + if (ret != 0) { + goto end; + } + } + break; + } + default: + break; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_validate_class_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *event_payload_type, + int trace_valid, int stream_class_valid, int event_class_valid, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag validate_flags) +{ + int ret = 0; + int contains_seq_var; + int valid_ret; + + /* Clean output values */ + memset(output, 0, sizeof(*output)); + + /* Set initial valid flags according to valid parameters */ + if (trace_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; + } + + if (stream_class_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; + } + + if (event_class_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; + } + + /* Own the type parameters */ + bt_get(packet_header_type); + bt_get(packet_context_type); + bt_get(event_header_type); + bt_get(stream_event_ctx_type); + bt_get(event_context_type); + bt_get(event_payload_type); + + /* Validate trace */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) { + struct bt_ctf_field_type *packet_header_type_copy = NULL; + + /* Create field type copies */ + if (packet_header_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + packet_header_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + packet_header_type_copy = packet_header_type; + bt_get(packet_header_type_copy); + goto skip_packet_header_type_copy; + } + + packet_header_type_copy = + bt_ctf_field_type_copy(packet_header_type); + if (!packet_header_type_copy) { + ret = -1; + _printf_error("Cannot copy packet header type\n"); + goto error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(packet_header_type_copy); + } + +skip_packet_header_type_copy: + /* Put original reference and move copy */ + BT_MOVE(packet_header_type, packet_header_type_copy); + + /* Validate trace field types */ + valid_ret = validate_trace_types(environment, + packet_header_type); + if (!valid_ret) { + /* Trace is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; + } + } + + /* Validate stream class */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) && + !stream_class_valid) { + struct bt_ctf_field_type *packet_context_type_copy = NULL; + struct bt_ctf_field_type *event_header_type_copy = NULL; + struct bt_ctf_field_type *stream_event_ctx_type_copy = NULL; + + if (packet_context_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + packet_context_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + packet_context_type_copy = packet_context_type; + bt_get(packet_context_type_copy); + goto skip_packet_context_type_copy; + } + + packet_context_type_copy = + bt_ctf_field_type_copy(packet_context_type); + if (!packet_context_type_copy) { + _printf_error("Cannot copy packet context type\n"); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(packet_context_type_copy); + } + +skip_packet_context_type_copy: + if (event_header_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_header_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_header_type_copy = event_header_type; + bt_get(event_header_type_copy); + goto skip_event_header_type_copy; + } + + event_header_type_copy = + bt_ctf_field_type_copy(event_header_type); + if (!event_header_type_copy) { + _printf_error("Cannot copy event header type\n"); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(event_header_type_copy); + } + +skip_event_header_type_copy: + if (stream_event_ctx_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + stream_event_ctx_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + stream_event_ctx_type_copy = + stream_event_ctx_type; + bt_get(stream_event_ctx_type_copy); + goto skip_stream_event_ctx_type_copy; + } + + stream_event_ctx_type_copy = + bt_ctf_field_type_copy(stream_event_ctx_type); + if (!stream_event_ctx_type_copy) { + _printf_error("Cannot copy stream event context type\n"); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(stream_event_ctx_type_copy); + } + +skip_stream_event_ctx_type_copy: + /* Put original references and move copies */ + BT_MOVE(packet_context_type, packet_context_type_copy); + BT_MOVE(event_header_type, event_header_type_copy); + BT_MOVE(stream_event_ctx_type, stream_event_ctx_type_copy); + + /* Validate stream class field types */ + valid_ret = validate_stream_class_types(environment, + packet_header_type, packet_context_type, + event_header_type, stream_event_ctx_type); + if (!valid_ret) { + /* Stream class is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; + } + + goto sc_validation_done; + +sc_validation_error: + BT_PUT(packet_context_type_copy); + BT_PUT(event_header_type_copy); + BT_PUT(stream_event_ctx_type_copy); + ret = -1; + goto error; + } + +sc_validation_done: + /* Validate event class */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) && + !event_class_valid) { + struct bt_ctf_field_type *event_context_type_copy = NULL; + struct bt_ctf_field_type *event_payload_type_copy = NULL; + + if (event_context_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_context_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_context_type_copy = event_context_type; + bt_get(event_context_type_copy); + goto skip_event_context_type_copy; + } + + event_context_type_copy = + bt_ctf_field_type_copy(event_context_type); + if (!event_context_type_copy) { + _printf_error("Cannot copy event context type\n"); + goto ec_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(event_context_type_copy); + } + +skip_event_context_type_copy: + if (event_payload_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_payload_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_payload_type_copy = event_payload_type; + bt_get(event_payload_type_copy); + goto skip_event_payload_type_copy; + } + + event_payload_type_copy = + bt_ctf_field_type_copy(event_payload_type); + if (!event_payload_type_copy) { + _printf_error("Cannot copy event payload type\n"); + goto ec_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_freeze(event_payload_type_copy); + } + +skip_event_payload_type_copy: + /* Put original references and move copies */ + BT_MOVE(event_context_type, event_context_type_copy); + BT_MOVE(event_payload_type, event_payload_type_copy); + + /* Validate event class field types */ + valid_ret = validate_event_class_types(environment, + packet_header_type, packet_context_type, + event_header_type, stream_event_ctx_type, + event_context_type, event_payload_type); + if (!valid_ret) { + /* Event class is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; + } + + goto ec_validation_done; + +ec_validation_error: + BT_PUT(event_context_type_copy); + BT_PUT(event_payload_type_copy); + ret = -1; + goto error; + } + +ec_validation_done: + /* + * Validation is complete. Move the field types that were used + * to validate (and that were possibly altered by the validation + * process) to the output values. + */ + BT_MOVE(output->packet_header_type, packet_header_type); + BT_MOVE(output->packet_context_type, packet_context_type); + BT_MOVE(output->event_header_type, event_header_type); + BT_MOVE(output->stream_event_ctx_type, stream_event_ctx_type); + BT_MOVE(output->event_context_type, event_context_type); + BT_MOVE(output->event_payload_type, event_payload_type); + + return ret; + +error: + 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); + + return ret; +} + +BT_HIDDEN +void bt_ctf_validation_replace_types(struct bt_ctf_trace *trace, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag replace_flags) +{ + if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) { + BT_MOVE(trace->packet_header_type, output->packet_header_type); + } + + if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) { + BT_MOVE(stream_class->packet_context_type, + output->packet_context_type); + BT_MOVE(stream_class->event_header_type, + output->event_header_type); + BT_MOVE(stream_class->event_context_type, + output->stream_event_ctx_type); + } + + if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) { + BT_MOVE(event_class->context, output->event_context_type); + BT_MOVE(event_class->fields, output->event_payload_type); + } +} + +BT_HIDDEN +void bt_ctf_validation_output_put_types( + struct bt_ctf_validation_output *output) +{ + BT_PUT(output->packet_header_type); + BT_PUT(output->packet_context_type); + BT_PUT(output->event_header_type); + BT_PUT(output->stream_event_ctx_type); + BT_PUT(output->event_context_type); + BT_PUT(output->event_payload_type); +} diff --git a/formats/ctf/writer/Makefile.am b/formats/ctf/writer/Makefile.am index 84ac03d5..1f06c1af 100644 --- a/formats/ctf/writer/Makefile.am +++ b/formats/ctf/writer/Makefile.am @@ -4,11 +4,6 @@ noinst_LTLIBRARIES = libctf-writer.la libctf_writer_la_SOURCES = \ writer.c \ - clock.c \ - stream.c \ - event-types.c \ - event-fields.c \ - event.c \ functor.c libctf_writer_la_LIBADD = \ diff --git a/formats/ctf/writer/clock.c b/formats/ctf/writer/clock.c deleted file mode 100644 index 1146e005..00000000 --- a/formats/ctf/writer/clock.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * clock.c - * - * Babeltrace CTF Writer - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include - -static -void bt_ctf_clock_destroy(struct bt_ctf_ref *ref); - -struct bt_ctf_clock *bt_ctf_clock_create(const char *name) -{ - struct bt_ctf_clock *clock = NULL; - - if (validate_identifier(name)) { - goto error; - } - - clock = g_new0(struct bt_ctf_clock, 1); - if (!clock) { - goto error; - } - - clock->name = g_string_new(name); - if (!clock->name) { - goto error_destroy; - } - - clock->description = g_string_new(NULL); - if (!clock->description) { - goto error_destroy; - } - - clock->precision = 1; - clock->frequency = 1000000000; - uuid_generate(clock->uuid); - bt_ctf_ref_init(&clock->ref_count); - return clock; -error_destroy: - bt_ctf_clock_destroy(&clock->ref_count); -error: - clock = NULL; - return clock; -} - -int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc) -{ - int ret = 0; - - if (!clock || !desc || clock->frozen) { - ret = -1; - goto end; - } - - clock->description = g_string_assign(clock->description, desc); - ret = clock->description ? 0 : -1; -end: - return ret; -} - -int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq) -{ - int ret = 0; - - if (!clock || clock->frozen) { - ret = -1; - goto end; - } - - clock->frequency = freq; -end: - return ret; -} - -int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision) -{ - int ret = 0; - - if (!clock || clock->frozen) { - ret = -1; - goto end; - } - - clock->precision = precision; -end: - return ret; -} - -int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, uint64_t offset_s) -{ - int ret = 0; - - if (!clock || clock->frozen) { - ret = -1; - goto end; - } - - clock->offset_s = offset_s; -end: - return ret; -} - -int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, uint64_t offset) -{ - int ret = 0; - - if (!clock || clock->frozen) { - ret = -1; - goto end; - } - - clock->offset = offset; -end: - return ret; -} - -int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute) -{ - int ret = 0; - - if (!clock || clock->frozen) { - ret = -1; - goto end; - } - - clock->absolute = !!is_absolute; -end: - return ret; -} - -int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, uint64_t time) -{ - int ret = 0; - - /* Timestamps are strictly monotonic */ - if (!clock || time < clock->time) { - ret = -1; - goto end; - } - - clock->time = time; -end: - return ret; -} - -void bt_ctf_clock_get(struct bt_ctf_clock *clock) -{ - if (!clock) { - return; - } - - bt_ctf_ref_get(&clock->ref_count); -} - -void bt_ctf_clock_put(struct bt_ctf_clock *clock) -{ - if (!clock) { - return; - } - - bt_ctf_ref_put(&clock->ref_count, bt_ctf_clock_destroy); -} - -BT_HIDDEN -void bt_ctf_clock_freeze(struct bt_ctf_clock *clock) -{ - if (!clock) { - return; - } - - clock->frozen = 1; -} - -BT_HIDDEN -void bt_ctf_clock_serialize(struct bt_ctf_clock *clock, - struct metadata_context *context) -{ - unsigned char *uuid; - - if (!clock || !context) { - return; - } - - uuid = clock->uuid; - g_string_append(context->string, "clock {\n"); - g_string_append_printf(context->string, "\tname = %s;\n", - clock->name->str); - g_string_append_printf(context->string, - "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - if (clock->description->len) { - g_string_append_printf(context->string, "\tdescription = \"%s\";\n", - clock->description->str); - } - - g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", - clock->frequency); - g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", - clock->precision); - g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", - clock->offset_s); - g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", - clock->offset); - g_string_append_printf(context->string, "\tabsolute = %s;\n", - clock->absolute ? "TRUE" : "FALSE"); - g_string_append(context->string, "};\n\n"); -} - -BT_HIDDEN -uint64_t bt_ctf_clock_get_time(struct bt_ctf_clock *clock) -{ - return clock ? clock->time : 0; -} - -static -void bt_ctf_clock_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_clock *clock; - - if (!ref) { - return; - } - - clock = container_of(ref, struct bt_ctf_clock, ref_count); - if (clock->name) { - g_string_free(clock->name, TRUE); - } - - if (clock->description) { - g_string_free(clock->description, TRUE); - } - - g_free(clock); -} diff --git a/formats/ctf/writer/event-fields.c b/formats/ctf/writer/event-fields.c deleted file mode 100644 index 1ffbd4a3..00000000 --- a/formats/ctf/writer/event-fields.c +++ /dev/null @@ -1,1262 +0,0 @@ -/* - * event-fields.c - * - * Babeltrace CTF Writer - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#define PACKET_LEN_INCREMENT (getpagesize() * 8 * CHAR_BIT) - -static -struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_enumeration_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_floating_point_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_structure_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_variant_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_array_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_sequence_create( - struct bt_ctf_field_type *); -static -struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *); - -static -void bt_ctf_field_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_integer_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_structure_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_variant_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_array_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_sequence_destroy(struct bt_ctf_field *); -static -void bt_ctf_field_string_destroy(struct bt_ctf_field *); - -static -int bt_ctf_field_generic_validate(struct bt_ctf_field *field); -static -int bt_ctf_field_structure_validate(struct bt_ctf_field *field); -static -int bt_ctf_field_variant_validate(struct bt_ctf_field *field); -static -int bt_ctf_field_enumeration_validate(struct bt_ctf_field *field); -static -int bt_ctf_field_array_validate(struct bt_ctf_field *field); -static -int bt_ctf_field_sequence_validate(struct bt_ctf_field *field); - -static -int bt_ctf_field_integer_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_structure_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_variant_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_array_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_sequence_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); -static -int bt_ctf_field_string_serialize(struct bt_ctf_field *, - struct ctf_stream_pos *); - -static -int increase_packet_size(struct ctf_stream_pos *pos); - -static -struct bt_ctf_field *(*field_create_funcs[])( - struct bt_ctf_field_type *) = { - [CTF_TYPE_INTEGER] = bt_ctf_field_integer_create, - [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_create, - [CTF_TYPE_FLOAT] = - bt_ctf_field_floating_point_create, - [CTF_TYPE_STRUCT] = bt_ctf_field_structure_create, - [CTF_TYPE_VARIANT] = bt_ctf_field_variant_create, - [CTF_TYPE_ARRAY] = bt_ctf_field_array_create, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_create, - [CTF_TYPE_STRING] = bt_ctf_field_string_create, -}; - -static -void (*field_destroy_funcs[])(struct bt_ctf_field *) = { - [CTF_TYPE_INTEGER] = bt_ctf_field_integer_destroy, - [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_destroy, - [CTF_TYPE_FLOAT] = - bt_ctf_field_floating_point_destroy, - [CTF_TYPE_STRUCT] = bt_ctf_field_structure_destroy, - [CTF_TYPE_VARIANT] = bt_ctf_field_variant_destroy, - [CTF_TYPE_ARRAY] = bt_ctf_field_array_destroy, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_destroy, - [CTF_TYPE_STRING] = bt_ctf_field_string_destroy, -}; - -static -int (*field_validate_funcs[])(struct bt_ctf_field *) = { - [CTF_TYPE_INTEGER] = bt_ctf_field_generic_validate, - [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_validate, - [CTF_TYPE_FLOAT] = bt_ctf_field_generic_validate, - [CTF_TYPE_STRUCT] = bt_ctf_field_structure_validate, - [CTF_TYPE_VARIANT] = bt_ctf_field_variant_validate, - [CTF_TYPE_ARRAY] = bt_ctf_field_array_validate, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_validate, - [CTF_TYPE_STRING] = bt_ctf_field_generic_validate, -}; - -static -int (*field_serialize_funcs[])(struct bt_ctf_field *, - struct ctf_stream_pos *) = { - [CTF_TYPE_INTEGER] = bt_ctf_field_integer_serialize, - [CTF_TYPE_ENUM] = bt_ctf_field_enumeration_serialize, - [CTF_TYPE_FLOAT] = - bt_ctf_field_floating_point_serialize, - [CTF_TYPE_STRUCT] = bt_ctf_field_structure_serialize, - [CTF_TYPE_VARIANT] = bt_ctf_field_variant_serialize, - [CTF_TYPE_ARRAY] = bt_ctf_field_array_serialize, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_sequence_serialize, - [CTF_TYPE_STRING] = bt_ctf_field_string_serialize, -}; - -struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field *field = NULL; - enum ctf_type_id type_id; - - if (!type) { - goto error; - } - - type_id = bt_ctf_field_type_get_type_id(type); - if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES || - bt_ctf_field_type_validate(type)) { - goto error; - } - - field = field_create_funcs[type_id](type); - if (!field) { - goto error; - } - - /* The type's declaration can't change after this point */ - bt_ctf_field_type_freeze(type); - bt_ctf_field_type_get(type); - bt_ctf_ref_init(&field->ref_count); - field->type = type; -error: - return field; -} - -void bt_ctf_field_get(struct bt_ctf_field *field) -{ - if (field) { - bt_ctf_ref_get(&field->ref_count); - } -} - -void bt_ctf_field_put(struct bt_ctf_field *field) -{ - if (field) { - bt_ctf_ref_put(&field->ref_count, bt_ctf_field_destroy); - } -} - -int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field, - struct bt_ctf_field *length_field) -{ - int ret = 0; - struct bt_ctf_field_type_integer *length_type; - struct bt_ctf_field_integer *length; - struct bt_ctf_field_sequence *sequence; - uint64_t sequence_length; - - if (!field || !length_field) { - ret = -1; - goto end; - } - if (bt_ctf_field_type_get_type_id(length_field->type) != - CTF_TYPE_INTEGER) { - ret = -1; - goto end; - } - - length_type = container_of(length_field->type, - struct bt_ctf_field_type_integer, parent); - if (length_type->declaration.signedness) { - ret = -1; - goto end; - } - - length = container_of(length_field, struct bt_ctf_field_integer, - parent); - sequence_length = length->definition.value._unsigned; - sequence = container_of(field, struct bt_ctf_field_sequence, parent); - if (sequence->elements) { - g_ptr_array_free(sequence->elements, TRUE); - bt_ctf_field_put(sequence->length); - } - - sequence->elements = g_ptr_array_sized_new((size_t)sequence_length); - if (!sequence->elements) { - ret = -1; - goto end; - } - - g_ptr_array_set_free_func(sequence->elements, - (GDestroyNotify)bt_ctf_field_put); - g_ptr_array_set_size(sequence->elements, (size_t)sequence_length); - bt_ctf_field_get(length_field); - sequence->length = length_field; -end: - return ret; -} - -struct bt_ctf_field *bt_ctf_field_structure_get_field( - struct bt_ctf_field *field, const char *name) -{ - struct bt_ctf_field *new_field = NULL; - GQuark field_quark; - struct bt_ctf_field_structure *structure; - struct bt_ctf_field_type_structure *structure_type; - struct bt_ctf_field_type *field_type; - size_t index; - - if (!field || !name || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_STRUCT) { - goto error; - } - - field_quark = g_quark_from_string(name); - structure = container_of(field, struct bt_ctf_field_structure, parent); - structure_type = container_of(field->type, - struct bt_ctf_field_type_structure, parent); - field_type = bt_ctf_field_type_structure_get_type(structure_type, name); - if (!g_hash_table_lookup_extended(structure->field_name_to_index, - GUINT_TO_POINTER(field_quark), NULL, (gpointer *)&index)) { - goto error; - } - - if (structure->fields->pdata[index]) { - new_field = structure->fields->pdata[index]; - goto end; - } - - new_field = bt_ctf_field_create(field_type); - if (!new_field) { - goto error; - } - - structure->fields->pdata[index] = new_field; -end: - bt_ctf_field_get(new_field); -error: - return new_field; -} - -BT_HIDDEN -int bt_ctf_field_structure_set_field(struct bt_ctf_field *field, - const char *name, struct bt_ctf_field *value) -{ - int ret = 0; - GQuark field_quark; - struct bt_ctf_field_structure *structure; - struct bt_ctf_field_type_structure *structure_type; - struct bt_ctf_field_type *expected_field_type; - size_t index; - - if (!field || !name || !value || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_STRUCT) { - ret = -1; - goto end; - } - - field_quark = g_quark_from_string(name); - structure = container_of(field, struct bt_ctf_field_structure, parent); - structure_type = container_of(field->type, - struct bt_ctf_field_type_structure, parent); - expected_field_type = bt_ctf_field_type_structure_get_type( - structure_type, name); - if (expected_field_type != value->type) { - ret = -1; - goto end; - } - - if (!g_hash_table_lookup_extended(structure->field_name_to_index, - GUINT_TO_POINTER(field_quark), NULL, (gpointer *) &index)) { - goto end; - } - - if (structure->fields->pdata[index]) { - bt_ctf_field_put(structure->fields->pdata[index]); - } - - structure->fields->pdata[index] = value; - bt_ctf_field_get(value); -end: - return ret; -} - -struct bt_ctf_field *bt_ctf_field_array_get_field(struct bt_ctf_field *field, - uint64_t index) -{ - struct bt_ctf_field *new_field = NULL; - struct bt_ctf_field_array *array; - struct bt_ctf_field_type_array *array_type; - struct bt_ctf_field_type *field_type; - - if (!field || bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_ARRAY) { - goto end; - } - - array = container_of(field, struct bt_ctf_field_array, parent); - if (index >= array->elements->len) { - goto end; - } - - array_type = container_of(field->type, struct bt_ctf_field_type_array, - parent); - field_type = bt_ctf_field_type_array_get_element_type(array_type); - if (array->elements->pdata[(size_t)index]) { - new_field = array->elements->pdata[(size_t)index]; - goto end; - } - - new_field = bt_ctf_field_create(field_type); - bt_ctf_field_get(new_field); - array->elements->pdata[(size_t)index] = new_field; -end: - return new_field; -} - -struct bt_ctf_field *bt_ctf_field_sequence_get_field(struct bt_ctf_field *field, - uint64_t index) -{ - struct bt_ctf_field *new_field = NULL; - struct bt_ctf_field_sequence *sequence; - struct bt_ctf_field_type_sequence *sequence_type; - struct bt_ctf_field_type *field_type; - - if (!field || bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_SEQUENCE) { - goto end; - } - - sequence = container_of(field, struct bt_ctf_field_sequence, parent); - if (!sequence->elements || sequence->elements->len <= index) { - goto end; - } - - sequence_type = container_of(field->type, - struct bt_ctf_field_type_sequence, parent); - field_type = bt_ctf_field_type_sequence_get_element_type(sequence_type); - if (sequence->elements->pdata[(size_t)index]) { - new_field = sequence->elements->pdata[(size_t)index]; - goto end; - } - - new_field = bt_ctf_field_create(field_type); - bt_ctf_field_get(new_field); - sequence->elements->pdata[(size_t)index] = new_field; -end: - return new_field; -} - -struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field, - struct bt_ctf_field *tag_field) -{ - struct bt_ctf_field *new_field = NULL; - struct bt_ctf_field_variant *variant; - struct bt_ctf_field_type_variant *variant_type; - struct bt_ctf_field_type *field_type; - struct bt_ctf_field *tag_enum = NULL; - struct bt_ctf_field_integer *tag_enum_integer; - int64_t tag_enum_value; - - if (!field || !tag_field || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_VARIANT || - bt_ctf_field_type_get_type_id(tag_field->type) != - CTF_TYPE_ENUM) { - goto end; - } - - variant = container_of(field, struct bt_ctf_field_variant, parent); - variant_type = container_of(field->type, - struct bt_ctf_field_type_variant, parent); - tag_enum = bt_ctf_field_enumeration_get_container(tag_field); - if (!tag_enum) { - goto end; - } - - tag_enum_integer = container_of(tag_enum, struct bt_ctf_field_integer, - parent); - - if (bt_ctf_field_validate(tag_field) < 0) { - goto end; - } - - tag_enum_value = tag_enum_integer->definition.value._signed; - field_type = bt_ctf_field_type_variant_get_field_type(variant_type, - tag_enum_value); - if (!field_type) { - goto end; - } - - new_field = bt_ctf_field_create(field_type); - if (!new_field) { - goto end; - } - - bt_ctf_field_put(variant->tag); - bt_ctf_field_put(variant->payload); - bt_ctf_field_get(new_field); - bt_ctf_field_get(tag_field); - variant->tag = tag_field; - variant->payload = new_field; -end: - bt_ctf_field_put(tag_enum); - return new_field; -} - -struct bt_ctf_field *bt_ctf_field_enumeration_get_container( - struct bt_ctf_field *field) -{ - struct bt_ctf_field *container = NULL; - struct bt_ctf_field_enumeration *enumeration; - - if (!field) { - goto end; - } - - enumeration = container_of(field, struct bt_ctf_field_enumeration, - parent); - if (!enumeration->payload) { - struct bt_ctf_field_type_enumeration *enumeration_type = - container_of(field->type, - struct bt_ctf_field_type_enumeration, parent); - enumeration->payload = - bt_ctf_field_create(enumeration_type->container); - } - - container = enumeration->payload; - bt_ctf_field_get(container); -end: - return container; -} - -int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *field, - int64_t value) -{ - int ret = 0; - struct bt_ctf_field_integer *integer; - struct bt_ctf_field_type_integer *integer_type; - unsigned int size; - int64_t min_value, max_value; - - if (!field || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_INTEGER) { - ret = -1; - goto end; - } - - integer = container_of(field, struct bt_ctf_field_integer, parent); - integer_type = container_of(field->type, - struct bt_ctf_field_type_integer, parent); - if (!integer_type->declaration.signedness) { - ret = -1; - goto end; - } - - size = integer_type->declaration.len; - min_value = -(1ULL << (size - 1)); - max_value = (1ULL << (size - 1)) - 1; - if (value < min_value || value > max_value) { - ret = -1; - goto end; - } - - integer->definition.value._signed = value; - integer->parent.payload_set = 1; -end: - return ret; -} - -int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *field, - uint64_t value) -{ - int ret = 0; - struct bt_ctf_field_integer *integer; - struct bt_ctf_field_type_integer *integer_type; - unsigned int size; - uint64_t max_value; - - if (!field || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_INTEGER) { - ret = -1; - goto end; - } - - integer = container_of(field, struct bt_ctf_field_integer, parent); - integer_type = container_of(field->type, - struct bt_ctf_field_type_integer, parent); - if (integer_type->declaration.signedness) { - ret = -1; - goto end; - } - - size = integer_type->declaration.len; - max_value = (size == 64) ? UINT64_MAX : ((uint64_t)1 << size) - 1; - if (value > max_value) { - ret = -1; - goto end; - } - - integer->definition.value._unsigned = value; - integer->parent.payload_set = 1; -end: - return ret; -} - -int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field, - double value) -{ - int ret = 0; - struct bt_ctf_field_floating_point *floating_point; - - if (!field || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_FLOAT) { - ret = -1; - goto end; - } - floating_point = container_of(field, struct bt_ctf_field_floating_point, - parent); - floating_point->definition.value = value; - floating_point->parent.payload_set = 1; -end: - return ret; -} - -int bt_ctf_field_string_set_value(struct bt_ctf_field *field, - const char *value) -{ - int ret = 0; - struct bt_ctf_field_string *string; - - if (!field || !value || - bt_ctf_field_type_get_type_id(field->type) != - CTF_TYPE_STRING) { - ret = -1; - goto end; - } - - string = container_of(field, struct bt_ctf_field_string, parent); - if (string->payload) { - g_string_free(string->payload, TRUE); - } - - string->payload = g_string_new(value); - string->parent.payload_set = 1; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_validate(struct bt_ctf_field *field) -{ - int ret = 0; - enum ctf_type_id type_id; - - if (!field) { - ret = -1; - goto end; - } - - type_id = bt_ctf_field_type_get_type_id(field->type); - if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) { - ret = -1; - goto end; - } - - ret = field_validate_funcs[type_id](field); -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - int ret = 0; - enum ctf_type_id type_id; - - if (!field || !pos) { - ret = -1; - goto end; - } - - type_id = bt_ctf_field_type_get_type_id(field->type); - if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) { - ret = -1; - goto end; - } - - ret = field_serialize_funcs[type_id](field, pos); -end: - return ret; -} - -static -struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_integer *integer_type = container_of(type, - struct bt_ctf_field_type_integer, parent); - struct bt_ctf_field_integer *integer = g_new0( - struct bt_ctf_field_integer, 1); - - if (integer) { - integer->definition.declaration = &integer_type->declaration; - } - - return integer ? &integer->parent : NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_enumeration_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_enumeration *enumeration = g_new0( - struct bt_ctf_field_enumeration, 1); - - return enumeration ? &enumeration->parent : NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_floating_point_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_floating_point *floating_point; - struct bt_ctf_field_type_floating_point *floating_point_type; - - floating_point = g_new0(struct bt_ctf_field_floating_point, 1); - if (!floating_point) { - goto end; - } - - floating_point_type = container_of(type, - struct bt_ctf_field_type_floating_point, parent); - floating_point->definition.declaration = container_of( - type->declaration, struct declaration_float, p); - - - floating_point->definition.sign = &floating_point->sign; - floating_point->sign.declaration = &floating_point_type->sign; - floating_point->definition.sign->p.declaration = - &floating_point_type->sign.p; - - floating_point->definition.mantissa = &floating_point->mantissa; - floating_point->mantissa.declaration = &floating_point_type->mantissa; - floating_point->definition.mantissa->p.declaration = - &floating_point_type->mantissa.p; - - floating_point->definition.exp = &floating_point->exp; - floating_point->exp.declaration = &floating_point_type->exp; - floating_point->definition.exp->p.declaration = - &floating_point_type->exp.p; - -end: - return floating_point ? &floating_point->parent : NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_structure_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_structure *structure_type = container_of(type, - struct bt_ctf_field_type_structure, parent); - struct bt_ctf_field_structure *structure = g_new0( - struct bt_ctf_field_structure, 1); - struct bt_ctf_field *field = NULL; - - if (!structure || !structure_type->fields->len) { - goto end; - } - - structure->field_name_to_index = structure_type->field_name_to_index; - structure->fields = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_field_put); - g_ptr_array_set_size(structure->fields, - g_hash_table_size(structure->field_name_to_index)); - field = &structure->parent; -end: - return field; -} - -static -struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_variant *variant = g_new0( - struct bt_ctf_field_variant, 1); - return variant ? &variant->parent : NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_array *array = g_new0(struct bt_ctf_field_array, 1); - struct bt_ctf_field_type_array *array_type; - unsigned int array_length; - - if (!array || !type) { - goto error; - } - - array_type = container_of(type, struct bt_ctf_field_type_array, parent); - array_length = array_type->length; - array->elements = g_ptr_array_sized_new(array_length); - if (!array->elements) { - goto error; - } - - g_ptr_array_set_free_func(array->elements, - (GDestroyNotify)bt_ctf_field_put); - g_ptr_array_set_size(array->elements, array_length); - return &array->parent; -error: - g_free(array); - return NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_sequence_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_sequence *sequence = g_new0( - struct bt_ctf_field_sequence, 1); - return sequence ? &sequence->parent : NULL; -} - -static -struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_string *string = g_new0( - struct bt_ctf_field_string, 1); - return string ? &string->parent : NULL; -} - -static -void bt_ctf_field_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field *field; - struct bt_ctf_field_type *type; - enum ctf_type_id type_id; - - if (!ref) { - return; - } - - field = container_of(ref, struct bt_ctf_field, ref_count); - type = field->type; - type_id = bt_ctf_field_type_get_type_id(type); - if (type_id <= CTF_TYPE_UNKNOWN || - type_id >= NR_CTF_TYPES) { - return; - } - - field_destroy_funcs[type_id](field); - if (type) { - bt_ctf_field_type_put(type); - } -} - -static -void bt_ctf_field_integer_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_integer *integer; - - if (!field) { - return; - } - - integer = container_of(field, struct bt_ctf_field_integer, parent); - g_free(integer); -} - -static -void bt_ctf_field_enumeration_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_enumeration *enumeration; - - if (!field) { - return; - } - - enumeration = container_of(field, struct bt_ctf_field_enumeration, - parent); - bt_ctf_field_put(enumeration->payload); - g_free(enumeration); -} - -static -void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_floating_point *floating_point; - - if (!field) { - return; - } - - floating_point = container_of(field, struct bt_ctf_field_floating_point, - parent); - g_free(floating_point); -} - -static -void bt_ctf_field_structure_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_structure *structure; - - if (!field) { - return; - } - - structure = container_of(field, struct bt_ctf_field_structure, parent); - g_ptr_array_free(structure->fields, TRUE); - g_free(structure); -} - -static -void bt_ctf_field_variant_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_variant *variant; - - if (!field) { - return; - } - - variant = container_of(field, struct bt_ctf_field_variant, parent); - bt_ctf_field_put(variant->tag); - bt_ctf_field_put(variant->payload); - g_free(variant); -} - -static -void bt_ctf_field_array_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_array *array; - - if (!field) { - return; - } - - array = container_of(field, struct bt_ctf_field_array, parent); - g_ptr_array_free(array->elements, TRUE); - g_free(array); -} - -static -void bt_ctf_field_sequence_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_sequence *sequence; - - if (!field) { - return; - } - - sequence = container_of(field, struct bt_ctf_field_sequence, parent); - g_ptr_array_free(sequence->elements, TRUE); - bt_ctf_field_put(sequence->length); - g_free(sequence); -} - -static -void bt_ctf_field_string_destroy(struct bt_ctf_field *field) -{ - struct bt_ctf_field_string *string; - if (!field) { - return; - } - - string = container_of(field, struct bt_ctf_field_string, parent); - g_string_free(string->payload, TRUE); - g_free(string); -} - -static -int bt_ctf_field_generic_validate(struct bt_ctf_field *field) -{ - return (field && field->payload_set) ? 0 : -1; -} - -static -int bt_ctf_field_enumeration_validate(struct bt_ctf_field *field) -{ - int ret; - struct bt_ctf_field_enumeration *enumeration; - - if (!field) { - ret = -1; - goto end; - } - - enumeration = container_of(field, struct bt_ctf_field_enumeration, - parent); - if (!enumeration->payload) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_validate(enumeration->payload); -end: - return ret; -} - -static -int bt_ctf_field_structure_validate(struct bt_ctf_field *field) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_structure *structure; - - if (!field) { - ret = -1; - goto end; - } - - structure = container_of(field, struct bt_ctf_field_structure, parent); - for (i = 0; i < structure->fields->len; i++) { - ret = bt_ctf_field_validate(structure->fields->pdata[i]); - if (ret) { - goto end; - } - } -end: - return ret; -} - -static -int bt_ctf_field_variant_validate(struct bt_ctf_field *field) -{ - int ret = 0; - struct bt_ctf_field_variant *variant; - - if (!field) { - ret = -1; - goto end; - } - - variant = container_of(field, struct bt_ctf_field_variant, parent); - ret = bt_ctf_field_validate(variant->payload); -end: - return ret; -} - -static -int bt_ctf_field_array_validate(struct bt_ctf_field *field) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_array *array; - - if (!field) { - ret = -1; - goto end; - } - - array = container_of(field, struct bt_ctf_field_array, parent); - for (i = 0; i < array->elements->len; i++) { - ret = bt_ctf_field_validate(array->elements->pdata[i]); - if (ret) { - goto end; - } - } -end: - return ret; -} - -static -int bt_ctf_field_sequence_validate(struct bt_ctf_field *field) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_sequence *sequence; - - if (!field) { - ret = -1; - goto end; - } - - sequence = container_of(field, struct bt_ctf_field_sequence, parent); - for (i = 0; i < sequence->elements->len; i++) { - ret = bt_ctf_field_validate(sequence->elements->pdata[i]); - if (ret) { - goto end; - } - } -end: - return ret; -} - -static -int bt_ctf_field_integer_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - int ret = 0; - struct bt_ctf_field_integer *integer = container_of(field, - struct bt_ctf_field_integer, parent); - -retry: - ret = ctf_integer_write(&pos->parent, &integer->definition.p); - if (ret == -EFAULT) { - /* - * The field is too large to fit in the current packet's - * remaining space. Bump the packet size and retry. - */ - ret = increase_packet_size(pos); - if (ret) { - goto end; - } - goto retry; - } -end: - return ret; -} - -static -int bt_ctf_field_enumeration_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - struct bt_ctf_field_enumeration *enumeration = container_of( - field, struct bt_ctf_field_enumeration, parent); - - return bt_ctf_field_serialize(enumeration->payload, pos); -} - -static -int bt_ctf_field_floating_point_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - int ret = 0; - struct bt_ctf_field_floating_point *floating_point = container_of(field, - struct bt_ctf_field_floating_point, parent); - -retry: - ret = ctf_float_write(&pos->parent, &floating_point->definition.p); - if (ret == -EFAULT) { - /* - * The field is too large to fit in the current packet's - * remaining space. Bump the packet size and retry. - */ - ret = increase_packet_size(pos); - if (ret) { - goto end; - } - goto retry; - } -end: - return ret; -} - -static -int bt_ctf_field_structure_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_structure *structure = container_of( - field, struct bt_ctf_field_structure, parent); - - while (!ctf_pos_access_ok(pos, - offset_align(pos->offset, - field->type->declaration->alignment))) { - ret = increase_packet_size(pos); - if (ret) { - goto end; - } - } - - if (!ctf_align_pos(pos, field->type->declaration->alignment)) { - ret = -1; - goto end; - } - - for (i = 0; i < structure->fields->len; i++) { - struct bt_ctf_field *field = g_ptr_array_index( - structure->fields, i); - - ret = bt_ctf_field_serialize(field, pos); - if (ret) { - break; - } - } -end: - return ret; -} - -static -int bt_ctf_field_variant_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - struct bt_ctf_field_variant *variant = container_of( - field, struct bt_ctf_field_variant, parent); - - return bt_ctf_field_serialize(variant->payload, pos); -} - -static -int bt_ctf_field_array_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_array *array = container_of( - field, struct bt_ctf_field_array, parent); - - for (i = 0; i < array->elements->len; i++) { - ret = bt_ctf_field_serialize( - g_ptr_array_index(array->elements, i), pos); - if (ret) { - goto end; - } - } -end: - return ret; -} - -static -int bt_ctf_field_sequence_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_sequence *sequence = container_of( - field, struct bt_ctf_field_sequence, parent); - - for (i = 0; i < sequence->elements->len; i++) { - ret = bt_ctf_field_serialize( - g_ptr_array_index(sequence->elements, i), pos); - if (ret) { - goto end; - } - } -end: - return ret; -} - -static -int bt_ctf_field_string_serialize(struct bt_ctf_field *field, - struct ctf_stream_pos *pos) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_string *string = container_of(field, - struct bt_ctf_field_string, parent); - struct bt_ctf_field_type *character_type = - get_field_type(FIELD_TYPE_ALIAS_UINT8_T); - struct bt_ctf_field *character = bt_ctf_field_create(character_type); - - for (i = 0; i < string->payload->len + 1; i++) { - ret = bt_ctf_field_unsigned_integer_set_value(character, - (uint64_t) string->payload->str[i]); - if (ret) { - goto end; - } - - ret = bt_ctf_field_integer_serialize(character, pos); - if (ret) { - goto end; - } - } -end: - bt_ctf_field_put(character); - bt_ctf_field_type_put(character_type); - return ret; -} - -static -int increase_packet_size(struct ctf_stream_pos *pos) -{ - int ret; - - assert(pos); - ret = munmap_align(pos->base_mma); - if (ret) { - goto end; - } - - pos->packet_size += PACKET_LEN_INCREMENT; - do { - ret = bt_posix_fallocate(pos->fd, pos->mmap_offset, - pos->packet_size / CHAR_BIT); - } while (ret == EINTR); - if (ret) { - errno = EINTR; - ret = -1; - goto end; - } - - pos->base_mma = mmap_align(pos->packet_size / CHAR_BIT, pos->prot, - pos->flags, pos->fd, pos->mmap_offset); - if (pos->base_mma == MAP_FAILED) { - ret = -1; - } -end: - return ret; -} diff --git a/formats/ctf/writer/event-types.c b/formats/ctf/writer/event-types.c deleted file mode 100644 index 08b832e8..00000000 --- a/formats/ctf/writer/event-types.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* - * event-types.c - * - * Babeltrace CTF Writer - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct range_overlap_query { - int64_t range_start, range_end; - int overlaps; - GQuark mapping_name; -}; - -static -void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *); -static -void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *); - -static -void (* const type_destroy_funcs[])(struct bt_ctf_ref *) = { - [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_destroy, - [CTF_TYPE_ENUM] = - bt_ctf_field_type_enumeration_destroy, - [CTF_TYPE_FLOAT] = - bt_ctf_field_type_floating_point_destroy, - [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_destroy, - [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_destroy, - [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_destroy, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_destroy, - [CTF_TYPE_STRING] = bt_ctf_field_type_string_destroy, -}; - -static -void generic_field_type_freeze(struct bt_ctf_field_type *); -static -void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *); -static -void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *); -static -void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *); -static -void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *); -static -void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *); - -static -type_freeze_func const type_freeze_funcs[] = { - [CTF_TYPE_INTEGER] = generic_field_type_freeze, - [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_freeze, - [CTF_TYPE_FLOAT] = generic_field_type_freeze, - [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_freeze, - [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_freeze, - [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_freeze, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_freeze, - [CTF_TYPE_STRING] = generic_field_type_freeze, -}; - -static -int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_floating_point_serialize( - struct bt_ctf_field_type *, struct metadata_context *); -static -int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *, - struct metadata_context *); -static -int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *, - struct metadata_context *); - -static -type_serialize_func const type_serialize_funcs[] = { - [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_serialize, - [CTF_TYPE_ENUM] = - bt_ctf_field_type_enumeration_serialize, - [CTF_TYPE_FLOAT] = - bt_ctf_field_type_floating_point_serialize, - [CTF_TYPE_STRUCT] = - bt_ctf_field_type_structure_serialize, - [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_serialize, - [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_serialize, - [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_serialize, - [CTF_TYPE_STRING] = bt_ctf_field_type_string_serialize, -}; - -static -void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *, - int byte_order); -static -void bt_ctf_field_type_floating_point_set_byte_order( - struct bt_ctf_field_type *, int byte_order); - -static -void (* const set_byte_order_funcs[])(struct bt_ctf_field_type *, - int) = { - [CTF_TYPE_INTEGER] = - bt_ctf_field_type_integer_set_byte_order, - [CTF_TYPE_FLOAT] = - bt_ctf_field_type_floating_point_set_byte_order, - [CTF_TYPE_ENUM ... CTF_TYPE_SEQUENCE] = NULL, -}; - - -static -void destroy_enumeration_mapping(struct enumeration_mapping *mapping) -{ - g_free(mapping); -} - -static -void destroy_structure_field(struct structure_field *field) -{ - if (field->type) { - bt_ctf_field_type_put(field->type); - } - - g_free(field); -} - -static -void check_ranges_overlap(gpointer element, gpointer query) -{ - struct enumeration_mapping *mapping = element; - struct range_overlap_query *overlap_query = query; - - if (mapping->range_start <= overlap_query->range_end - && overlap_query->range_start <= mapping->range_end) { - overlap_query->overlaps = 1; - overlap_query->mapping_name = mapping->string; - } - - overlap_query->overlaps |= - mapping->string == overlap_query->mapping_name; -} - -static -void bt_ctf_field_type_init(struct bt_ctf_field_type *type) -{ - enum ctf_type_id type_id = type->declaration->id; - int ret; - - assert(type && (type_id > CTF_TYPE_UNKNOWN) && - (type_id < NR_CTF_TYPES)); - - bt_ctf_ref_init(&type->ref_count); - type->freeze = type_freeze_funcs[type_id]; - type->serialize = type_serialize_funcs[type_id]; - ret = bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_NATIVE); - assert(!ret); - type->declaration->alignment = 1; -} - -static -int add_structure_field(GPtrArray *fields, - GHashTable *field_name_to_index, - struct bt_ctf_field_type *field_type, - const char *field_name) -{ - int ret = 0; - GQuark name_quark = g_quark_from_string(field_name); - struct structure_field *field; - - /* Make sure structure does not contain a field of the same name */ - if (g_hash_table_lookup_extended(field_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, NULL)) { - ret = -1; - goto end; - } - - field = g_new0(struct structure_field, 1); - if (!field) { - ret = -1; - goto end; - } - - bt_ctf_field_type_get(field_type); - field->name = name_quark; - field->type = field_type; - g_hash_table_insert(field_name_to_index, - (gpointer) (unsigned long) name_quark, - (gpointer) (unsigned long) fields->len); - g_ptr_array_add(fields, field); - bt_ctf_field_type_freeze(field_type); -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) -{ - int ret = 0; - - if (!type) { - ret = -1; - goto end; - } - - if (type->declaration->id == CTF_TYPE_ENUM) { - struct bt_ctf_field_type_enumeration *enumeration = - container_of(type, struct bt_ctf_field_type_enumeration, - parent); - - ret = enumeration->entries->len ? 0 : -1; - } -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) -{ - struct bt_ctf_field_type_integer *integer = - g_new0(struct bt_ctf_field_type_integer, 1); - - if (!integer || size > 64) { - return NULL; - } - - integer->parent.declaration = &integer->declaration.p; - integer->parent.declaration->id = CTF_TYPE_INTEGER; - integer->declaration.len = size; - integer->declaration.base = BT_CTF_INTEGER_BASE_DECIMAL; - integer->declaration.encoding = CTF_STRING_NONE; - bt_ctf_field_type_init(&integer->parent); - return &integer->parent; -} - -int bt_ctf_field_type_integer_set_signed(struct bt_ctf_field_type *type, - int is_signed) -{ - int ret = 0; - struct bt_ctf_field_type_integer *integer; - - if (!type || type->frozen || - type->declaration->id != CTF_TYPE_INTEGER) { - ret = -1; - goto end; - } - - integer = container_of(type, struct bt_ctf_field_type_integer, parent); - if (is_signed && integer->declaration.len <= 1) { - ret = -1; - goto end; - } - - integer->declaration.signedness = !!is_signed; -end: - return ret; -} - -int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *type, - enum bt_ctf_integer_base base) -{ - int ret = 0; - - if (!type || type->frozen || - type->declaration->id != CTF_TYPE_INTEGER) { - ret = -1; - goto end; - } - - switch (base) { - case BT_CTF_INTEGER_BASE_BINARY: - case BT_CTF_INTEGER_BASE_OCTAL: - case BT_CTF_INTEGER_BASE_DECIMAL: - case BT_CTF_INTEGER_BASE_HEXADECIMAL: - { - struct bt_ctf_field_type_integer *integer = container_of(type, - struct bt_ctf_field_type_integer, parent); - integer->declaration.base = base; - break; - } - default: - ret = -1; - } -end: - return ret; -} - -int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *type, - enum ctf_string_encoding encoding) -{ - int ret = 0; - struct bt_ctf_field_type_integer *integer; - - if (!type || type->frozen || - (type->declaration->id != CTF_TYPE_INTEGER) || - (encoding < CTF_STRING_NONE) || - (encoding >= CTF_STRING_UNKNOWN)) { - ret = -1; - goto end; - } - - integer = container_of(type, struct bt_ctf_field_type_integer, parent); - integer->declaration.encoding = encoding; -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( - struct bt_ctf_field_type *integer_container_type) -{ - struct bt_ctf_field_type_enumeration *enumeration = NULL; - - if (!integer_container_type) { - goto error; - } - - enumeration = g_new0(struct bt_ctf_field_type_enumeration, 1); - if (!enumeration) { - goto error; - } - - enumeration->parent.declaration = &enumeration->declaration.p; - enumeration->parent.declaration->id = CTF_TYPE_ENUM; - bt_ctf_field_type_get(integer_container_type); - enumeration->container = integer_container_type; - enumeration->entries = g_ptr_array_new_with_free_func( - (GDestroyNotify)destroy_enumeration_mapping); - bt_ctf_field_type_init(&enumeration->parent); - return &enumeration->parent; -error: - g_free(enumeration); - return NULL; -} - -int bt_ctf_field_type_enumeration_add_mapping( - struct bt_ctf_field_type *type, const char *string, - int64_t range_start, int64_t range_end) -{ - int ret = 0; - GQuark mapping_name; - struct enumeration_mapping *mapping; - struct bt_ctf_field_type_enumeration *enumeration; - struct range_overlap_query query; - char *escaped_string; - - if (!type || (type->declaration->id != CTF_TYPE_ENUM) || - type->frozen || - (range_end < range_start)) { - ret = -1; - goto end; - } - - if (!string || strlen(string) == 0) { - ret = -1; - goto end; - } - - escaped_string = g_strescape(string, NULL); - if (!escaped_string) { - ret = -1; - goto end; - } - - mapping_name = g_quark_from_string(escaped_string); - query = (struct range_overlap_query) { .range_start = range_start, - .range_end = range_end, - .mapping_name = mapping_name, - .overlaps = 0 }; - enumeration = container_of(type, struct bt_ctf_field_type_enumeration, - parent); - - /* Check that the range does not overlap with one already present */ - g_ptr_array_foreach(enumeration->entries, check_ranges_overlap, &query); - if (query.overlaps) { - ret = -1; - goto error_free; - } - - mapping = g_new(struct enumeration_mapping, 1); - if (!mapping) { - ret = -1; - goto error_free; - } - - *mapping = (struct enumeration_mapping) {.range_start = range_start, - .range_end = range_end, .string = mapping_name}; - g_ptr_array_add(enumeration->entries, mapping); -error_free: - free(escaped_string); -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) -{ - struct bt_ctf_field_type_floating_point *floating_point = - g_new0(struct bt_ctf_field_type_floating_point, 1); - - if (!floating_point) { - goto end; - } - - floating_point->declaration.sign = &floating_point->sign; - floating_point->declaration.mantissa = &floating_point->mantissa; - floating_point->declaration.exp = &floating_point->exp; - floating_point->sign.len = 1; - floating_point->parent.declaration = &floating_point->declaration.p; - floating_point->parent.declaration->id = CTF_TYPE_FLOAT; - floating_point->declaration.exp->len = - sizeof(float) * CHAR_BIT - FLT_MANT_DIG; - floating_point->declaration.mantissa->len = FLT_MANT_DIG - 1; - floating_point->sign.p.alignment = 1; - floating_point->mantissa.p.alignment = 1; - floating_point->exp.p.alignment = 1; - - bt_ctf_field_type_init(&floating_point->parent); -end: - return floating_point ? &floating_point->parent : NULL; -} - -int bt_ctf_field_type_floating_point_set_exponent_digits( - struct bt_ctf_field_type *type, - unsigned int exponent_digits) -{ - int ret = 0; - struct bt_ctf_field_type_floating_point *floating_point; - - if (!type || type->frozen || - (type->declaration->id != CTF_TYPE_FLOAT)) { - ret = -1; - goto end; - } - - floating_point = container_of(type, - struct bt_ctf_field_type_floating_point, parent); - if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && - (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && - (exponent_digits != - sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { - ret = -1; - goto end; - } - - floating_point->declaration.exp->len = exponent_digits; -end: - return ret; -} - -int bt_ctf_field_type_floating_point_set_mantissa_digits( - struct bt_ctf_field_type *type, - unsigned int mantissa_digits) -{ - int ret = 0; - struct bt_ctf_field_type_floating_point *floating_point; - - if (!type || type->frozen || - (type->declaration->id != CTF_TYPE_FLOAT)) { - ret = -1; - goto end; - } - - floating_point = container_of(type, - struct bt_ctf_field_type_floating_point, parent); - - if ((mantissa_digits != FLT_MANT_DIG) && - (mantissa_digits != DBL_MANT_DIG) && - (mantissa_digits != LDBL_MANT_DIG)) { - ret = -1; - goto end; - } - - floating_point->declaration.mantissa->len = mantissa_digits - 1; -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) -{ - struct bt_ctf_field_type_structure *structure = - g_new0(struct bt_ctf_field_type_structure, 1); - - if (!structure) { - goto error; - } - - structure->parent.declaration = &structure->declaration.p; - structure->parent.declaration->id = CTF_TYPE_STRUCT; - bt_ctf_field_type_init(&structure->parent); - structure->fields = g_ptr_array_new_with_free_func( - (GDestroyNotify)destroy_structure_field); - structure->field_name_to_index = g_hash_table_new(NULL, NULL); - return &structure->parent; -error: - return NULL; -} - -int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type, - struct bt_ctf_field_type *field_type, - const char *field_name) -{ - int ret = 0; - struct bt_ctf_field_type_structure *structure; - - if (!type || !field_type || type->frozen || - validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_STRUCT) || - bt_ctf_field_type_validate(field_type)) { - ret = -1; - goto end; - } - - structure = container_of(type, - struct bt_ctf_field_type_structure, parent); - if (add_structure_field(structure->fields, - structure->field_name_to_index, field_type, field_name)) { - ret = -1; - goto end; - } - - if (type->declaration->alignment < field_type->declaration->alignment) { - type->declaration->alignment = - field_type->declaration->alignment; - } -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_variant_create( - struct bt_ctf_field_type *enum_tag, const char *tag_name) -{ - struct bt_ctf_field_type_variant *variant = NULL; - - if (!enum_tag || validate_identifier(tag_name) || - (enum_tag->declaration->id != CTF_TYPE_ENUM)) { - goto error; - } - - variant = g_new0(struct bt_ctf_field_type_variant, 1); - if (!variant) { - goto error; - } - - variant->parent.declaration = &variant->declaration.p; - variant->parent.declaration->id = CTF_TYPE_VARIANT; - variant->tag_name = g_string_new(tag_name); - bt_ctf_field_type_init(&variant->parent); - variant->field_name_to_index = g_hash_table_new(NULL, NULL); - variant->fields = g_ptr_array_new_with_free_func( - (GDestroyNotify)destroy_structure_field); - bt_ctf_field_type_get(enum_tag); - variant->tag = container_of(enum_tag, - struct bt_ctf_field_type_enumeration, parent); - return &variant->parent; -error: - return NULL; -} - -int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, - struct bt_ctf_field_type *field_type, - const char *field_name) -{ - size_t i; - int ret = 0; - int name_found = 0; - struct bt_ctf_field_type_variant *variant; - GQuark field_name_quark = g_quark_from_string(field_name); - - if (!type || !field_type || type->frozen || - validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_VARIANT) || - bt_ctf_field_type_validate(field_type)) { - ret = -1; - goto end; - } - - variant = container_of(type, struct bt_ctf_field_type_variant, parent); - /* Make sure this name is present in the enum tag */ - for (i = 0; i < variant->tag->entries->len; i++) { - struct enumeration_mapping *mapping = - g_ptr_array_index(variant->tag->entries, i); - - if (mapping->string == field_name_quark) { - name_found = 1; - break; - } - } - - if (!name_found || add_structure_field(variant->fields, - variant->field_name_to_index, field_type, field_name)) { - ret = -1; - goto end; - } -end: - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_array_create( - struct bt_ctf_field_type *element_type, - unsigned int length) -{ - struct bt_ctf_field_type_array *array = NULL; - - if (!element_type || length == 0 || - bt_ctf_field_type_validate(element_type)) { - goto error; - } - - array = g_new0(struct bt_ctf_field_type_array, 1); - if (!array) { - goto error; - } - - array->parent.declaration = &array->declaration.p; - array->parent.declaration->id = CTF_TYPE_ARRAY; - bt_ctf_field_type_init(&array->parent); - bt_ctf_field_type_get(element_type); - array->element_type = element_type; - array->length = length; - array->parent.declaration->alignment = - element_type->declaration->alignment; - return &array->parent; -error: - return NULL; -} - -struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( - struct bt_ctf_field_type *element_type, - const char *length_field_name) -{ - struct bt_ctf_field_type_sequence *sequence = NULL; - - if (!element_type || validate_identifier(length_field_name) || - bt_ctf_field_type_validate(element_type)) { - goto error; - } - - sequence = g_new0(struct bt_ctf_field_type_sequence, 1); - if (!sequence) { - goto error; - } - - sequence->parent.declaration = &sequence->declaration.p; - sequence->parent.declaration->id = CTF_TYPE_SEQUENCE; - bt_ctf_field_type_init(&sequence->parent); - bt_ctf_field_type_get(element_type); - sequence->element_type = element_type; - sequence->length_field_name = g_string_new(length_field_name); - sequence->parent.declaration->alignment = - element_type->declaration->alignment; - return &sequence->parent; -error: - return NULL; -} - -struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) -{ - struct bt_ctf_field_type_string *string = - g_new0(struct bt_ctf_field_type_string, 1); - - if (!string) { - return NULL; - } - - string->parent.declaration = &string->declaration.p; - string->parent.declaration->id = CTF_TYPE_STRING; - bt_ctf_field_type_init(&string->parent); - string->declaration.encoding = CTF_STRING_UTF8; - string->parent.declaration->alignment = CHAR_BIT; - return &string->parent; -} - -int bt_ctf_field_type_string_set_encoding( - struct bt_ctf_field_type *type, - enum ctf_string_encoding encoding) -{ - int ret = 0; - struct bt_ctf_field_type_string *string; - - if (!type || type->declaration->id != CTF_TYPE_STRING || - (encoding != CTF_STRING_UTF8 && - encoding != CTF_STRING_ASCII)) { - ret = -1; - goto end; - } - - string = container_of(type, struct bt_ctf_field_type_string, parent); - string->declaration.encoding = encoding; -end: - return ret; -} - -int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, - unsigned int alignment) -{ - int ret = 0; - - /* Alignment must be bit-aligned (1) or byte aligned */ - if (!type || type->frozen || (alignment != 1 && (alignment & 0x7))) { - ret = -1; - goto end; - } - - if (type->declaration->id == CTF_TYPE_STRING && - alignment != CHAR_BIT) { - ret = -1; - goto end; - } - - type->declaration->alignment = alignment; - ret = 0; -end: - return ret; -} - -int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - int internal_byte_order; - enum ctf_type_id type_id; - - if (!type || type->frozen) { - ret = -1; - goto end; - } - - type_id = type->declaration->id; - switch (byte_order) { - case BT_CTF_BYTE_ORDER_NATIVE: - internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - break; - case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: - internal_byte_order = LITTLE_ENDIAN; - break; - case BT_CTF_BYTE_ORDER_BIG_ENDIAN: - case BT_CTF_BYTE_ORDER_NETWORK: - internal_byte_order = BIG_ENDIAN; - break; - default: - ret = -1; - goto end; - } - - if (set_byte_order_funcs[type_id]) { - set_byte_order_funcs[type_id](type, internal_byte_order); - } -end: - return ret; -} - -void bt_ctf_field_type_get(struct bt_ctf_field_type *type) -{ - if (!type) { - return; - } - - bt_ctf_ref_get(&type->ref_count); -} - -void bt_ctf_field_type_put(struct bt_ctf_field_type *type) -{ - enum ctf_type_id type_id; - - if (!type) { - return; - } - - type_id = type->declaration->id; - assert(type_id > CTF_TYPE_UNKNOWN && type_id < NR_CTF_TYPES); - bt_ctf_ref_put(&type->ref_count, type_destroy_funcs[type_id]); -} - -BT_HIDDEN -void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type) -{ - if (!type) { - return; - } - - type->freeze(type); -} - -BT_HIDDEN -enum ctf_type_id bt_ctf_field_type_get_type_id( - struct bt_ctf_field_type *type) -{ - if (!type) { - return CTF_TYPE_UNKNOWN; - } - - return type->declaration->id; -} - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_structure_get_type( - struct bt_ctf_field_type_structure *structure, - const char *name) -{ - struct bt_ctf_field_type *type = NULL; - struct structure_field *field; - GQuark name_quark = g_quark_try_string(name); - size_t index; - - if (!name_quark) { - goto end; - } - - if (!g_hash_table_lookup_extended(structure->field_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { - goto end; - } - - field = structure->fields->pdata[index]; - type = field->type; -end: - return type; -} - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( - struct bt_ctf_field_type_array *array) -{ - assert(array); - return array->element_type; -} - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( - struct bt_ctf_field_type_sequence *sequence) -{ - assert(sequence); - return sequence->element_type; -} - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type( - struct bt_ctf_field_type_variant *variant, - int64_t tag_value) -{ - struct bt_ctf_field_type *type = NULL; - GQuark field_name_quark; - gpointer index; - struct structure_field *field_entry; - struct range_overlap_query query = {.range_start = tag_value, - .range_end = tag_value, .mapping_name = 0, .overlaps = 0}; - - g_ptr_array_foreach(variant->tag->entries, check_ranges_overlap, - &query); - if (!query.overlaps) { - goto end; - } - - field_name_quark = query.mapping_name; - if (!g_hash_table_lookup_extended(variant->field_name_to_index, - GUINT_TO_POINTER(field_name_quark), NULL, &index)) { - goto end; - } - - field_entry = g_ptr_array_index(variant->fields, (size_t)index); - type = field_entry->type; -end: - return type; -} - -BT_HIDDEN -int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - int ret; - - if (!type || !context) { - ret = -1; - goto end; - } - - ret = type->serialize(type, context); -end: - return ret; -} - -static -void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_integer *integer; - - if (!ref) { - return; - } - - integer = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_integer, parent); - g_free(integer); -} - -static -void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_enumeration *enumeration; - - if (!ref) { - return; - } - - enumeration = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_enumeration, parent); - g_ptr_array_free(enumeration->entries, TRUE); - bt_ctf_field_type_put(enumeration->container); - g_free(enumeration); -} - -static -void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_floating_point *floating_point; - - if (!ref) { - return; - } - - floating_point = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_floating_point, parent); - g_free(floating_point); -} - -static -void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_structure *structure; - - if (!ref) { - return; - } - - structure = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_structure, parent); - g_ptr_array_free(structure->fields, TRUE); - g_hash_table_destroy(structure->field_name_to_index); - g_free(structure); -} - -static -void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_variant *variant; - - if (!ref) { - return; - } - - variant = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_variant, parent); - g_ptr_array_free(variant->fields, TRUE); - g_hash_table_destroy(variant->field_name_to_index); - g_string_free(variant->tag_name, TRUE); - bt_ctf_field_type_put(&variant->tag->parent); - g_free(variant); -} - -static -void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_array *array; - - if (!ref) { - return; - } - - array = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_array, parent); - bt_ctf_field_type_put(array->element_type); - g_free(array); -} - -static -void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_sequence *sequence; - - if (!ref) { - return; - } - - sequence = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_sequence, parent); - bt_ctf_field_type_put(sequence->element_type); - g_string_free(sequence->length_field_name, TRUE); - g_free(sequence); -} - -static -void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_field_type_string *string; - - if (!ref) { - return; - } - - string = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_string, parent); - g_free(string); -} - -static -void generic_field_type_freeze(struct bt_ctf_field_type *type) -{ - type->frozen = 1; -} - -static -void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_enumeration *enumeration_type = container_of( - type, struct bt_ctf_field_type_enumeration, parent); - - generic_field_type_freeze(type); - bt_ctf_field_type_freeze(enumeration_type->container); -} - -static -void freeze_structure_field(struct structure_field *field) -{ - bt_ctf_field_type_freeze(field->type); -} - -static -void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_structure *structure_type = container_of( - type, struct bt_ctf_field_type_structure, parent); - - generic_field_type_freeze(type); - g_ptr_array_foreach(structure_type->fields, (GFunc)freeze_structure_field, - NULL); -} - -static -void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_variant *variant_type = container_of( - type, struct bt_ctf_field_type_variant, parent); - - generic_field_type_freeze(type); - g_ptr_array_foreach(variant_type->fields, (GFunc)freeze_structure_field, - NULL); -} - -static -void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_array *array_type = container_of( - type, struct bt_ctf_field_type_array, parent); - - generic_field_type_freeze(type); - bt_ctf_field_type_freeze(array_type->element_type); -} - -static -void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_sequence *sequence_type = container_of( - type, struct bt_ctf_field_type_sequence, parent); - - generic_field_type_freeze(type); - bt_ctf_field_type_freeze(sequence_type->element_type); -} - -static -const char *get_encoding_string(enum ctf_string_encoding encoding) -{ - const char *encoding_string; - - switch (encoding) { - case CTF_STRING_NONE: - encoding_string = "none"; - break; - case CTF_STRING_ASCII: - encoding_string = "ASCII"; - break; - case CTF_STRING_UTF8: - encoding_string = "UTF8"; - break; - default: - encoding_string = "unknown"; - break; - } - - return encoding_string; -} - -static -const char *get_integer_base_string(enum bt_ctf_integer_base base) -{ - const char *base_string; - - switch (base) { - case BT_CTF_INTEGER_BASE_DECIMAL: - base_string = "decimal"; - break; - case BT_CTF_INTEGER_BASE_HEXADECIMAL: - base_string = "hexadecimal"; - break; - case BT_CTF_INTEGER_BASE_OCTAL: - base_string = "octal"; - break; - case BT_CTF_INTEGER_BASE_BINARY: - base_string = "binary"; - break; - default: - base_string = "unknown"; - break; - } - - return base_string; -} - -static -int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_integer *integer = container_of(type, - struct bt_ctf_field_type_integer, parent); - - g_string_append_printf(context->string, - "integer { size = %zu; align = %zu; signed = %s; encoding = %s; base = %s; byte_order = %s; }", - integer->declaration.len, type->declaration->alignment, - (integer->declaration.signedness ? "true" : "false"), - get_encoding_string(integer->declaration.encoding), - get_integer_base_string(integer->declaration.base), - get_byte_order_string(integer->declaration.byte_order)); - return 0; -} - -static -int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - size_t entry; - int ret; - struct bt_ctf_field_type_enumeration *enumeration = container_of(type, - struct bt_ctf_field_type_enumeration, parent); - - ret = bt_ctf_field_type_validate(type); - if (ret) { - goto end; - } - - g_string_append(context->string, "enum : "); - ret = bt_ctf_field_type_serialize(enumeration->container, context); - if (ret) { - goto end; - } - - g_string_append(context->string, " { "); - for (entry = 0; entry < enumeration->entries->len; entry++) { - struct enumeration_mapping *mapping = - enumeration->entries->pdata[entry]; - - if (mapping->range_start == mapping->range_end) { - g_string_append_printf(context->string, - "\"%s\" = %" PRId64, - g_quark_to_string(mapping->string), - mapping->range_start); - } else { - g_string_append_printf(context->string, - "\"%s\" = %" PRId64 " ... %" PRId64, - g_quark_to_string(mapping->string), - mapping->range_start, mapping->range_end); - } - - g_string_append(context->string, - ((entry != (enumeration->entries->len - 1)) ? - ", " : " }")); - } - - if (context->field_name->len) { - g_string_append_printf(context->string, " %s", - context->field_name->str); - g_string_assign(context->field_name, ""); - } -end: - return ret; -} - -static -int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_floating_point *floating_point = container_of( - type, struct bt_ctf_field_type_floating_point, parent); - - g_string_append_printf(context->string, - "floating_point { exp_dig = %zu; mant_dig = %zu; byte_order = %s; align = %zu; }", - floating_point->declaration.exp->len, - floating_point->declaration.mantissa->len + 1, - get_byte_order_string(floating_point->declaration.byte_order), - type->declaration->alignment); - return 0; -} - -static -int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - size_t i; - unsigned int indent; - int ret = 0; - struct bt_ctf_field_type_structure *structure = container_of(type, - struct bt_ctf_field_type_structure, parent); - GString *structure_field_name = context->field_name; - - context->field_name = g_string_new(""); - - context->current_indentation_level++; - g_string_append(context->string, "struct {\n"); - - for (i = 0; i < structure->fields->len; i++) { - struct structure_field *field; - - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - field = structure->fields->pdata[i]; - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - ret = bt_ctf_field_type_serialize(field->type, context); - if (ret) { - goto end; - } - - if (context->field_name->len) { - g_string_append_printf(context->string, " %s", - context->field_name->str); - } - g_string_append(context->string, ";\n"); - } - - context->current_indentation_level--; - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_append_printf(context->string, "} align(%zu)", - type->declaration->alignment); -end: - g_string_free(context->field_name, TRUE); - context->field_name = structure_field_name; - return ret; -} - -static -int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - size_t i; - unsigned int indent; - int ret = 0; - struct bt_ctf_field_type_variant *variant = container_of( - type, struct bt_ctf_field_type_variant, parent); - GString *variant_field_name = context->field_name; - - context->field_name = g_string_new(""); - g_string_append_printf(context->string, - "variant <%s> {\n", variant->tag_name->str); - context->current_indentation_level++; - for (i = 0; i < variant->fields->len; i++) { - struct structure_field *field = variant->fields->pdata[i]; - - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - ret = bt_ctf_field_type_serialize(field->type, context); - if (ret) { - goto end; - } - - if (context->field_name->len) { - g_string_append_printf(context->string, " %s;", - context->field_name->str); - } - - g_string_append_c(context->string, '\n'); - } - - context->current_indentation_level--; - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_append(context->string, "}"); -end: - g_string_free(context->field_name, TRUE); - context->field_name = variant_field_name; - return ret; -} - -static -int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - int ret = 0; - struct bt_ctf_field_type_array *array = container_of(type, - struct bt_ctf_field_type_array, parent); - - ret = bt_ctf_field_type_serialize(array->element_type, context); - if (ret) { - goto end; - } - - if (context->field_name->len) { - g_string_append_printf(context->string, " %s[%u]", - context->field_name->str, array->length); - g_string_assign(context->field_name, ""); - } else { - g_string_append_printf(context->string, "[%u]", array->length); - } -end: - return ret; -} - -static -int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - int ret = 0; - struct bt_ctf_field_type_sequence *sequence = container_of( - type, struct bt_ctf_field_type_sequence, parent); - - ret = bt_ctf_field_type_serialize(sequence->element_type, context); - if (ret) { - goto end; - } - - if (context->field_name->len) { - g_string_append_printf(context->string, " %s[%s]", - context->field_name->str, - sequence->length_field_name->str); - g_string_assign(context->field_name, ""); - } else { - g_string_append_printf(context->string, "[%s]", - sequence->length_field_name->str); - } -end: - return ret; -} - -static -int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_string *string = container_of( - type, struct bt_ctf_field_type_string, parent); - - g_string_append_printf(context->string, - "string { encoding = %s; }", - get_encoding_string(string->declaration.encoding)); - return 0; -} - -static -void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *type, - int byte_order) -{ - struct bt_ctf_field_type_integer *integer_type = container_of(type, - struct bt_ctf_field_type_integer, parent); - - integer_type->declaration.byte_order = byte_order; -} - -static -void bt_ctf_field_type_floating_point_set_byte_order( - struct bt_ctf_field_type *type, int byte_order) -{ - struct bt_ctf_field_type_floating_point *floating_point_type = - container_of(type, struct bt_ctf_field_type_floating_point, - parent); - - floating_point_type->declaration.byte_order = byte_order; - floating_point_type->sign.byte_order = byte_order; - floating_point_type->mantissa.byte_order = byte_order; - floating_point_type->exp.byte_order = byte_order; -} diff --git a/formats/ctf/writer/event.c b/formats/ctf/writer/event.c deleted file mode 100644 index c7f1b22a..00000000 --- a/formats/ctf/writer/event.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * event.c - * - * Babeltrace CTF Writer - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static -void bt_ctf_event_class_destroy(struct bt_ctf_ref *ref); -static -void bt_ctf_event_destroy(struct bt_ctf_ref *ref); - -struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name) -{ - struct bt_ctf_event_class *event_class = NULL; - - if (validate_identifier(name)) { - goto end; - } - - event_class = g_new0(struct bt_ctf_event_class, 1); - if (!event_class) { - goto end; - } - - bt_ctf_ref_init(&event_class->ref_count); - event_class->name = g_quark_from_string(name); -end: - return event_class; -} - -int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, - struct bt_ctf_field_type *type, - const char *name) -{ - int ret = 0; - - if (!event_class || !type || validate_identifier(name) || - event_class->frozen) { - ret = -1; - goto end; - } - - if (!event_class->fields) { - event_class->fields = bt_ctf_field_type_structure_create(); - if (!event_class->fields) { - ret = -1; - goto end; - } - } - - ret = bt_ctf_field_type_structure_add_field(event_class->fields, - type, name); -end: - return ret; -} - -void bt_ctf_event_class_get(struct bt_ctf_event_class *event_class) -{ - if (!event_class) { - return; - } - - bt_ctf_ref_get(&event_class->ref_count); -} - -void bt_ctf_event_class_put(struct bt_ctf_event_class *event_class) -{ - if (!event_class) { - return; - } - - bt_ctf_ref_put(&event_class->ref_count, bt_ctf_event_class_destroy); -} - -struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class) -{ - struct bt_ctf_event *event = NULL; - - if (!event_class) { - goto end; - } - - event = g_new0(struct bt_ctf_event, 1); - if (!event) { - goto end; - } - - bt_ctf_ref_init(&event->ref_count); - bt_ctf_event_class_get(event_class); - bt_ctf_event_class_freeze(event_class); - event->event_class = event_class; - event->context_payload = bt_ctf_field_create(event_class->context); - event->fields_payload = bt_ctf_field_create(event_class->fields); -end: - return event; -} - -int bt_ctf_event_set_payload(struct bt_ctf_event *event, - const char *name, - struct bt_ctf_field *value) -{ - int ret = 0; - - if (!event || !value || validate_identifier(name)) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_structure_set_field(event->fields_payload, - name, value); -end: - return ret; -} - - -struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, - const char *name) -{ - struct bt_ctf_field *field = NULL; - - if (!event || !name) { - goto end; - } - - field = bt_ctf_field_structure_get_field(event->fields_payload, name); -end: - return field; -} - -void bt_ctf_event_get(struct bt_ctf_event *event) -{ - if (!event) { - return; - } - - bt_ctf_ref_get(&event->ref_count); -} - -void bt_ctf_event_put(struct bt_ctf_event *event) -{ - if (!event) { - return; - } - - bt_ctf_ref_put(&event->ref_count, bt_ctf_event_destroy); -} - -static -void bt_ctf_event_class_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_event_class *event_class; - - if (!ref) { - return; - } - - event_class = container_of(ref, struct bt_ctf_event_class, ref_count); - bt_ctf_field_type_put(event_class->context); - bt_ctf_field_type_put(event_class->fields); - g_free(event_class); -} - -static -void bt_ctf_event_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_event *event; - - if (!ref) { - return; - } - - event = container_of(ref, struct bt_ctf_event, - ref_count); - bt_ctf_event_class_put(event->event_class); - bt_ctf_field_put(event->context_payload); - bt_ctf_field_put(event->fields_payload); - g_free(event); -} - -BT_HIDDEN -void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class) -{ - assert(event_class); - event_class->frozen = 1; - bt_ctf_field_type_freeze(event_class->context); - bt_ctf_field_type_freeze(event_class->fields); -} - -BT_HIDDEN -int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, - uint32_t id) -{ - int ret = 0; - - if (event_class->id_set && id != event_class->id) { - ret = -1; - goto end; - } - - event_class->id = id; - event_class->id_set = 1; -end: - return ret; -} - -BT_HIDDEN -uint32_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class) -{ - assert(event_class); - return event_class->id; -} - -BT_HIDDEN -int bt_ctf_event_class_set_stream_id(struct bt_ctf_event_class *event_class, - uint32_t id) -{ - int ret = 0; - - assert(event_class); - if (event_class->stream_id_set && id != event_class->stream_id) { - ret = -1; - goto end; - } - - event_class->stream_id = id; - event_class->stream_id_set = 1; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, - struct metadata_context *context) -{ - int ret = 0; - - assert(event_class); - assert(context); - context->current_indentation_level = 1; - g_string_assign(context->field_name, ""); - g_string_append_printf(context->string, "event {\n\tname = \"%s\";\n\tid = %u;\n\tstream_id = %" PRIu32 ";\n", - g_quark_to_string(event_class->name), - event_class->id, - event_class->stream_id); - - if (event_class->context) { - g_string_append(context->string, "\tcontext := "); - ret = bt_ctf_field_type_serialize(event_class->context, - context); - if (ret) { - goto end; - } - g_string_append(context->string, ";\n"); - } - - if (event_class->fields) { - g_string_append(context->string, "\tfields := "); - ret = bt_ctf_field_type_serialize(event_class->fields, context); - if (ret) { - goto end; - } - g_string_append(context->string, ";\n"); - } - - g_string_append(context->string, "};\n\n"); -end: - context->current_indentation_level = 0; - return ret; -} - -BT_HIDDEN -int bt_ctf_event_validate(struct bt_ctf_event *event) -{ - /* Make sure each field's payload has been set */ - int ret; - - assert(event); - ret = bt_ctf_field_validate(event->fields_payload); - if (ret) { - goto end; - } - - if (event->event_class->context) { - ret = bt_ctf_field_validate(event->context_payload); - } -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_event_serialize(struct bt_ctf_event *event, - struct ctf_stream_pos *pos) -{ - int ret = 0; - - assert(event); - assert(pos); - if (event->context_payload) { - ret = bt_ctf_field_serialize(event->context_payload, pos); - if (ret) { - goto end; - } - } - - if (event->fields_payload) { - ret = bt_ctf_field_serialize(event->fields_payload, pos); - if (ret) { - goto end; - } - } -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_event_set_timestamp(struct bt_ctf_event *event, - uint64_t timestamp) -{ - int ret = 0; - - assert(event); - if (event->timestamp) { - ret = -1; - goto end; - } - - event->timestamp = timestamp; -end: - return ret; -} - -BT_HIDDEN -uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event) -{ - assert(event); - return event->timestamp; -} diff --git a/formats/ctf/writer/functor.c b/formats/ctf/writer/functor.c index 9c932cf6..3d99b639 100644 --- a/formats/ctf/writer/functor.c +++ b/formats/ctf/writer/functor.c @@ -3,7 +3,7 @@ * * Babeltrace CTF Writer * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * diff --git a/formats/ctf/writer/stream.c b/formats/ctf/writer/stream.c deleted file mode 100644 index 4efb3692..00000000 --- a/formats/ctf/writer/stream.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - * stream.c - * - * Babeltrace CTF Writer - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -void bt_ctf_stream_destroy(struct bt_ctf_ref *ref); -static -void bt_ctf_stream_class_destroy(struct bt_ctf_ref *ref); -static -int init_event_header(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order); -static -int init_packet_context(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order); -static -int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); - -struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) -{ - struct bt_ctf_stream_class *stream_class = NULL; - - if (!name || !strlen(name)) { - goto error; - } - - stream_class = g_new0(struct bt_ctf_stream_class, 1); - if (!stream_class) { - goto error; - } - - stream_class->name = g_string_new(name); - stream_class->event_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_event_class_put); - if (!stream_class->event_classes) { - goto error_destroy; - } - - bt_ctf_ref_init(&stream_class->ref_count); - return stream_class; - -error_destroy: - bt_ctf_stream_class_destroy(&stream_class->ref_count); - stream_class = NULL; -error: - return stream_class; -} - -int bt_ctf_stream_class_set_clock(struct bt_ctf_stream_class *stream_class, - struct bt_ctf_clock *clock) -{ - int ret = 0; - - if (!stream_class || !clock || stream_class->frozen) { - ret = -1; - goto end; - } - - if (stream_class->clock) { - bt_ctf_clock_put(stream_class->clock); - } - - stream_class->clock = clock; - bt_ctf_clock_get(clock); -end: - return ret; -} - -int bt_ctf_stream_class_add_event_class( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_event_class *event_class) -{ - int ret = 0; - - if (!stream_class || !event_class) { - ret = -1; - goto end; - } - - /* Check for duplicate event classes */ - struct search_query query = { .value = event_class, .found = 0 }; - g_ptr_array_foreach(stream_class->event_classes, value_exists, &query); - if (query.found) { - ret = -1; - goto end; - } - - if (bt_ctf_event_class_set_id(event_class, - stream_class->next_event_id++)) { - /* The event is already associated to a stream class */ - ret = -1; - goto end; - } - - bt_ctf_event_class_get(event_class); - g_ptr_array_add(stream_class->event_classes, event_class); -end: - return ret; -} - -void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class) -{ - if (!stream_class) { - return; - } - - bt_ctf_ref_get(&stream_class->ref_count); -} - -void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class) -{ - if (!stream_class) { - return; - } - - bt_ctf_ref_put(&stream_class->ref_count, bt_ctf_stream_class_destroy); -} - -BT_HIDDEN -void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class) -{ - if (!stream_class) { - return; - } - - stream_class->frozen = 1; - bt_ctf_clock_freeze(stream_class->clock); - g_ptr_array_foreach(stream_class->event_classes, - (GFunc)bt_ctf_event_class_freeze, NULL); -} - -BT_HIDDEN -int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, - uint32_t id) -{ - int ret = 0; - - if (!stream_class || - (stream_class->id_set && (id != stream_class->id))) { - ret = -1; - goto end; - } - - stream_class->id = id; - stream_class->id_set = 1; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_class_set_byte_order(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - - ret = init_packet_context(stream_class, byte_order); - if (ret) { - goto end; - } - - ret = init_event_header(stream_class, byte_order); - if (ret) { - goto end; - } -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, - struct metadata_context *context) -{ - int ret = 0; - size_t i; - - g_string_assign(context->field_name, ""); - context->current_indentation_level = 1; - if (!stream_class->id_set) { - ret = -1; - goto end; - } - - g_string_append_printf(context->string, - "stream {\n\tid = %" PRIu32 ";\n\tevent.header := ", - stream_class->id); - ret = bt_ctf_field_type_serialize(stream_class->event_header_type, - context); - if (ret) { - goto end; - } - - g_string_append(context->string, ";\n\n\tpacket.context := "); - ret = bt_ctf_field_type_serialize(stream_class->packet_context_type, - context); - if (ret) { - goto end; - } - - if (stream_class->event_context_type) { - g_string_append(context->string, ";\n\n\tevent.context := "); - ret = bt_ctf_field_type_serialize( - stream_class->event_context_type, context); - if (ret) { - goto end; - } - } - - g_string_append(context->string, ";\n};\n\n"); - - /* Assign this stream's ID to every event and serialize them */ - g_ptr_array_foreach(stream_class->event_classes, - (GFunc) bt_ctf_event_class_set_stream_id, - GUINT_TO_POINTER(stream_class->id)); - for (i = 0; i < stream_class->event_classes->len; i++) { - struct bt_ctf_event_class *event_class = - stream_class->event_classes->pdata[i]; - - ret = bt_ctf_event_class_set_stream_id(event_class, - stream_class->id); - if (ret) { - goto end; - } - - ret = bt_ctf_event_class_serialize(event_class, context); - if (ret) { - goto end; - } - } -end: - context->current_indentation_level = 0; - return ret; -} - -BT_HIDDEN -struct bt_ctf_stream *bt_ctf_stream_create( - struct bt_ctf_stream_class *stream_class) -{ - struct bt_ctf_stream *stream = NULL; - - if (!stream_class) { - goto end; - } - - stream = g_new0(struct bt_ctf_stream, 1); - if (!stream) { - goto end; - } - - bt_ctf_ref_init(&stream->ref_count); - stream->pos.fd = -1; - stream->id = stream_class->next_stream_id++; - stream->stream_class = stream_class; - bt_ctf_stream_class_get(stream_class); - bt_ctf_stream_class_freeze(stream_class); - stream->events = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_event_put); -end: - return stream; -} - -BT_HIDDEN -int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream, - flush_func callback, void *data) -{ - int ret = stream ? 0 : -1; - - if (!stream) { - goto end; - } - - stream->flush.func = callback; - stream->flush.data = data; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd) -{ - int ret = 0; - - if (stream->pos.fd != -1) { - ret = -1; - goto end; - } - - ctf_init_pos(&stream->pos, NULL, fd, O_RDWR); - stream->pos.fd = fd; -end: - return ret; -} - -void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, - uint64_t event_count) -{ - if (!stream) { - return; - } - - stream->events_discarded += event_count; -} - -int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, - struct bt_ctf_event *event) -{ - int ret = 0; - uint64_t timestamp; - - if (!stream || !event) { - ret = -1; - goto end; - } - - ret = bt_ctf_event_validate(event); - if (ret) { - goto end; - } - - timestamp = bt_ctf_clock_get_time(stream->stream_class->clock); - ret = bt_ctf_event_set_timestamp(event, timestamp); - if (ret) { - goto end; - } - - bt_ctf_event_get(event); - g_ptr_array_add(stream->events, event); -end: - return ret; -} - -int bt_ctf_stream_flush(struct bt_ctf_stream *stream) -{ - int ret = 0; - size_t i; - uint64_t timestamp_begin, timestamp_end; - struct bt_ctf_stream_class *stream_class; - struct bt_ctf_field *integer = NULL; - struct ctf_stream_pos packet_context_pos; - - if (!stream) { - ret = -1; - goto end; - } - - if (!stream->events->len) { - goto end; - } - - if (stream->flush.func) { - stream->flush.func(stream, stream->flush.data); - } - - stream_class = stream->stream_class; - timestamp_begin = ((struct bt_ctf_event *) g_ptr_array_index( - stream->events, 0))->timestamp; - timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index( - stream->events, stream->events->len - 1))->timestamp; - ret = set_structure_field_integer(stream_class->packet_context, - "timestamp_begin", timestamp_begin); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->packet_context, - "timestamp_end", timestamp_end); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->packet_context, - "events_discarded", stream->events_discarded); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->packet_context, - "content_size", UINT64_MAX); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->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_class->packet_context, - &stream->pos); - if (ret) { - goto end; - } - - for (i = 0; i < stream->events->len; i++) { - struct bt_ctf_event *event = g_ptr_array_index( - stream->events, i); - uint32_t event_id = bt_ctf_event_class_get_id( - event->event_class); - uint64_t timestamp = bt_ctf_event_get_timestamp(event); - - ret = set_structure_field_integer(stream_class->event_header, - "id", event_id); - if (ret) { - goto end; - } - ret = set_structure_field_integer(stream_class->event_header, - "timestamp", timestamp); - if (ret) { - goto end; - } - - /* Write event header */ - ret = bt_ctf_field_serialize(stream_class->event_header, - &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_class->packet_context, - "content_size", stream->pos.offset); - if (ret) { - goto end; - } - - ret = set_structure_field_integer(stream_class->packet_context, - "packet_size", stream->pos.packet_size); - if (ret) { - goto end; - } - - ret = bt_ctf_field_serialize(stream_class->packet_context, - &packet_context_pos); - if (ret) { - goto end; - } - - g_ptr_array_set_size(stream->events, 0); - stream->flushed_packet_count++; -end: - bt_ctf_field_put(integer); - return ret; -} - -void bt_ctf_stream_get(struct bt_ctf_stream *stream) -{ - if (!stream) { - return; - } - - bt_ctf_ref_get(&stream->ref_count); -} - -void bt_ctf_stream_put(struct bt_ctf_stream *stream) -{ - if (!stream) { - return; - } - - bt_ctf_ref_put(&stream->ref_count, bt_ctf_stream_destroy); -} - -static -void bt_ctf_stream_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_stream *stream; - - if (!ref) { - return; - } - - stream = container_of(ref, struct bt_ctf_stream, ref_count); - ctf_fini_pos(&stream->pos); - if (close(stream->pos.fd)) { - perror("close"); - } - bt_ctf_stream_class_put(stream->stream_class); - g_ptr_array_free(stream->events, TRUE); - g_free(stream); -} - -static -void bt_ctf_stream_class_destroy(struct bt_ctf_ref *ref) -{ - struct bt_ctf_stream_class *stream_class; - - if (!ref) { - return; - } - - stream_class = container_of(ref, struct bt_ctf_stream_class, ref_count); - bt_ctf_clock_put(stream_class->clock); - - if (stream_class->event_classes) { - g_ptr_array_free(stream_class->event_classes, TRUE); - } - - if (stream_class->name) { - g_string_free(stream_class->name, TRUE); - } - - bt_ctf_field_type_put(stream_class->event_header_type); - bt_ctf_field_put(stream_class->event_header); - bt_ctf_field_type_put(stream_class->packet_context_type); - bt_ctf_field_put(stream_class->packet_context); - bt_ctf_field_type_put(stream_class->event_context_type); - bt_ctf_field_put(stream_class->event_context); - g_free(stream_class); -} - -static -int init_event_header(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - struct bt_ctf_field_type *event_header_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *_uint32_t = - get_field_type(FIELD_TYPE_ALIAS_UINT32_T); - struct bt_ctf_field_type *_uint64_t = - get_field_type(FIELD_TYPE_ALIAS_UINT64_T); - - if (!event_header_type) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_set_byte_order(_uint32_t, byte_order); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_set_byte_order(_uint64_t, byte_order); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(event_header_type, - _uint32_t, "id"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(event_header_type, - _uint64_t, "timestamp"); - if (ret) { - goto end; - } - - stream_class->event_header_type = event_header_type; - stream_class->event_header = bt_ctf_field_create( - stream_class->event_header_type); - if (!stream_class->event_header) { - ret = -1; - } -end: - if (ret) { - bt_ctf_field_type_put(event_header_type); - } - - bt_ctf_field_type_put(_uint32_t); - bt_ctf_field_type_put(_uint64_t); - return ret; -} - -static -int init_packet_context(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - struct bt_ctf_field_type *packet_context_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *_uint64_t = - get_field_type(FIELD_TYPE_ALIAS_UINT64_T); - - if (!packet_context_type) { - ret = -1; - goto end; - } - - /* - * We create a stream packet context as proposed in the CTF - * specification. - */ - ret = bt_ctf_field_type_set_byte_order(_uint64_t, byte_order); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "timestamp_begin"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "timestamp_end"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "content_size"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "packet_size"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "events_discarded"); - if (ret) { - goto end; - } - - stream_class->packet_context_type = packet_context_type; - stream_class->packet_context = bt_ctf_field_create(packet_context_type); - if (!stream_class->packet_context) { - ret = -1; - } -end: - if (ret) { - bt_ctf_field_type_put(packet_context_type); - goto end; - } - - bt_ctf_field_type_put(_uint64_t); - return ret; -} - -static -int set_structure_field_integer(struct bt_ctf_field *structure, char *name, - uint64_t value) -{ - int ret = 0; - - struct bt_ctf_field *integer = - bt_ctf_field_structure_get_field(structure, name); - if (!integer) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_unsigned_integer_set_value(integer, value); -end: - bt_ctf_field_put(integer); - return ret; -} diff --git a/formats/ctf/writer/writer.c b/formats/ctf/writer/writer.c index 3ef4dae9..012b3ef0 100644 --- a/formats/ctf/writer/writer.c +++ b/formats/ctf/writer/writer.c @@ -3,7 +3,7 @@ * * Babeltrace CTF Writer * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -26,17 +26,16 @@ * SOFTWARE. */ -#include -#include -#include +#include #include -#include -#include +#include +#include #include -#include -#include +#include +#include +#include +#include #include -#include #include #include #include @@ -45,50 +44,8 @@ #include #include -#define DEFAULT_IDENTIFIER_SIZE 128 -#define DEFAULT_METADATA_STRING_SIZE 4096 - -static -void environment_variable_destroy(struct environment_variable *var); -static -void bt_ctf_writer_destroy(struct bt_ctf_ref *ref); -static -int init_trace_packet_header(struct bt_ctf_writer *writer); -static -int create_stream_file(struct bt_ctf_writer *writer, - struct bt_ctf_stream *stream); -static -void stream_flush_cb(struct bt_ctf_stream *stream, - struct bt_ctf_writer *writer); - 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_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, - [FIELD_TYPE_ALIAS_UINT27_T] = 1, - [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, -}; - -static -const unsigned int field_type_aliases_sizes[] = { - [FIELD_TYPE_ALIAS_UINT5_T] = 5, - [FIELD_TYPE_ALIAS_UINT8_T] = 8, - [FIELD_TYPE_ALIAS_UINT16_T] = 16, - [FIELD_TYPE_ALIAS_UINT27_T] = 27, - [FIELD_TYPE_ALIAS_UINT32_T] = 32, - [FIELD_TYPE_ALIAS_UINT64_T] = 64, -}; - -static GHashTable *reserved_keywords_set; -static int init_done; -static int global_data_refcount; +void bt_ctf_writer_destroy(struct bt_object *obj); struct bt_ctf_writer *bt_ctf_writer_create(const char *path) { @@ -103,13 +60,20 @@ struct bt_ctf_writer *bt_ctf_writer_create(const char *path) goto error; } - bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE); - bt_ctf_ref_init(&writer->ref_count); + bt_object_init(writer, bt_ctf_writer_destroy); writer->path = g_string_new(path); if (!writer->path) { goto error_destroy; } + writer->trace = bt_ctf_trace_create(); + if (!writer->trace) { + goto error_destroy; + } + + writer->trace->is_created_by_writer = 1; + bt_object_set_parent(writer->trace, writer); + bt_put(writer->trace); /* Create trace directory if necessary and open a metadata file */ if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) { perror("g_mkdir_with_parents"); @@ -125,43 +89,21 @@ struct bt_ctf_writer *bt_ctf_writer_create(const char *path) writer->metadata_fd = openat(writer->trace_dir_fd, "metadata", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - writer->environment = g_ptr_array_new_with_free_func( - (GDestroyNotify)environment_variable_destroy); - writer->clocks = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_clock_put); - writer->streams = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_stream_put); - writer->stream_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify)bt_ctf_stream_class_put); - if (!writer->environment || !writer->clocks || - !writer->stream_classes || !writer->streams) { - goto error_destroy; - } - - /* Generate a trace UUID */ - uuid_generate(writer->uuid); - if (init_trace_packet_header(writer)) { - goto error_destroy; - } return writer; + error_destroy: unlinkat(writer->trace_dir_fd, "metadata", 0); - bt_ctf_writer_destroy(&writer->ref_count); - writer = NULL; + BT_PUT(writer); error: return writer; } -void bt_ctf_writer_destroy(struct bt_ctf_ref *ref) +void bt_ctf_writer_destroy(struct bt_object *obj) { struct bt_ctf_writer *writer; - if (!ref) { - return; - } - - writer = container_of(ref, struct bt_ctf_writer, ref_count); + writer = container_of(obj, struct bt_ctf_writer, base); bt_ctf_writer_flush_metadata(writer); if (writer->path) { g_string_free(writer->path, TRUE); @@ -170,292 +112,145 @@ void bt_ctf_writer_destroy(struct bt_ctf_ref *ref) if (writer->trace_dir_fd > 0) { if (close(writer->trace_dir_fd)) { perror("close"); - abort(); } } if (writer->metadata_fd > 0) { if (close(writer->metadata_fd)) { perror("close"); - abort(); } } - if (writer->environment) { - g_ptr_array_free(writer->environment, TRUE); - } - - if (writer->clocks) { - g_ptr_array_free(writer->clocks, TRUE); - } + bt_object_release(writer->trace); + g_free(writer); +} - if (writer->streams) { - g_ptr_array_free(writer->streams, TRUE); - } +struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer) +{ + struct bt_ctf_trace *trace = NULL; - if (writer->stream_classes) { - g_ptr_array_free(writer->stream_classes, TRUE); + if (!writer) { + goto end; } - bt_ctf_field_type_put(writer->trace_packet_header_type); - bt_ctf_field_put(writer->trace_packet_header); - g_free(writer); + trace = writer->trace; + bt_get(trace); +end: + return trace; } struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, struct bt_ctf_stream_class *stream_class) { - int ret; - int stream_class_found = 0; - size_t i; - int stream_fd; struct bt_ctf_stream *stream = NULL; + int stream_class_count; + bool stream_class_found = false; + int i; if (!writer || !stream_class) { goto error; } - stream = bt_ctf_stream_create(stream_class); - if (!stream) { + /* Make sure the stream class is part of the writer's trace */ + stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace); + if (stream_class_count < 0) { goto error; } - stream_fd = create_stream_file(writer, stream); - if (stream_fd < 0 || bt_ctf_stream_set_fd(stream, stream_fd)) { - goto error; - } + for (i = 0; i < stream_class_count; i++) { + struct bt_ctf_stream_class *existing_stream_class = + bt_ctf_trace_get_stream_class(writer->trace, i); - bt_ctf_stream_set_flush_callback(stream, (flush_func)stream_flush_cb, - writer); - ret = bt_ctf_stream_class_set_byte_order(stream->stream_class, - writer->byte_order == LITTLE_ENDIAN ? - BT_CTF_BYTE_ORDER_LITTLE_ENDIAN : BT_CTF_BYTE_ORDER_BIG_ENDIAN); - if (ret) { - goto error; - } + if (existing_stream_class == stream_class) { + stream_class_found = true; + } + + BT_PUT(existing_stream_class); - for (i = 0; i < writer->stream_classes->len; i++) { - if (writer->stream_classes->pdata[i] == stream->stream_class) { - stream_class_found = 1; + if (stream_class_found) { + break; } } if (!stream_class_found) { - if (bt_ctf_stream_class_set_id(stream->stream_class, - writer->next_stream_id++)) { + int ret = bt_ctf_trace_add_stream_class(writer->trace, + stream_class); + + if (ret) { goto error; } + } - bt_ctf_stream_class_get(stream->stream_class); - g_ptr_array_add(writer->stream_classes, stream->stream_class); + stream = bt_ctf_stream_create(stream_class, NULL); + if (!stream) { + goto error; } - bt_ctf_stream_get(stream); - g_ptr_array_add(writer->streams, stream); - writer->frozen = 1; return stream; + error: - bt_ctf_stream_put(stream); - return NULL; + BT_PUT(stream); + return stream; } int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, const char *name, const char *value) { - struct environment_variable *var = NULL; - char *escaped_value = NULL; - int ret = 0; - - if (!writer || !name || !value || validate_identifier(name)) { - ret = -1; - goto error; - } - - if (strchr(name, ' ')) { - ret = -1; - goto error; - } - - var = g_new0(struct environment_variable, 1); - if (!var) { - ret = -1; - goto error; - } - - escaped_value = g_strescape(value, NULL); - if (!escaped_value) { - ret = -1; - goto error; - } - - var->name = g_string_new(name); - var->value = g_string_new(escaped_value); - g_free(escaped_value); - if (!var->name || !var->value) { - ret = -1; - goto error; - } - - g_ptr_array_add(writer->environment, var); - return ret; + int ret = -1; -error: - if (var && var->name) { - g_string_free(var->name, TRUE); - } - - if (var && var->value) { - g_string_free(var->value, TRUE); + if (!writer || !name || !value) { + goto end; } - g_free(var); + ret = bt_ctf_trace_set_environment_field_string(writer->trace, + name, value); +end: return ret; } -int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, - struct bt_ctf_clock *clock) +int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer, + const char *name, + int64_t value) { - int ret = 0; - struct search_query query = { .value = clock, .found = 0 }; + int ret = -1; - if (!writer || !clock) { - ret = -1; + if (!writer || !name) { goto end; } - /* Check for duplicate clocks */ - g_ptr_array_foreach(writer->clocks, value_exists, &query); - if (query.found) { - ret = -1; - goto end; - } - - bt_ctf_clock_get(clock); - g_ptr_array_add(writer->clocks, clock); + ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name, + value); end: return ret; } -BT_HIDDEN -const char *get_byte_order_string(int byte_order) -{ - const char *string; - - switch (byte_order) { - case LITTLE_ENDIAN: - string = "le"; - break; - case BIG_ENDIAN: - string = "be"; - break; - default: - string = "unknown"; - break; - } - - return string; -} - -static -int append_trace_metadata(struct bt_ctf_writer *writer, - struct metadata_context *context) +int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, + struct bt_ctf_clock *clock) { - unsigned char *uuid = writer->uuid; - int ret; + int ret = -1; - g_string_append(context->string, "trace {\n"); - - g_string_append(context->string, "\tmajor = 1;\n"); - g_string_append(context->string, "\tminor = 8;\n"); - - g_string_append_printf(context->string, - "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - g_string_append_printf(context->string, "\tbyte_order = %s;\n", - get_byte_order_string(writer->byte_order)); - - g_string_append(context->string, "\tpacket.header := "); - context->current_indentation_level++; - g_string_assign(context->field_name, ""); - ret = bt_ctf_field_type_serialize(writer->trace_packet_header_type, - context); - if (ret) { + if (!writer || !clock) { goto end; } - context->current_indentation_level--; - g_string_append(context->string, ";\n};\n\n"); + ret = bt_ctf_trace_add_clock(writer->trace, clock); end: return ret; } -static -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); -} - -static -void append_env_metadata(struct bt_ctf_writer *writer, - struct metadata_context *context) -{ - if (writer->environment->len == 0) { - return; - } - - g_string_append(context->string, "env {\n"); - g_ptr_array_foreach(writer->environment, - (GFunc)append_env_field_metadata, context); - g_string_append(context->string, "};\n\n"); -} - char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer) { - char *metadata = NULL; - struct metadata_context *context = NULL; - int err = 0; - size_t i; + char *metadata_string = NULL; if (!writer) { goto end; } - context = g_new0(struct metadata_context, 1); - if (!context) { - goto end; - } - - context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE); - context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE); - g_string_append(context->string, "/* CTF 1.8 */\n\n"); - if (append_trace_metadata(writer, context)) { - goto error; - } - append_env_metadata(writer, context); - g_ptr_array_foreach(writer->clocks, - (GFunc)bt_ctf_clock_serialize, context); - - for (i = 0; i < writer->stream_classes->len; i++) { - err = bt_ctf_stream_class_serialize( - writer->stream_classes->pdata[i], context); - if (err) { - goto error; - } - } - - metadata = context->string->str; -error: - g_string_free(context->string, err ? TRUE : FALSE); - g_string_free(context->field_name, TRUE); - g_free(context); + metadata_string = bt_ctf_trace_get_metadata_string( + writer->trace); end: - return metadata; + return metadata_string; } void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) @@ -467,7 +262,8 @@ void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) goto end; } - metadata_string = bt_ctf_writer_get_metadata_string(writer); + metadata_string = bt_ctf_trace_get_metadata_string( + writer->trace); if (!metadata_string) { goto end; } @@ -496,269 +292,30 @@ int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, enum bt_ctf_byte_order byte_order) { int ret = 0; - int internal_byte_order; if (!writer || writer->frozen) { ret = -1; goto end; } - switch (byte_order) { - case BT_CTF_BYTE_ORDER_NATIVE: - internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? - LITTLE_ENDIAN : BIG_ENDIAN; - break; - case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: - internal_byte_order = LITTLE_ENDIAN; - break; - case BT_CTF_BYTE_ORDER_BIG_ENDIAN: - case BT_CTF_BYTE_ORDER_NETWORK: - internal_byte_order = BIG_ENDIAN; - break; - default: - ret = -1; - goto end; - } - - writer->byte_order = internal_byte_order; - if (writer->trace_packet_header_type || - writer->trace_packet_header) { - init_trace_packet_header(writer); - } + ret = bt_ctf_trace_set_byte_order(writer->trace, + byte_order); end: return ret; } void bt_ctf_writer_get(struct bt_ctf_writer *writer) { - if (!writer) { - return; - } - - bt_ctf_ref_get(&writer->ref_count); + bt_get(writer); } void bt_ctf_writer_put(struct bt_ctf_writer *writer) { - if (!writer) { - return; - } - - bt_ctf_ref_put(&writer->ref_count, bt_ctf_writer_destroy); + bt_put(writer); } 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) -{ - unsigned int alignment, size; - struct bt_ctf_field_type *field_type; - - if (alias >= NR_FIELD_TYPE_ALIAS) { - return NULL; - } - - alignment = field_type_aliases_alignments[alias]; - size = field_type_aliases_sizes[alias]; - field_type = bt_ctf_field_type_integer_create(size); - bt_ctf_field_type_set_alignment(field_type, alignment); - return field_type; -} - -static -int init_trace_packet_header(struct bt_ctf_writer *writer) -{ - size_t i; - int ret = 0; - struct bt_ctf_field *trace_packet_header = NULL, - *magic = NULL, *uuid_array = NULL; - struct bt_ctf_field_type *_uint32_t = - get_field_type(FIELD_TYPE_ALIAS_UINT32_T); - struct bt_ctf_field_type *_uint8_t = - get_field_type(FIELD_TYPE_ALIAS_UINT8_T); - struct bt_ctf_field_type *trace_packet_header_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *uuid_array_type = - bt_ctf_field_type_array_create(_uint8_t, 16); - - if (!trace_packet_header_type || !uuid_array_type) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_set_byte_order(_uint32_t, - (writer->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; - } - - ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, - uuid_array_type, "uuid"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, - _uint32_t, "stream_id"); - if (ret) { - goto end; - } - - trace_packet_header = bt_ctf_field_create(trace_packet_header_type); - if (!trace_packet_header) { - ret = -1; - goto end; - } - - magic = bt_ctf_field_structure_get_field(trace_packet_header, "magic"); - ret = bt_ctf_field_unsigned_integer_set_value(magic, 0xC1FC1FC1); - if (ret) { - goto end; - } - - uuid_array = bt_ctf_field_structure_get_field(trace_packet_header, - "uuid"); - for (i = 0; i < 16; i++) { - struct bt_ctf_field *uuid_element = - bt_ctf_field_array_get_field(uuid_array, i); - ret = bt_ctf_field_unsigned_integer_set_value(uuid_element, - writer->uuid[i]); - bt_ctf_field_put(uuid_element); - if (ret) { - goto end; - } - } - - bt_ctf_field_type_put(writer->trace_packet_header_type); - bt_ctf_field_put(writer->trace_packet_header); - writer->trace_packet_header_type = trace_packet_header_type; - writer->trace_packet_header = trace_packet_header; -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_put(trace_packet_header); - } - - return ret; -} - -static -void environment_variable_destroy(struct environment_variable *var) +void bt_ctf_writer_freeze(struct bt_ctf_writer *writer) { - g_string_free(var->name, TRUE); - g_string_free(var->value, TRUE); - g_free(var); -} - -static -int create_stream_file(struct bt_ctf_writer *writer, - struct bt_ctf_stream *stream) -{ - int fd; - GString *filename = g_string_new(stream->stream_class->name->str); - - g_string_append_printf(filename, "_%" PRIu32, stream->id); - fd = openat(writer->trace_dir_fd, filename->str, - O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - g_string_free(filename, TRUE); - return fd; -} - -static -void stream_flush_cb(struct bt_ctf_stream *stream, struct bt_ctf_writer *writer) -{ - struct bt_ctf_field *stream_id; - - /* Start a new packet in the stream */ - if (stream->flushed_packet_count) { - /* ctf_init_pos has already initialized the first packet */ - ctf_packet_seek(&stream->pos.parent, 0, SEEK_CUR); - } - - stream_id = bt_ctf_field_structure_get_field( - writer->trace_packet_header, "stream_id"); - bt_ctf_field_unsigned_integer_set_value(stream_id, - stream->stream_class->id); - bt_ctf_field_put(stream_id); - - /* Write the trace_packet_header */ - bt_ctf_field_serialize(writer->trace_packet_header, &stream->pos); -} - -static __attribute__((constructor)) -void writer_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 writer_finalize(void) -{ - if (--global_data_refcount == 0) { - g_hash_table_destroy(reserved_keywords_set); - } + writer->frozen = 1; } diff --git a/include/Makefile.am b/include/Makefile.am index f6e8e492..fcbd6a3d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -5,7 +5,9 @@ babeltraceinclude_HEADERS = \ babeltrace/iterator.h \ babeltrace/trace-handle.h \ babeltrace/list.h \ - babeltrace/clock-types.h + babeltrace/clock-types.h \ + babeltrace/values.h \ + babeltrace/ref.h babeltracectfinclude_HEADERS = \ babeltrace/ctf/events.h \ @@ -18,7 +20,21 @@ babeltracectfwriterinclude_HEADERS = \ babeltrace/ctf-writer/event-fields.h \ babeltrace/ctf-writer/event-types.h \ babeltrace/ctf-writer/event.h \ - babeltrace/ctf-writer/stream.h + babeltrace/ctf-writer/stream.h \ + babeltrace/ctf-writer/stream-class.h + +babeltracectfirinclude_HEADERS = \ + babeltrace/ctf-ir/clock.h \ + babeltrace/ctf-ir/fields.h \ + babeltrace/ctf-ir/field-types.h \ + babeltrace/ctf-ir/event.h \ + babeltrace/ctf-ir/event-class.h \ + babeltrace/ctf-ir/field-path.h \ + babeltrace/ctf-ir/stream.h \ + babeltrace/ctf-ir/packet.h \ + babeltrace/ctf-ir/stream-class.h \ + babeltrace/ctf-ir/trace.h \ + babeltrace/ctf-ir/utils.h noinst_HEADERS = \ babeltrace/align.h \ @@ -31,7 +47,9 @@ noinst_HEADERS = \ babeltrace/iterator-internal.h \ babeltrace/trace-collection.h \ babeltrace/prio_heap.h \ + babeltrace/ref-internal.h \ babeltrace/types.h \ + babeltrace/object-internal.h \ babeltrace/crc32.h \ babeltrace/debug-info.h \ babeltrace/trace-debug-info.h \ @@ -45,13 +63,20 @@ noinst_HEADERS = \ babeltrace/ctf/types.h \ babeltrace/ctf/callbacks-internal.h \ babeltrace/ctf/ctf-index.h \ - babeltrace/ctf-writer/ref-internal.h \ babeltrace/ctf-writer/writer-internal.h \ - babeltrace/ctf-writer/event-types-internal.h \ - babeltrace/ctf-writer/event-fields-internal.h \ - babeltrace/ctf-writer/event-internal.h \ - babeltrace/ctf-writer/clock-internal.h \ - babeltrace/ctf-writer/stream-internal.h \ + babeltrace/ctf-ir/attributes-internal.h \ + babeltrace/ctf-ir/field-types-internal.h \ + babeltrace/ctf-ir/fields-internal.h \ + babeltrace/ctf-ir/event-internal.h \ + babeltrace/ctf-ir/event-class-internal.h \ + babeltrace/ctf-ir/field-path-internal.h \ + babeltrace/ctf-ir/clock-internal.h \ + babeltrace/ctf-ir/resolve-internal.h \ + babeltrace/ctf-ir/stream-class-internal.h \ + babeltrace/ctf-ir/stream-internal.h \ + babeltrace/ctf-ir/packet-internal.h \ + babeltrace/ctf-ir/trace-internal.h \ + babeltrace/ctf-ir/validation-internal.h \ babeltrace/ctf-writer/functor-internal.h \ babeltrace/trace-handle-internal.h \ babeltrace/compat/uuid.h \ @@ -59,6 +84,7 @@ noinst_HEADERS = \ babeltrace/compat/string.h \ babeltrace/compat/utc.h \ babeltrace/compat/limits.h \ + babeltrace/compat/glib.h \ babeltrace/compat/send.h \ babeltrace/compat/fcntl.h \ babeltrace/compat/stdlib.h \ diff --git a/include/babeltrace/compat/glib.h b/include/babeltrace/compat/glib.h new file mode 100644 index 00000000..a95d045b --- /dev/null +++ b/include/babeltrace/compat/glib.h @@ -0,0 +1,83 @@ +#ifndef _BABELTRACE_COMPAT_GLIB_H +#define _BABELTRACE_COMPAT_GLIB_H + +/* + * babeltrace/compat/glib.h + * + * Copyright (C) 2015 Michael Jeanson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#if GLIB_CHECK_VERSION(2,31,8) + +static inline gboolean +babeltrace_g_hash_table_contains(GHashTable *hash_table, gconstpointer key) +{ + return g_hash_table_contains(hash_table, key); +} + +#else + +static inline gboolean +babeltrace_g_hash_table_contains(GHashTable *hash_table, gconstpointer key) +{ + const char *value; + + value = g_hash_table_lookup(hash_table, key); + if (value == NULL) { + return FALSE; + } + + return TRUE; +} + +#endif + + +#if GLIB_CHECK_VERSION(2,29,16) + +static inline GPtrArray * +babeltrace_g_ptr_array_new_full(guint reserved_size, + GDestroyNotify element_free_func) +{ + return g_ptr_array_new_full(reserved_size, element_free_func); +} + +#else + +static inline GPtrArray * +babeltrace_g_ptr_array_new_full(guint reserved_size, + GDestroyNotify element_free_func) +{ + GPtrArray *array; + + array = g_ptr_array_sized_new(reserved_size); + if (!array) { + goto end; + } + g_ptr_array_set_free_func(array, element_free_func); +end: + return array; +} +#endif + +#endif /* _BABELTRACE_COMPAT_GLIB_H */ diff --git a/include/babeltrace/ctf-ir/attributes-internal.h b/include/babeltrace/ctf-ir/attributes-internal.h new file mode 100644 index 00000000..b6a15a8c --- /dev/null +++ b/include/babeltrace/ctf-ir/attributes-internal.h @@ -0,0 +1,70 @@ +#ifndef BABELTRACE_CTF_IR_ATTRIBUTES_H +#define BABELTRACE_CTF_IR_ATTRIBUTES_H + +/* + * attributes.c + * + * Babeltrace - CTF IR: Attributes internal + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_create(void); + +BT_HIDDEN +void bt_ctf_attributes_destroy(struct bt_value *attr_obj); + +BT_HIDDEN +int bt_ctf_attributes_get_count(struct bt_value *attr_obj); + +BT_HIDDEN +const char *bt_ctf_attributes_get_field_name(struct bt_value *attr_obj, + int index); + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_get_field_value(struct bt_value *attr_obj, + int index); + +BT_HIDDEN +int bt_ctf_attributes_set_field_value(struct bt_value *attr_obj, + const char *name, struct bt_value *value_obj); + +BT_HIDDEN +struct bt_value *bt_ctf_attributes_get_field_value_by_name( + struct bt_value *attr_obj, const char *name); + +BT_HIDDEN +int bt_ctf_attributes_freeze(struct bt_value *attr_obj); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_ATTRIBUTES_H */ diff --git a/include/babeltrace/ctf-ir/clock-internal.h b/include/babeltrace/ctf-ir/clock-internal.h new file mode 100644 index 00000000..8f7b5f07 --- /dev/null +++ b/include/babeltrace/ctf-ir/clock-internal.h @@ -0,0 +1,91 @@ +#ifndef BABELTRACE_CTF_IR_CLOCK_INTERNAL_H +#define BABELTRACE_CTF_IR_CLOCK_INTERNAL_H + +/* + * BabelTrace - CTF IR: Clock internal + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +struct bt_ctf_clock { + struct bt_object base; + GString *name; + GString *description; + uint64_t frequency; + uint64_t precision; + int64_t offset_s; /* Offset in seconds */ + int64_t offset; /* Offset in ticks */ + uint64_t value; /* Current clock value */ + uuid_t uuid; + int uuid_set; + int absolute; + + /* + * This field is set once a clock is added to a trace. If the + * trace was created by a CTF writer, then the clock's value + * can be set and returned. Otherwise both functions fail + * because, in non-writer mode, clocks do not have global + * values: values are per-stream. + */ + int has_value; + + /* + * A clock's properties can't be modified once it is added to a stream + * class. + */ + int frozen; +}; + +/* + * This is not part of the public API to prevent users from creating clocks + * in an invalid state (being nameless, in this case). + * + * The only legitimate use-case for this function is to allocate a clock + * while the TSDL metadata is being parsed. + */ +BT_HIDDEN +struct bt_ctf_clock *_bt_ctf_clock_create(void); + +/* + * Not exposed as part of the public API since the only usecase + * for this is when we are creating clocks from the TSDL metadata. + */ +BT_HIDDEN +int bt_ctf_clock_set_name(struct bt_ctf_clock *clock, + const char *name); + +BT_HIDDEN +void bt_ctf_clock_freeze(struct bt_ctf_clock *clock); + +BT_HIDDEN +void bt_ctf_clock_serialize(struct bt_ctf_clock *clock, + struct metadata_context *context); + +#endif /* BABELTRACE_CTF_IR_CLOCK_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/clock.h b/include/babeltrace/ctf-ir/clock.h new file mode 100644 index 00000000..e35882e0 --- /dev/null +++ b/include/babeltrace/ctf-ir/clock.h @@ -0,0 +1,247 @@ +#ifndef BABELTRACE_CTF_IR_CLOCK_H +#define BABELTRACE_CTF_IR_CLOCK_H + +/* + * BabelTrace - CTF IR: Clock + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_clock; + +/* + * bt_ctf_clock_create: create a clock. + * + * Allocate a new clock setting its reference count to 1. + * + * @param name Name of the clock (will be copied). + * + * Returns an allocated clock on success, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_clock_create(const char *name); + +/* + * bt_ctf_clock_get_name: get a clock's name. + * + * Get the clock's name. + * + * @param clock Clock instance. + * + * Returns the clock's name, NULL on error. + */ +extern const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_get_description: get a clock's description. + * + * Get the clock's description. + * + * @param clock Clock instance. + * + * Returns the clock's description, NULL if unset. + */ +extern const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_set_description: set a clock's description. + * + * Set the clock's description. The description appears in the clock's TSDL + * meta-data. + * + * @param clock Clock instance. + * @param desc Description of the clock. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, + const char *desc); + +/* + * bt_ctf_clock_get_frequency: get a clock's frequency. + * + * Get the clock's frequency (Hz). + * + * @param clock Clock instance. + * + * Returns the clock's frequency, -1ULL on error. + */ +extern uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_set_frequency: set a clock's frequency. + * + * Set the clock's frequency (Hz). + * + * @param clock Clock instance. + * @param freq Clock's frequency in Hz, defaults to 1 000 000 000 Hz (1ns). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, + uint64_t freq); + +/* + * bt_ctf_clock_get_precision: get a clock's precision. + * + * Get the clock's precision (in clock ticks). + * + * @param clock Clock instance. + * + * Returns the clock's precision, -1ULL on error. + */ +extern uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_set_precision: set a clock's precision. + * + * Set the clock's precision. + * + * @param clock Clock instance. + * @param precision Clock's precision in clock ticks, defaults to 1. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, + uint64_t precision); + +/* + * bt_ctf_clock_get_offset_s: get a clock's offset in seconds. + * + * Get the clock's offset in seconds from POSIX.1 Epoch, 1970-01-01. + * + * @param clock Clock instance. + * @param offset_s Pointer to clock offset in seconds (output). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, + int64_t *offset_s); + +/* + * bt_ctf_clock_set_offset_s: set a clock's offset in seconds. + * + * Set the clock's offset in seconds from POSIX.1 Epoch, 1970-01-01, + * defaults to 0. + * + * @param clock Clock instance. + * @param offset_s Clock's offset in seconds, defaults to 0. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, + int64_t offset_s); + +/* + * bt_ctf_clock_get_offset: get a clock's offset in ticks. + * + * Get the clock's offset in ticks from Epoch + offset_t. + * + * @param clock Clock instance. + * @param offset Clock offset in ticks from Epoch + offset_s (output). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, + int64_t *offset); + +/* + * bt_ctf_clock_set_offset: set a clock's offset in ticks. + * + * Set the clock's offset in ticks from Epoch + offset_s. + * + * @param clock Clock instance. + * @param offset Clock's offset in ticks from Epoch + offset_s, defaults to 0. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, + int64_t offset); + +/* + * bt_ctf_clock_get_is_absolute: get a clock's absolute attribute. + * + * Get the clock's absolute attribute. A clock is absolute if the clock is a + * global reference across the trace's other clocks. + * + * @param clock Clock instance. + * + * Returns the clock's absolute attribute, a negative value on error. + */ +extern int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_set_is_absolute: set a clock's absolute attribute. + * + * Set the clock's absolute attribute. A clock is absolute if the clock is a + * global reference across the trace's other clocks. + * + * @param clock Clock instance. + * @param is_absolute Clock's absolute attribute, defaults to FALSE. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, + int is_absolute); + +/* + * bt_ctf_clock_get_uuid: get a clock's UUID. + * + * Get the clock's UUID. + * + * @param clock Clock instance. + * + * Returns a pointer to the clock's UUID (16 byte array) on success, + * NULL on error. + */ +extern const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock); + +/* + * bt_ctf_clock_set_uuid: set a clock's UUID. + * + * Set a clock's UUID. + * + * @param clock Clock instance. + * @param uuid A 16-byte array containing a UUID. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, + const unsigned char *uuid); + +extern int64_t bt_ctf_clock_ns_from_value(struct bt_ctf_clock *clock, + uint64_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_CLOCK_H */ diff --git a/include/babeltrace/ctf-writer/event-internal.h b/include/babeltrace/ctf-ir/event-class-internal.h similarity index 59% rename from include/babeltrace/ctf-writer/event-internal.h rename to include/babeltrace/ctf-ir/event-class-internal.h index b84c3dda..1c6a9a6c 100644 --- a/include/babeltrace/ctf-writer/event-internal.h +++ b/include/babeltrace/ctf-ir/event-class-internal.h @@ -1,10 +1,10 @@ -#ifndef BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H -#define BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H +#ifndef BABELTRACE_CTF_IR_EVENT_CLASS_INTERNAL_H +#define BABELTRACE_CTF_IR_EVENT_CLASS_INTERNAL_H /* - * BabelTrace - CTF Writer: Event internal + * Babeltrace - CTF IR: Event class internal * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,64 +27,51 @@ * SOFTWARE. */ -#include -#include -#include +#include +#include #include +#include #include +#include +#include +#include #include +#define BT_CTF_EVENT_CLASS_ATTR_ID_INDEX 0 +#define BT_CTF_EVENT_CLASS_ATTR_NAME_INDEX 1 + struct bt_ctf_event_class { - struct bt_ctf_ref ref_count; - GQuark name; - int id_set; - uint32_t id; - int stream_id_set; - uint32_t stream_id; + struct bt_object base; + struct bt_value *attributes; /* Structure type containing the event's context */ struct bt_ctf_field_type *context; /* Structure type containing the event's fields */ struct bt_ctf_field_type *fields; int frozen; -}; -struct bt_ctf_event { - struct bt_ctf_ref ref_count; - uint64_t timestamp; - struct bt_ctf_event_class *event_class; - struct bt_ctf_field *context_payload; - struct bt_ctf_field *fields_payload; + /* + * This flag indicates if the event class is valid. A valid + * event class is _always_ frozen. However, an event class + * may be frozen, but not valid yet. This is okay, as long as + * no events are created out of this event class. + */ + int valid; }; BT_HIDDEN void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class); -BT_HIDDEN -int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, - uint32_t id); - -BT_HIDDEN -uint32_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class); - -BT_HIDDEN -int bt_ctf_event_class_set_stream_id(struct bt_ctf_event_class *event_class, - uint32_t id); - BT_HIDDEN int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, struct metadata_context *context); BT_HIDDEN -int bt_ctf_event_validate(struct bt_ctf_event *event); - -BT_HIDDEN -int bt_ctf_event_serialize(struct bt_ctf_event *event, - struct ctf_stream_pos *pos); +void bt_ctf_event_class_set_native_byte_order( + struct bt_ctf_event_class *event_class, + int byte_order); BT_HIDDEN -int bt_ctf_event_set_timestamp(struct bt_ctf_event *event, uint64_t timestamp); - -BT_HIDDEN -uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event); +int bt_ctf_event_class_set_stream_id(struct bt_ctf_event_class *event_class, + uint32_t stream_id); -#endif /* BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H */ +#endif /* BABELTRACE_CTF_IR_EVENT_CLASS_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/event-class.h b/include/babeltrace/ctf-ir/event-class.h new file mode 100644 index 00000000..314260a5 --- /dev/null +++ b/include/babeltrace/ctf-ir/event-class.h @@ -0,0 +1,309 @@ +#ifndef BABELTRACE_CTF_IR_EVENT_CLASS_H +#define BABELTRACE_CTF_IR_EVENT_CLASS_H + +/* + * BabelTrace - CTF IR: Event class + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_field; +struct bt_ctf_field_type; +struct bt_ctf_stream_class; + +/* + * bt_ctf_event_class_create: create an event class. + * + * Allocate a new event class of the given name. The creation of an event class + * sets its reference count to 1. A unique event id is automatically assigned + * to the event class. + * + * @param name Event class name (will be copied). + * + * Returns an allocated event class on success, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name); + +/* + * bt_ctf_event_class_get_name: Get an event class' name. + * + * @param event_class Event class. + * + * Returns the event class' name, NULL on error. + */ +extern const char *bt_ctf_event_class_get_name( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_get_id: Get an event class' id. + * + * @param event_class Event class. + * + * Returns the event class' id, a negative value on error. + */ +extern int64_t bt_ctf_event_class_get_id( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_set_id: Set an event class' id. + * + * Set an event class' id. Must be unique stream-wise. + * Note that event classes are already assigned a unique id when added to a + * stream class if none was set explicitly. + * + * @param event_class Event class. + * @param id Event class id. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_class_set_id( + struct bt_ctf_event_class *event_class, uint32_t id); + +/* + * bt_ctf_event_class_set_attribute: sets an attribute to the event + * class. + * + * Sets an attribute to the event class. The name parameter is copied, + * whereas the value parameter's reference count is incremented + * (if the function succeeds). + * + * If an attribute exists in the event class for the specified name, it + * is replaced by the new value. + * + * Valid attributes and object types are: + * + * - "id": integer object with a value >= 0 + * - "name": string object + * - "loglevel": integer object with a value >= 0 + * - "model.emf.uri": string object + * + * @param event_class Event class. + * @param name Name of the attribute (will be copied). + * @param value Value of the attribute. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_class_set_attribute( + struct bt_ctf_event_class *event_class, const char *name, + struct bt_value *value); + +/* + * bt_ctf_event_class_get_attribute_count: get the number of attributes + * in this event class. + * + * Get the event class' attribute count. + * + * @param event_class Event class. + * + * Returns the attribute count, a negative value on error. + */ +extern int bt_ctf_event_class_get_attribute_count( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_get_attribute_name: get attribute name. + * + * Get an attribute's name. The string's ownership is not + * transferred to the caller. The string data is valid as long as + * this event class' attributes are not modified. + * + * @param event_class Event class. + * @param index Index of the attribute. + * + * Returns the attribute's name, NULL on error. + */ +extern const char * +bt_ctf_event_class_get_attribute_name( + struct bt_ctf_event_class *event_class, int index); + +/* + * bt_ctf_event_class_get_attribute_value: get attribute value (an object). + * + * Get an attribute's value (an object). The returned object's + * reference count is incremented. When done with the object, the caller + * must call bt_value_put() on it. + * + * @param event_class Event class. + * @param index Index of the attribute. + * + * Returns the attribute's object value, NULL on error. + */ +extern struct bt_value * +bt_ctf_event_class_get_attribute_value(struct bt_ctf_event_class *event_class, + int index); + +/* + * bt_ctf_event_class_get_attribute_value_by_name: get attribute + * value (an object) by name. + * + * Get an attribute's value (an object) by its name. The returned object's + * reference count is incremented. When done with the object, the caller + * must call bt_value_put() on it. + * + * @param event_class Event class. + * @param name Attribute's name + * + * Returns the attribute's object value, NULL on error. + */ +extern struct bt_value * +bt_ctf_event_class_get_attribute_value_by_name( + struct bt_ctf_event_class *event_class, const char *name); + +/* + * bt_ctf_event_class_get_stream_class: Get an event class' stream class. + * + * @param event_class Event class. + * + * Returns the event class' stream class, NULL on error or if the event class + * is not associated with a stream class. + */ +extern struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_get_payload_type: get an event class' payload. + * + * Get an event class' payload type. + * + * @param event_class Event class. + * + * Returns the event class' payload, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_event_class_get_payload_type( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_set_payload_type: set an event class' payload. + * + * Set an event class' payload type. + * + * @param event_class Event class. + * @param payload The payload's type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_class_set_payload_type( + struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *payload); + +/* + * bt_ctf_event_class_add_field: add a field to an event class. + * + * Add a field of type "type" to the event class. The event class will share + * type's ownership by increasing its reference count. The "name" will be + * copied. + * + * @param event_class Event class. + * @param type Field type to add to the event class. + * @param name Name of the new field. + * + * Returns 0 on success, a negative value on error. + * + * Note: Returns an error if the payload is not a structure. + */ +extern int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *type, + const char *name); + +/* + * bt_ctf_event_class_get_field_count: Get an event class' field count. + * + * @param event_class Event class. + * + * Returns the event class' field count, a negative value on error. + * + * Note: Returns an error if the payload is not a structure. + */ +extern int bt_ctf_event_class_get_field_count( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_get_field: Get event class' field type and name by index. + * + * @param event_class Event class. + * @param field_name Pointer to a const char* where the field's name will + * be returned. + * @param field_type Pointer to a bt_ctf_field_type* where the field's type will + * be returned. + * @param index Index of field. + * + * Returns 0 on success, a negative error on value. + * + * Note: Returns an error if the payload is not a structure. + */ +extern int bt_ctf_event_class_get_field(struct bt_ctf_event_class *event_class, + const char **field_name, struct bt_ctf_field_type **field_type, + int index); + +/* + * bt_ctf_event_class_get_field_type_by_name: Get an event class's field by name + * + * @param event_class Event class. + * @param name Name of the field. + * + * Returns a field type on success, NULL on error. + * + * Note: Returns an error if the payload is not a structure. + */ +extern struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name( + struct bt_ctf_event_class *event_class, const char *name); + +/* + * bt_ctf_event_class_get_context_type: Get an event class's context type + * + * @param event_class Event class. + * + * Returns a field type (a structure) on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_event_class_get_context_type( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_class_set_context_type: Set an event class's context type + * + * @param event_class Event class. + * @param context Event context field type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_class_set_context_type( + struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *context); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_EVENT_CLASS_H */ diff --git a/include/babeltrace/ctf-ir/event-internal.h b/include/babeltrace/ctf-ir/event-internal.h new file mode 100644 index 00000000..cc10f224 --- /dev/null +++ b/include/babeltrace/ctf-ir/event-internal.h @@ -0,0 +1,78 @@ +#ifndef BABELTRACE_CTF_IR_EVENT_INTERNAL_H +#define BABELTRACE_CTF_IR_EVENT_INTERNAL_H + +/* + * Babeltrace - CTF IR: Event internal + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bt_ctf_event { + struct bt_object base; + struct bt_ctf_event_class *event_class; + struct bt_ctf_packet *packet; + struct bt_ctf_field *event_header; + struct bt_ctf_field *stream_event_context; + struct bt_ctf_field *context_payload; + struct bt_ctf_field *fields_payload; + GHashTable *clock_values; /* Maps clock addresses to (uint64_t *) */ + int frozen; +}; + +BT_HIDDEN +int bt_ctf_event_register_stream_clock_values(struct bt_ctf_event *event); + +BT_HIDDEN +int bt_ctf_event_validate(struct bt_ctf_event *event); + +BT_HIDDEN +int bt_ctf_event_serialize(struct bt_ctf_event *event, + struct ctf_stream_pos *pos); + +/* + * Attempt to populate the "id" and "timestamp" fields of the event header if + * they are present, unset and their types are integers. + * + * Not finding these fields or encountering unexpected types is not an error + * since the user may have defined a different event header layout. In this + * case, it is expected that the fields be manually populated before appending + * an event to a stream. + */ +BT_HIDDEN +int bt_ctf_event_populate_event_header(struct bt_ctf_event *event); + +BT_HIDDEN +void bt_ctf_event_freeze(struct bt_ctf_event *event); + +#endif /* BABELTRACE_CTF_IR_EVENT_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/event.h b/include/babeltrace/ctf-ir/event.h new file mode 100644 index 00000000..840627ea --- /dev/null +++ b/include/babeltrace/ctf-ir/event.h @@ -0,0 +1,255 @@ +#ifndef BABELTRACE_CTF_IR_EVENT_H +#define BABELTRACE_CTF_IR_EVENT_H + +/* + * BabelTrace - CTF IR: Event + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field; +struct bt_ctf_field_type; +struct bt_ctf_stream_class; +struct bt_ctf_packet; + +/* + * bt_ctf_event_create: instanciate an event. + * + * Allocate a new event of the given event class. The creation of an event + * sets its reference count to 1. Each instance shares the ownership of the + * event class using its reference count. + * + * An event class must be associated with a stream class before events + * may be instanciated. + * + * @param event_class Event class. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_event *bt_ctf_event_create( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_get_class: get an event's class. + * + * @param event Event. + * + * Returns the event's class, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_event_get_class( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_get_stream: get an event's associated stream. + * + * @param event Event. + * + * Returns the event's associated stream, NULL on error. + */ +extern struct bt_ctf_stream *bt_ctf_event_get_stream( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_get_clock: get an event's associated clock. + * + * @param event Event. + * + * Returns the event's clock, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_event_get_clock( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_get_payload_field: get an event's payload. + * + * @param event Event instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_event_get_payload_field( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_set_payload_field: set an event's payload. + * + * @param event Event instance. + * @param payload Field instance (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_set_payload_field(struct bt_ctf_event *event, + struct bt_ctf_field *payload); + +/* + * bt_ctf_event_get_payload: get an event's field. + * + * Returns the field matching "name". bt_ctf_field_put() must be called on the + * returned value. + * + * @param event Event instance. + * @param name Event field name, see notes. + * + * Returns a field instance on success, NULL on error. + * + * Note: Passing a name will cause the function to perform a look-up by + * name assuming the event's payload is a structure. This will return + * the raw payload instance if name is NULL. + */ +extern struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, + const char *name); + +/* + * bt_ctf_event_set_payload: set an event's field. + * + * Set a manually allocated field as an event's payload. The event will share + * the field's ownership by using its reference count. + * bt_ctf_field_put() must be called on the returned value. + * + * @param event Event instance. + * @param name Event field name, see notes. + * @param value Instance of a field whose type corresponds to the event's field. + * + * Returns 0 on success, a negative value on error. + * + * Note: The function will return an error if a name is provided and the payload + * type is not a structure. If name is NULL, the payload field will be set + * directly and must match the event class' payload's type. + */ +extern int bt_ctf_event_set_payload(struct bt_ctf_event *event, + const char *name, + struct bt_ctf_field *value); + +/* + * bt_ctf_event_get_payload_by_index: Get event's field by index. + * + * Returns the field associated with the provided index. bt_ctf_field_put() + * must be called on the returned value. The indexes to be provided are + * the same as can be retrieved from the event class. + * + * @param event Event. + * @param index Index of field. + * + * Returns the event's field, NULL on error. + * + * Note: Will return an error if the payload's type is not a structure. + */ +extern struct bt_ctf_field *bt_ctf_event_get_payload_by_index( + struct bt_ctf_event *event, int index); + +/* + * bt_ctf_event_get_header: get an event's header. + * + * @param event Event instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_event_get_header( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_set_header: set an event's header. + * + * The event header's type must match the stream class' event + * header type. + * + * @param event Event instance. + * @param header Event header field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern int bt_ctf_event_set_header( + struct bt_ctf_event *event, + struct bt_ctf_field *header); + +/* + * bt_ctf_event_get_event_context: Get an event's context + * + * @param event_class Event class. + * + * Returns a field on success (a structure), NULL on error. + * + * Note: This function is named this way instead of the expected + * "bt_ctf_event_get_context" in order to work around a name clash with + * an unrelated function bearing this name in context.h. + */ +extern struct bt_ctf_field *bt_ctf_event_get_event_context( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_set_event_context: Set an event's context + * + * @param event Event. + * @param context Event context field (must match the event class' + * context type). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_set_event_context(struct bt_ctf_event *event, + struct bt_ctf_field *context); + +/* + * bt_ctf_event_get_stream_event_context: Get an event's stream event context + * + * @param event_class Event class. + * + * Returns a field on success (a structure), NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_event_get_stream_event_context( + struct bt_ctf_event *event); + +/* + * bt_ctf_event_set_stream_event_context: Set an event's stream event context + * + * @param event Event. + * @param context Event stream context field (must match the stream class' + * stream event context type). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event, + struct bt_ctf_field *context); + +extern int bt_ctf_event_set_packet(struct bt_ctf_event *event, + struct bt_ctf_packet *packet); + +extern uint64_t bt_ctf_event_get_clock_value(struct bt_ctf_event *event, + struct bt_ctf_clock *clock); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_EVENT_H */ diff --git a/include/babeltrace/ctf-ir/field-path-internal.h b/include/babeltrace/ctf-ir/field-path-internal.h new file mode 100644 index 00000000..de08a87e --- /dev/null +++ b/include/babeltrace/ctf-ir/field-path-internal.h @@ -0,0 +1,57 @@ +#ifndef BABELTRACE_CTF_IR_FIELD_PATH_INTERNAL +#define BABELTRACE_CTF_IR_FIELD_PATH_INTERNAL + +/* + * BabelTrace - CTF IR: Field path + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include + +struct bt_ctf_field_path { + struct bt_object base; + enum bt_ctf_scope root; + + /* + * Array of integers (int) indicating the index in either + * structures, variants, arrays, or sequences that make up + * the path to a field type. -1 means the "current element + * of an array or sequence type". + */ + GArray *indexes; +}; + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_create(void); + +BT_HIDDEN +void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path); + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_copy( + struct bt_ctf_field_path *path); + +#endif /* BABELTRACE_CTF_IR_FIELD_PATH_INTERNAL */ diff --git a/include/babeltrace/ctf-ir/field-path.h b/include/babeltrace/ctf-ir/field-path.h new file mode 100644 index 00000000..40acfc8b --- /dev/null +++ b/include/babeltrace/ctf-ir/field-path.h @@ -0,0 +1,81 @@ +#ifndef BABELTRACE_CTF_IR_FIELD_PATH +#define BABELTRACE_CTF_IR_FIELD_PATH + +/* + * BabelTrace - CTF IR: Field path + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_field_path; + +/* + * bt_ctf_field_path_get_root_scope: get the root node of a field path. + * + * Get the field path's root node. + * + * @param field_path Field path. + * + * Returns the root node of a field path, or BT_CTF_SCOPE_UNKNOWN on error. + */ +extern enum bt_ctf_scope bt_ctf_field_path_get_root_scope( + const struct bt_ctf_field_path *field_path); + +/* + * bt_ctf_field_path_get_index_count: get the number of indexes of a field path. + * + * Get the number of indexes of a field path. + * + * @param field_path Field path. + * + * Returns the field path's index count, or a negative value on error. + */ +extern int bt_ctf_field_path_get_index_count( + const struct bt_ctf_field_path *field_path); + +/* + * bt_ctf_field_path_get_index: get the field path's index at a specific index. + * + * Get the field path's index at a specific index. + * + * @param field_path Field path. + * @param index Index. + * + * Returns a field path index, or INT_MIN on error. + */ +extern int bt_ctf_field_path_get_index( + const struct bt_ctf_field_path *field_path, + int index); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_FIELD_PATH */ diff --git a/include/babeltrace/ctf-ir/field-types-internal.h b/include/babeltrace/ctf-ir/field-types-internal.h new file mode 100644 index 00000000..4e401ebe --- /dev/null +++ b/include/babeltrace/ctf-ir/field-types-internal.h @@ -0,0 +1,276 @@ +#ifndef BABELTRACE_CTF_IR_FIELD_TYPES_INTERNAL_H +#define BABELTRACE_CTF_IR_FIELD_TYPES_INTERNAL_H + +/* + * BabelTrace - CTF IR: Event field types internal + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef void (*type_freeze_func)(struct bt_ctf_field_type *); +typedef int (*type_serialize_func)(struct bt_ctf_field_type *, + struct metadata_context *); + +enum bt_ctf_type_id { + BT_CTF_TYPE_ID_UNKNOWN = CTF_TYPE_UNKNOWN, + BT_CTF_TYPE_ID_INTEGER = CTF_TYPE_INTEGER, + BT_CTF_TYPE_ID_FLOAT = CTF_TYPE_FLOAT, + BT_CTF_TYPE_ID_ENUM = CTF_TYPE_ENUM, + BT_CTF_TYPE_ID_STRING = CTF_TYPE_STRING, + BT_CTF_TYPE_ID_STRUCT = CTF_TYPE_STRUCT, + BT_CTF_TYPE_ID_UNTAGGED_VARIANT = CTF_TYPE_UNTAGGED_VARIANT, + BT_CTF_TYPE_ID_VARIANT = CTF_TYPE_VARIANT, + BT_CTF_TYPE_ID_ARRAY = CTF_TYPE_ARRAY, + BT_CTF_TYPE_ID_SEQUENCE = CTF_TYPE_SEQUENCE, + BT_CTF_NR_TYPE_IDS, +}; + +enum bt_ctf_ir_scope { + BT_CTF_SCOPE_UNKNOWN = -1, + BT_CTF_SCOPE_ENV = 0, + BT_CTF_SCOPE_TRACE_PACKET_HEADER = 1, + BT_CTF_SCOPE_STREAM_PACKET_CONTEXT = 2, + BT_CTF_SCOPE_STREAM_EVENT_HEADER = 3, + BT_CTF_SCOPE_STREAM_EVENT_CONTEXT = 4, + BT_CTF_SCOPE_EVENT_CONTEXT = 5, + BT_CTF_SCOPE_EVENT_FIELDS = 6, +}; + +struct bt_ctf_field_type { + struct bt_object base; + struct bt_declaration *declaration; + type_freeze_func freeze; + type_serialize_func serialize; + /* + * A type can't be modified once it is added to an event or after a + * a field has been instanciated from it. + */ + int frozen; + + /* + * This flag indicates if the field type is valid. A valid + * field type is _always_ frozen. All the nested field types of + * a valid field type are also valid (and thus frozen). + */ + int valid; +}; + +struct bt_ctf_field_type_integer { + struct bt_ctf_field_type parent; + struct declaration_integer declaration; + struct bt_ctf_clock *mapped_clock; + + /* + * This is what the user sets and is never modified by internal + * code. + * + * This field must contain a `BT_CTF_BYTE_ORDER_*` value. + */ + enum bt_ctf_byte_order user_byte_order; +}; + +struct enumeration_mapping { + union { + uint64_t _unsigned; + int64_t _signed; + } range_start; + + union { + uint64_t _unsigned; + int64_t _signed; + } range_end; + GQuark string; +}; + +struct bt_ctf_field_type_enumeration { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *container; + GPtrArray *entries; /* Array of ptrs to struct enumeration_mapping */ + struct declaration_enum declaration; +}; + +struct bt_ctf_field_type_floating_point { + struct bt_ctf_field_type parent; + struct declaration_float declaration; + + /* + * The `declaration` field above contains 3 pointers pointing + * to the fields below. This avoids unnecessary dynamic + * allocations. + */ + struct declaration_integer sign; + struct declaration_integer mantissa; + struct declaration_integer exp; + + /* + * This is what the user sets and is never modified by internal + * code. + * + * This field must contain a `BT_CTF_BYTE_ORDER_*` value. + */ + enum bt_ctf_byte_order user_byte_order; +}; + +struct structure_field { + GQuark name; + struct bt_ctf_field_type *type; +}; + +struct bt_ctf_field_type_structure { + struct bt_ctf_field_type parent; + GHashTable *field_name_to_index; + GPtrArray *fields; /* Array of pointers to struct structure_field */ + struct declaration_struct declaration; +}; + +struct bt_ctf_field_type_variant { + struct bt_ctf_field_type parent; + GString *tag_name; + struct bt_ctf_field_type_enumeration *tag; + struct bt_ctf_field_path *tag_field_path; + GHashTable *field_name_to_index; + GPtrArray *fields; /* Array of pointers to struct structure_field */ + struct declaration_variant declaration; +}; + +struct bt_ctf_field_type_array { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *element_type; + unsigned int length; /* Number of elements */ + struct declaration_array declaration; +}; + +struct bt_ctf_field_type_sequence { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *element_type; + GString *length_field_name; + struct bt_ctf_field_path *length_field_path; + struct declaration_sequence declaration; +}; + +struct bt_ctf_field_type_string { + struct bt_ctf_field_type parent; + struct declaration_string declaration; +}; + +BT_HIDDEN +void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_signed( + struct bt_ctf_field_type_variant *variant, int64_t tag_value); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_unsigned( + struct bt_ctf_field_type_variant *variant, uint64_t tag_value); + +BT_HIDDEN +int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context); + +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type); + +BT_HIDDEN +const char *bt_ctf_field_type_enumeration_get_mapping_name_unsigned( + struct bt_ctf_field_type_enumeration *enumeration_type, + uint64_t value); + +BT_HIDDEN +const char *bt_ctf_field_type_enumeration_get_mapping_name_signed( + struct bt_ctf_field_type_enumeration *enumeration_type, + int64_t value); + +/* Override field type's byte order only if it is set to "native" */ +BT_HIDDEN +void bt_ctf_field_type_set_native_byte_order( + struct bt_ctf_field_type *type, int byte_order); + +/* Deep copy a field type */ +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_copy( + struct bt_ctf_field_type *type); + +BT_HIDDEN +int bt_ctf_field_type_structure_get_field_name_index( + struct bt_ctf_field_type *structure, const char *name); + +/* Replace an existing field's type in a structure */ +BT_HIDDEN +int bt_ctf_field_type_structure_set_field_index( + struct bt_ctf_field_type *structure, + struct bt_ctf_field_type *field, int index); + +BT_HIDDEN +int bt_ctf_field_type_variant_get_field_name_index( + struct bt_ctf_field_type *variant, const char *name); + +BT_HIDDEN +int bt_ctf_field_type_sequence_set_length_field_path( + struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path); + +BT_HIDDEN +int bt_ctf_field_type_variant_set_tag_field_path(struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path); + +BT_HIDDEN +int bt_ctf_field_type_variant_set_tag_field_type(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *tag_type); + +/* Replace an existing field's type in a variant */ +BT_HIDDEN +int bt_ctf_field_type_variant_set_field_index( + struct bt_ctf_field_type *variant, + struct bt_ctf_field_type *field, int index); + +BT_HIDDEN +int bt_ctf_field_type_array_set_element_type(struct bt_ctf_field_type *array, + struct bt_ctf_field_type *element_type); + +BT_HIDDEN +int bt_ctf_field_type_sequence_set_element_type(struct bt_ctf_field_type *array, + struct bt_ctf_field_type *element_type); + +BT_HIDDEN +int bt_ctf_field_type_get_field_count(struct bt_ctf_field_type *type); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_get_field_at_index( + struct bt_ctf_field_type *type, int index); + +BT_HIDDEN +int bt_ctf_field_type_get_field_index(struct bt_ctf_field_type *type, + const char *name); + +#endif /* BABELTRACE_CTF_IR_FIELD_TYPES_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/field-types.h b/include/babeltrace/ctf-ir/field-types.h new file mode 100644 index 00000000..e38acabf --- /dev/null +++ b/include/babeltrace/ctf-ir/field-types.h @@ -0,0 +1,893 @@ +#ifndef BABELTRACE_CTF_IR_FIELD_TYPES_H +#define BABELTRACE_CTF_IR_FIELD_TYPES_H + +/* + * BabelTrace - CTF IR: Event field types + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field_type; +struct bt_ctf_field; +struct bt_ctf_field_path; + +enum bt_ctf_integer_base { + BT_CTF_INTEGER_BASE_UNKNOWN = -1, + BT_CTF_INTEGER_BASE_BINARY = 2, + BT_CTF_INTEGER_BASE_OCTAL = 8, + BT_CTF_INTEGER_BASE_DECIMAL = 10, + BT_CTF_INTEGER_BASE_HEXADECIMAL = 16, +}; + +enum bt_ctf_byte_order { + BT_CTF_BYTE_ORDER_UNKNOWN = -1, + /* + * Note that native, in the context of the CTF specification, is defined + * as "the byte order described in the trace" and does not mean that the + * host's endianness will be used. + */ + BT_CTF_BYTE_ORDER_NATIVE = 0, + BT_CTF_BYTE_ORDER_LITTLE_ENDIAN, + BT_CTF_BYTE_ORDER_BIG_ENDIAN, + BT_CTF_BYTE_ORDER_NETWORK, +}; + +enum bt_ctf_string_encoding { + BT_CTF_STRING_ENCODING_NONE = CTF_STRING_NONE, + BT_CTF_STRING_ENCODING_UTF8 = CTF_STRING_UTF8, + BT_CTF_STRING_ENCODING_ASCII = CTF_STRING_ASCII, + BT_CTF_STRING_ENCODING_UNKNOWN = CTF_STRING_UNKNOWN, +}; + +/* + * bt_ctf_field_type_integer_create: create an integer field type. + * + * Allocate a new integer field type of the given size. The creation of a field + * type sets its reference count to 1. + * + * @param size Integer field type size/length in bits. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_integer_create( + unsigned int size); + +/* + * bt_ctf_field_type_integer_get_size: get an integer type's size. + * + * Get an integer type's size. + * + * @param integer Integer type. + * + * Returns the integer type's size, a negative value on error. + */ +extern int bt_ctf_field_type_integer_get_size( + struct bt_ctf_field_type *integer); + +/* + * bt_ctf_field_type_integer_get_signed: get an integer type's signedness. + * + * Get an integer type's signedness attribute. + * + * @param integer Integer type. + * + * Returns the integer's signedness, a negative value on error. + */ +extern int bt_ctf_field_type_integer_get_signed( + struct bt_ctf_field_type *integer); + +/* + * bt_ctf_field_type_integer_set_signed: set an integer type's signedness. + * + * Set an integer type's signedness attribute. + * + * @param integer Integer type. + * @param is_signed Integer's signedness, defaults to FALSE. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_signed( + struct bt_ctf_field_type *integer, int is_signed); + +/* + * bt_ctf_field_type_integer_get_base: get an integer type's base. + * + * Get an integer type's base used to pretty-print the resulting trace. + * + * @param integer Integer type. + * + * Returns the integer type's base on success, BT_CTF_INTEGER_BASE_UNKNOWN on + * error. + */ +extern enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base( + struct bt_ctf_field_type *integer); + +/* + * bt_ctf_field_type_integer_set_base: set an integer type's base. + * + * Set an integer type's base used to pretty-print the resulting trace. + * + * @param integer Integer type. + * @param base Integer base, defaults to BT_CTF_INTEGER_BASE_DECIMAL. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *integer, + enum bt_ctf_integer_base base); + +/* + * bt_ctf_field_type_integer_get_encoding: get an integer type's encoding. + * + * @param integer Integer type. + * + * Returns the string field's encoding on success, + * BT_CTF_STRING_ENCODING_UNKNOWN on error. + */ +extern enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding( + struct bt_ctf_field_type *integer); + +/* + * bt_ctf_field_type_integer_set_encoding: set an integer type's encoding. + * + * An integer encoding may be set to signal that the integer must be printed as + * a text character. + * + * @param integer Integer type. + * @param encoding Integer output encoding, defaults to + * BT_CTF_STRING_ENCODING_NONE + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_encoding( + struct bt_ctf_field_type *integer, + enum bt_ctf_string_encoding encoding); + +/** + * bt_ctf_field_type_integer_get_mapped_clock: get an integer type's mapped clock. + * + * @param integer Integer type. + * + * Returns the integer's mapped clock (if any), NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_field_type_integer_get_mapped_clock( + struct bt_ctf_field_type *integer); + +/** + * bt_ctf_field_type_integer_set_mapped_clock: set an integer type's mapped clock. + * + * @param integer Integer type. + * @param clock Clock to map. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_mapped_clock( + struct bt_ctf_field_type *integer, + struct bt_ctf_clock *clock); + +/* + * bt_ctf_field_type_enumeration_create: create an enumeration field type. + * + * Allocate a new enumeration field type with the given underlying type. The + * creation of a field type sets its reference count to 1. + * The resulting enumeration will share the integer_container_type's ownership + * by increasing its reference count. + * + * @param integer_container_type Underlying integer type of the enumeration + * type. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( + struct bt_ctf_field_type *integer_container_type); + +/* + * bt_ctf_field_type_enumeration_get_container_type: get underlying container. + * + * Get the enumeration type's underlying integer container type. + * + * @param enumeration Enumeration type. + * + * Returns an allocated field type on success, NULL on error. + */ +extern +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_type( + struct bt_ctf_field_type *enumeration); + +/* + * bt_ctf_field_type_enumeration_add_mapping: add an enumeration mapping. + * + * Add a mapping to the enumeration. The range's values are inclusive. + * + * @param enumeration Enumeration type. + * @param name Enumeration mapping name (will be copied). + * @param range_start Enumeration mapping range start. + * @param range_end Enumeration mapping range end. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_add_mapping( + struct bt_ctf_field_type *enumeration, const char *name, + int64_t range_start, int64_t range_end); + +/* + * bt_ctf_field_type_enumeration_add_mapping_unsigned: add an enumeration + * mapping. + * + * Add a mapping to the enumeration. The range's values are inclusive. + * + * @param enumeration Enumeration type. + * @param name Enumeration mapping name (will be copied). + * @param range_start Enumeration mapping range start. + * @param range_end Enumeration mapping range end. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_add_mapping_unsigned( + struct bt_ctf_field_type *enumeration, const char *name, + uint64_t range_start, uint64_t range_end); + +/* + * bt_ctf_field_type_enumeration_get_mapping_count: Get the number of mappings + * defined in the enumeration. + * + * @param enumeration Enumeration type. + * + * Returns the mapping count on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping_count( + struct bt_ctf_field_type *enumeration); + +/* + * bt_ctf_field_type_enumeration_get_mapping: get an enumeration mapping. + * + * @param enumeration Enumeration type. + * @param index Index of mapping. + * @param name Pointer where the mapping's name will be returned (valid for + * the lifetime of the enumeration). + * @param range_start Pointer where the enumeration mapping's range start will + * be returned. + * @param range_end Pointer where the enumeration mapping's range end will + * be returned. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping( + struct bt_ctf_field_type *enumeration, int index, + const char **name, int64_t *range_start, int64_t *range_end); + +/* + * bt_ctf_field_type_enumeration_get_mapping_unsigned: get a mapping. + * + * @param enumeration Enumeration type. + * @param index Index of mapping. + * @param name Pointer where the mapping's name will be returned (valid for + * the lifetime of the enumeration). + * @param range_start Pointer where the enumeration mapping's range start will + * be returned. + * @param range_end Pointer where the enumeration mapping's range end will + * be returned. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping_unsigned( + struct bt_ctf_field_type *enumeration, int index, + const char **name, uint64_t *range_start, + uint64_t *range_end); + +/* + * bt_ctf_field_type_enumeration_get_mapping_index_by_name: get an enumerations' + * mapping index by name. + * + * @param enumeration Enumeration type. + * @param name Mapping name. + * + * Returns mapping index on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping_index_by_name( + struct bt_ctf_field_type *enumeration, const char *name); + +/* + * bt_ctf_field_type_enumeration_get_mapping_index_by_value: get an + * enumerations' mapping index by value. + * + * @param enumeration Enumeration type. + * @param value Value. + * + * Returns mapping index on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping_index_by_value( + struct bt_ctf_field_type *enumeration, int64_t value); + +/* + * bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value: get an + * enumerations' mapping index by value. + * + * @param enumeration Enumeration type. + * @param value Value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value( + struct bt_ctf_field_type *enumeration, uint64_t value); + +/* + * bt_ctf_field_type_floating_point_create: create a floating point field type. + * + * Allocate a new floating point field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void); + +/* + * bt_ctf_field_type_floating_point_get_exponent_digits: get exponent digit + * count. + * + * @param floating_point Floating point type. + * + * Returns the exponent digit count on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_get_exponent_digits( + struct bt_ctf_field_type *floating_point); + +/* + * bt_ctf_field_type_floating_point_set_exponent_digits: set exponent digit + * count. + * + * Set the number of exponent digits to use to store the floating point field. + * The only values currently supported are FLT_EXP_DIG and DBL_EXP_DIG. + * + * @param floating_point Floating point type. + * @param exponent_digits Number of digits to allocate to the exponent (defaults + * to FLT_EXP_DIG). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_set_exponent_digits( + struct bt_ctf_field_type *floating_point, + unsigned int exponent_digits); + +/* + * bt_ctf_field_type_floating_point_get_mantissa_digits: get mantissa digit + * count. + * + * @param floating_point Floating point type. + * + * Returns the mantissa digit count on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_get_mantissa_digits( + struct bt_ctf_field_type *floating_point); + +/* + * bt_ctf_field_type_floating_point_set_mantissa_digits: set mantissa digit + * count. + * + * Set the number of mantissa digits to use to store the floating point field. + * The only values currently supported are FLT_MANT_DIG and DBL_MANT_DIG. + * + * @param floating_point Floating point type. + * @param mantissa_digits Number of digits to allocate to the mantissa (defaults + * to FLT_MANT_DIG). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_set_mantissa_digits( + struct bt_ctf_field_type *floating_point, + unsigned int mantissa_digits); + +/* + * bt_ctf_field_type_structure_create: create a structure field type. + * + * Allocate a new structure field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void); + +/* + * bt_ctf_field_type_structure_add_field: add a field to a structure. + * + * Add a field of type "field_type" to the structure. The structure will share + * field_type's ownership by increasing its reference count. + * + * @param structure Structure type. + * @param field_type Type of the field to add to the structure type. + * @param field_name Name of the structure's new field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_structure_add_field( + struct bt_ctf_field_type *structure, + struct bt_ctf_field_type *field_type, + const char *field_name); + +/* + * bt_ctf_field_type_structure_get_field_count: Get the number of fields defined + * in the structure. + * + * @param structure Structure type. + * + * Returns the field count on success, a negative value on error. + */ +extern int bt_ctf_field_type_structure_get_field_count( + struct bt_ctf_field_type *structure); + +/* + * bt_ctf_field_type_structure_get_field: get a structure's field type and name. + * + * @param structure Structure type. + * @param field_type Pointer to a const char* where the field's name will + * be returned. + * @param field_type Pointer to a bt_ctf_field_type* where the field's type will + * be returned. + * @param index Index of field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_structure_get_field( + struct bt_ctf_field_type *structure, + const char **field_name, struct bt_ctf_field_type **field_type, + int index); + +/* + * bt_ctf_field_type_structure_get_field_type_by_name: get a structure field's + * type by name. + * + * @param structure Structure type. + * @param field_name Name of the structure's field. + * + * Returns a field type instance on success, NULL on error. + */ +extern +struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name( + struct bt_ctf_field_type *structure, const char *field_name); + +/* + * bt_ctf_field_type_variant_create: create a variant field type. + * + * Allocate a new variant field type. The creation of a field type sets + * its reference count to 1. tag_name must be the name of an enumeration + * field declared in the same scope as this variant. + * + * @param enum_tag Type of the variant's tag/selector (must be an enumeration). + * @param tag_name Name of the variant's tag/selector field (will be copied). + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_variant_create( + struct bt_ctf_field_type *enum_tag, const char *tag_name); + +/* + * bt_ctf_field_type_variant_get_tag_type: get a variant's tag type. + * + * @param variant Variant type. + * + * Returns a field type instance on success, NULL if unset. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_type( + struct bt_ctf_field_type *variant); + +/* + * bt_ctf_field_type_variant_get_tag_name: get a variant's tag name. + * + * @param variant Variant type. + * + * Returns the tag field's name, NULL if unset. + */ +extern const char *bt_ctf_field_type_variant_get_tag_name( + struct bt_ctf_field_type *variant); + +/* + * bt_ctf_field_type_variant_set_tag_name: set a variant's tag name. + * + * @param variant Variant type. + * @param name Tag field name. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_variant_set_tag_name( + struct bt_ctf_field_type *variant, const char *name); + +/* + * bt_ctf_field_type_variant_add_field: add a field to a variant. + * + * Add a field of type "field_type" to the variant. The variant will share + * field_type's ownership by increasing its reference count. The "field_name" + * will be copied. field_name must match a mapping in the tag/selector + * enumeration. + * + * @param variant Variant type. + * @param field_type Type of the variant type's new field. + * @param field_name Name of the variant type's new field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_variant_add_field( + struct bt_ctf_field_type *variant, + struct bt_ctf_field_type *field_type, + const char *field_name); + +/* + * bt_ctf_field_type_variant_get_field_type_by_name: get variant field's type. + * + * @param structure Variant type. + * @param field_name Name of the variant's field. + * + * Returns a field type instance on success, NULL on error. + */ +extern +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name( + struct bt_ctf_field_type *variant, const char *field_name); + +/* + * bt_ctf_field_type_variant_get_field_type_from_tag: get variant field's type. + * + * @param variant Variant type. + * @param tag Type tag (enum). + * + * Returns a field type instance on success, NULL on error. + */ +extern +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag( + struct bt_ctf_field_type *variant, struct bt_ctf_field *tag); + +/* + * bt_ctf_field_type_variant_get_field_count: Get the number of fields defined + * in the variant. + * + * @param variant Variant type. + * + * Returns the field count on success, a negative value on error. + */ +extern int bt_ctf_field_type_variant_get_field_count( + struct bt_ctf_field_type *variant); + +/* + * bt_ctf_field_type_variant_get_field: get a variant's field name and type. + * + * @param variant Variant type. + * @param field_type Pointer to a const char* where the field's name will + * be returned. + * @param field_type Pointer to a bt_ctf_field_type* where the field's type will + * be returned. + * @param index Index of field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_variant_get_field( + struct bt_ctf_field_type *variant, const char **field_name, + struct bt_ctf_field_type **field_type, int index); + +/* + * bt_ctf_field_type_array_create: create an array field type. + * + * Allocate a new array field type. The creation of a field type sets + * its reference count to 1. + * + * @param element_type Array's element type. + * @oaram length Array type's length. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_array_create( + struct bt_ctf_field_type *element_type, unsigned int length); + +/* + * bt_ctf_field_type_array_get_element_type: get an array's element type. + * + * @param array Array type. + * + * Returns a field type instance on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( + struct bt_ctf_field_type *array); + +/* + * bt_ctf_field_type_array_get_length: get an array's length. + * + * @param array Array type. + * + * Returns the array's length on success, a negative value on error. + */ +extern int64_t bt_ctf_field_type_array_get_length( + struct bt_ctf_field_type *array); + +/* + * bt_ctf_field_type_sequence_create: create a sequence field type. + * + * Allocate a new sequence field type. The creation of a field type sets + * its reference count to 1. "length_field_name" must match an integer field + * declared in the same scope. + * + * @param element_type Sequence's element type. + * @param length_field_name Name of the sequence's length field (will be + * copied). + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( + struct bt_ctf_field_type *element_type, + const char *length_field_name); + +/* + * bt_ctf_field_type_sequence_get_element_type: get a sequence's element type. + * + * @param sequence Sequence type. + * + * Returns a field type instance on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( + struct bt_ctf_field_type *sequence); + +/* + * bt_ctf_field_type_sequence_get_length_field_name: get length field name. + * + * @param sequence Sequence type. + * + * Returns the sequence's length field on success, NULL on error. + */ +extern const char *bt_ctf_field_type_sequence_get_length_field_name( + struct bt_ctf_field_type *sequence); + +/* + * bt_ctf_field_type_string_create: create a string field type. + * + * Allocate a new string field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_string_create(void); + +/* + * bt_ctf_field_type_string_get_encoding: get a string type's encoding. + * + * Get the string type's encoding. + * + * @param string_type String type. + * + * Returns the string's encoding on success, a BT_CTF_STRING_ENCODING_UNKNOWN + * on error. + */ +extern enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding( + struct bt_ctf_field_type *string_type); + +/* + * bt_ctf_field_type_string_set_encoding: set a string type's encoding. + * + * Set the string type's encoding. + * + * @param string_type String type. + * @param encoding String field encoding, default BT_CTF_STRING_ENCODING_ASCII. + * Valid values are BT_CTF_STRING_ENCODING_ASCII and + * BT_CTF_STRING_ENCODING_UTF8. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_string_set_encoding( + struct bt_ctf_field_type *string_type, + enum bt_ctf_string_encoding encoding); + +/* + * bt_ctf_field_type_get_alignment: get a field type's alignment. + * + * Get the field type's alignment. + * + * @param type Field type. + * + * Returns the field type's alignment on success, a negative value on error and + * 0 if the alignment is undefined (as in the case of a variant). + */ +extern int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_set_alignment: set a field type's alignment. + * + * Set the field type's alignment. + * + * @param type Field type. + * @param alignment Type's alignment. Defaults to 1 (bit-aligned). However, + * some types, such as structures and string, may impose other alignment + * constraints. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, + unsigned int alignment); + +/* + * bt_ctf_field_type_get_byte_order: get a field type's byte order. + * + * @param type Field type. + * + * Returns the field type's byte order on success, a negative value on error. + */ +extern enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_set_byte_order: set a field type's byte order. + * + * Set the field type's byte order. + * + * @param type Field type. + * @param byte_order Field type's byte order. Defaults to + * BT_CTF_BYTE_ORDER_NATIVE; the trace's endianness. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, + enum bt_ctf_byte_order byte_order); + +/* + * bt_ctf_field_type_variant_get_tag_field_path: get a variant's tag's field + * path. + * + * Get the variant's tag's field path. + * + * @param type Field type. + * + * Returns the field path on success, NULL on error or if no field path is set. + */ +extern struct bt_ctf_field_path *bt_ctf_field_type_variant_get_tag_field_path( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_sequence_get_length_field_path: get a sequence's length's + * field path. + * + * Get the sequence's length's field path. + * + * @param type Field type. + * + * Returns the field path on success, NULL on error or if no field path is set. + */ +extern struct bt_ctf_field_path *bt_ctf_field_type_sequence_get_length_field_path( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_compare: compare two field types recursively + * + * Compare two field types recursively. + * + * The registered tag field type of a variant field type is ignored: + * only the tag strings are compared. + * + * @param type_a Field type A. + * @param type_b Field type B. + * + * Returns 0 if both field types are semantically equivalent, a positive + * value if they are not equivalent, or a negative value on error. + */ +extern int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b); + +/* + * bt_ctf_field_type_get_type_id: get a field type's bt_ctf_type_id. + * + * @param type Field type. + * + * Returns the field type's bt_ctf_type_id, CTF_TYPE_UNKNOWN on error. + */ +extern enum bt_ctf_type_id bt_ctf_field_type_get_type_id( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_integer: returns whether or not a given field + * type is an integer type. + * + * @param type Field type. + * + * Returns 1 if the field type is an integer type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_integer(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_floating_point: returns whether or not a given field + * type is a floating point number type. + * + * @param type Field type. + * + * Returns 1 if the field type is a floating point number type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_floating_point(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_enumeration: returns whether or not a given field + * type is an enumeration type. + * + * @param type Field type. + * + * Returns 1 if the field type is an enumeration type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_enumeration(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_string: returns whether or not a given field + * type is a string type. + * + * @param type Field type. + * + * Returns 1 if the field type is a string type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_string(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_structure: returns whether or not a given field + * type is a structure type. + * + * @param type Field type. + * + * Returns 1 if the field type is a structure type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_structure(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_array: returns whether or not a given field + * type is an array type. + * + * @param type Field type. + * + * Returns 1 if the field type is an array type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_array(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_sequence: returns whether or not a given field + * type is a sequence type. + * + * @param type Field type. + * + * Returns 1 if the field type is a sequence type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_sequence(struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_type_is_variant: returns whether or not a given field + * type is a variant type. + * + * @param type Field type. + * + * Returns 1 if the field type is a variant type, 0 otherwise. + */ +extern int bt_ctf_field_type_is_variant(struct bt_ctf_field_type *type); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_FIELD_TYPES_H */ diff --git a/include/babeltrace/ctf-writer/event-fields-internal.h b/include/babeltrace/ctf-ir/fields-internal.h similarity index 82% rename from include/babeltrace/ctf-writer/event-fields-internal.h rename to include/babeltrace/ctf-ir/fields-internal.h index 9f2670d2..a75120f3 100644 --- a/include/babeltrace/ctf-writer/event-fields-internal.h +++ b/include/babeltrace/ctf-ir/fields-internal.h @@ -1,10 +1,10 @@ -#ifndef BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H -#define BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H +#ifndef BABELTRACE_CTF_IR_FIELDS_INTERNAL_H +#define BABELTRACE_CTF_IR_FIELDS_INTERNAL_H /* - * BabelTrace - CTF Writer: Event Fields internal + * Babeltrace - CTF IR: Event Fields internal * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,16 +27,17 @@ * SOFTWARE. */ -#include #include +#include #include #include #include struct bt_ctf_field { - struct bt_ctf_ref ref_count; + struct bt_object base; struct bt_ctf_field_type *type; int payload_set; + int frozen; }; struct bt_ctf_field_integer { @@ -90,11 +91,19 @@ BT_HIDDEN int bt_ctf_field_structure_set_field(struct bt_ctf_field *structure, const char *name, struct bt_ctf_field *value); +/* Validate that the field's payload is set (returns 0 if set). */ BT_HIDDEN int bt_ctf_field_validate(struct bt_ctf_field *field); +/* Mark field payload as unset. */ +BT_HIDDEN +int bt_ctf_field_reset(struct bt_ctf_field *field); + BT_HIDDEN int bt_ctf_field_serialize(struct bt_ctf_field *field, struct ctf_stream_pos *pos); -#endif /* BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H */ +BT_HIDDEN +void bt_ctf_field_freeze(struct bt_ctf_field *field); + +#endif /* BABELTRACE_CTF_IR_FIELDS_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/fields.h b/include/babeltrace/ctf-ir/fields.h new file mode 100644 index 00000000..cbed745a --- /dev/null +++ b/include/babeltrace/ctf-ir/fields.h @@ -0,0 +1,467 @@ +#ifndef BABELTRACE_CTF_IR_FIELDS_H +#define BABELTRACE_CTF_IR_FIELDS_H + +/* + * Babeltrace - CTF IR: Event Fields + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field; +struct bt_ctf_field_type; + +/* + * bt_ctf_field_create: create an instance of a field. + * + * Allocate a new field of the type described by the bt_ctf_field_type + * structure.The creation of a field sets its reference count to 1. + * + * @param type Field type to be instanciated. + * + * Returns an allocated field on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_create( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_structure_get_field: get a structure's field. + * + * Get the structure's field corresponding to the provided field name. + * bt_ctf_field_put() must be called on the returned value. + * + * @param structure Structure field instance. + * @param name Name of the field in the provided structure. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_structure_get_field( + struct bt_ctf_field *structure, const char *name); + +/* + * bt_ctf_field_structure_get_field_by_index: get a structure's field by index. + * + * Get the structure's field corresponding to the provided field name. + * bt_ctf_field_put() must be called on the returned value. + * The indexes are the same as those provided for bt_ctf_field_type_structure. + * + * @param structure Structure field instance. + * @param index Index of the field in the provided structure. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index( + struct bt_ctf_field *structure, int index); + +/* + * bt_ctf_field_array_get_field: get an array's field at position "index". + * + * Return the array's field at position "index". bt_ctf_field_put() must be + * called on the returned value. + * + * @param array Array field instance. + * @param index Position of the array's desired element. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_array_get_field( + struct bt_ctf_field *array, uint64_t index); + +/* + * bt_ctf_field_sequence_get_length: get a sequence's length. + * + * Get the sequence's length field. + * + * @param sequence Sequence field instance. + * + * Returns a field instance on success, NULL if a length was never set. + */ +extern struct bt_ctf_field *bt_ctf_field_sequence_get_length( + struct bt_ctf_field *sequence); + +/* + * bt_ctf_field_sequence_set_length: set a sequence's length. + * + * Set the sequence's length field. + * + * @param sequence Sequence field instance. + * @param length_field Unsigned integer field instance indicating the + * sequence's length. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_sequence_set_length(struct bt_ctf_field *sequence, + struct bt_ctf_field *length_field); + +/* + * bt_ctf_field_sequence_get_field: get a sequence's field at position "index". + * + * Return the sequence's field at position "index". The sequence's length must + * have been set prior to calling this function using + * bt_ctf_field_sequence_set_length(). + * bt_ctf_field_put() must be called on the returned value. + * + * @param array Sequence field instance. + * @param index Position of the sequence's desired element. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_sequence_get_field( + struct bt_ctf_field *sequence, uint64_t index); + +/* + * bt_ctf_field_variant_get_field: get a variant's selected field. + * + * Return the variant's selected field. The "tag" field is the selector enum + * field. bt_ctf_field_put() must be called on the returned value. + * + * @param variant Variant field instance. + * @param tag Selector enumeration field. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_variant_get_field( + struct bt_ctf_field *variant, struct bt_ctf_field *tag); + +/* + * bt_ctf_field_variant_get_current_field: get the current selected field of a + * variant. + * + * Return the variant's current selected field. This function, unlike + * bt_ctf_field_variant_get_field(), does not create any field; it + * returns NULL if there's no current selected field yet. + * + * @param variant Variant field instance. + * + * Returns a field instance on success, NULL on error or when there's no + * current selected field. + */ +extern struct bt_ctf_field *bt_ctf_field_variant_get_current_field( + struct bt_ctf_field *variant); + +/* + * bt_ctf_field_enumeration_get_container: get an enumeration field's container. + * + * Return the enumeration's underlying container field (an integer). + * bt_ctf_field_put() must be called on the returned value. + * + * @param enumeration Enumeration field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_enumeration_get_container( + struct bt_ctf_field *enumeration); + +/* + * bt_ctf_field_enumeration_get_mapping_name: get an enumeration field's mapping + * name. + * + * Return the enumeration's underlying container field (an integer). + * bt_ctf_field_put() must be called on the returned value. + * + * @param enumeration Enumeration field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern const char *bt_ctf_field_enumeration_get_mapping_name( + struct bt_ctf_field *enumeration); + +/* + * bt_ctf_field_signed_integer_get_value: get a signed integer field's value + * + * Get a signed integer field's value. + * + * @param integer Signed integer field instance. + * @param value Pointer to a signed integer where the value will be stored. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_signed_integer_get_value(struct bt_ctf_field *integer, + int64_t *value); + +/* + * bt_ctf_field_signed_integer_set_value: set a signed integer field's value + * + * Set a signed integer field's value. The value is checked to make sure it + * can be stored in the underlying field. + * + * @param integer Signed integer field instance. + * @param value Signed integer field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *integer, + int64_t value); + +/* + * bt_ctf_field_unsigned_integer_get_value: get unsigned integer field's value + * + * Get an unsigned integer field's value. + * + * @param integer Unsigned integer field instance. + * @param value Pointer to an unsigned integer where the value will be stored. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_unsigned_integer_get_value(struct bt_ctf_field *integer, + uint64_t *value); + +/* + * bt_ctf_field_unsigned_integer_set_value: set unsigned integer field's value + * + * Set an unsigned integer field's value. The value is checked to make sure it + * can be stored in the underlying field. + * + * @param integer Unsigned integer field instance. + * @param value Unsigned integer field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *integer, + uint64_t value); + +/* + * bt_ctf_field_floating_point_get_value: get a floating point field's value + * + * Get a floating point field's value. + * + * @param floating_point Floating point field instance. + * @param value Pointer to a double where the value will be stored. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_floating_point_get_value( + struct bt_ctf_field *floating_point, double *value); + +/* + * bt_ctf_field_floating_point_set_value: set a floating point field's value + * + * Set a floating point field's value. The underlying type may not support the + * double's full precision. + * + * @param floating_point Floating point field instance. + * @param value Floating point field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_floating_point_set_value( + struct bt_ctf_field *floating_point, + double value); + +/* + * bt_ctf_field_string_get_value: get a string field's value + * + * Get a string field's value. + * + * @param string_field String field instance. + * + * Returns the string's value, NULL if unset. + */ +extern const char *bt_ctf_field_string_get_value( + struct bt_ctf_field *string_field); + +/* + * bt_ctf_field_string_set_value: set a string field's value + * + * Set a string field's value. + * + * @param string_field String field instance. + * @param value String field value (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_string_set_value(struct bt_ctf_field *string_field, + const char *value); + +/* + * bt_ctf_field_string_append: append a string to a string field's + * current value. + * + * Append a string to the current value of a string field. If the string + * field was never set using bt_ctf_field_string_set_value(), it is + * first set to an empty string, and then the concatenation happens. + * + * @param string_field String field instance. + * @param value String to append to the current string field's value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_string_append(struct bt_ctf_field *string_field, + const char *value); + +/* + * bt_ctf_field_string_append_len: append a string of a given length to + * a string field's current value. + * + * Append a string of a given length to the current value of a string + * field. If the string field was never set using + * bt_ctf_field_string_set_value(), it is first set to an empty string, + * and then the concatenation happens. + * + * If a null byte is encountered before the given length, only the + * substring before the first null byte is appended. + * + * @param string_field String field instance. + * @param value String to append to the current string field's value. + * @param length Length of string value to append. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_string_append_len( + struct bt_ctf_field *string_field, const char *value, + unsigned int length); + +/* + * bt_ctf_field_get_type: get a field's type + * + * @param field Field intance. + * + * Returns a field type instance on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_get_type( + struct bt_ctf_field *field); + +/* + * bt_ctf_field_get_type_id: get a field's ctf_type_id. + * + * This is a helper function which avoids a call to + * bt_ctf_field_get_type(), followed by a call to + * bt_ctf_field_type_get_type_id(), followed by a call to + * bt_ctf_put(). + * + * @param field Field instance. + * + * Returns the field's ctf_type_id, CTF_TYPE_UNKNOWN on error. + */ +extern enum bt_ctf_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_integer: returns whether or not a given field + * is an integer type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is an integer type, 0 otherwise. + */ +extern int bt_ctf_field_is_integer(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_floating_point: returns whether or not a given field + * is a floating point number type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is a floating point number type, 0 otherwise. + */ +extern int bt_ctf_field_is_floating_point(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_enumeration: returns whether or not a given field + * is an enumeration type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is an enumeration type, 0 otherwise. + */ +extern int bt_ctf_field_is_enumeration(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_string: returns whether or not a given field + * is a string type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is a string type, 0 otherwise. + */ +extern int bt_ctf_field_is_string(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_structure: returns whether or not a given field + * is a structure type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is a structure type, 0 otherwise. + */ +extern int bt_ctf_field_is_structure(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_array: returns whether or not a given field + * is an array type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is an array type, 0 otherwise. + */ +extern int bt_ctf_field_is_array(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_sequence: returns whether or not a given field + * is a sequence type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is a sequence type, 0 otherwise. + */ +extern int bt_ctf_field_is_sequence(struct bt_ctf_field *field); + +/* + * bt_ctf_field_is_variant: returns whether or not a given field + * is a variant type. + * + * @param field Field instance. + * + * Returns 1 if the field instance is a variant type, 0 otherwise. + */ +extern int bt_ctf_field_is_variant(struct bt_ctf_field *field); + +/* + * bt_ctf_field_copy: get a field's deep copy. + * + * Get a field's deep copy. The created field copy shares the source's + * associated field types. + * + * On success, the returned copy has its reference count set to 1. + * + * @param field Field instance. + * + * Returns the field copy on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_FIELDS_H */ diff --git a/include/babeltrace/ctf-ir/metadata.h b/include/babeltrace/ctf-ir/metadata.h index 07706bb1..4d291c75 100644 --- a/include/babeltrace/ctf-ir/metadata.h +++ b/include/babeltrace/ctf-ir/metadata.h @@ -111,10 +111,14 @@ struct ctf_clock { /* * The offset from Epoch is: offset_s + (offset * (1/freq)) * Coarse clock offset from Epoch (in seconds). + * It can be negative. */ - uint64_t offset_s; - /* Fine clock offset from Epoch, in (1/freq) units. */ - uint64_t offset; + int64_t offset_s; + /* + * Fine clock offset from Epoch, in (1/freq) units. + * It can be negative. + */ + int64_t offset; int absolute; enum { /* Fields populated mask */ diff --git a/include/babeltrace/ctf-ir/packet-internal.h b/include/babeltrace/ctf-ir/packet-internal.h new file mode 100644 index 00000000..275524ba --- /dev/null +++ b/include/babeltrace/ctf-ir/packet-internal.h @@ -0,0 +1,44 @@ +#ifndef BABELTRACE_CTF_IR_PACKET_INTERNAL_H +#define BABELTRACE_CTF_IR_PACKET_INTERNAL_H + +/* + * Babeltrace - CTF IR: Stream packet internal + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +struct bt_ctf_packet { + struct bt_object base; + struct bt_ctf_field *header; + struct bt_ctf_field *context; + struct bt_ctf_stream *stream; + int frozen; +}; + +BT_HIDDEN +void bt_ctf_packet_freeze(struct bt_ctf_packet *packet); + +#endif /* BABELTRACE_CTF_IR_PACKET_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/packet.h b/include/babeltrace/ctf-ir/packet.h new file mode 100644 index 00000000..40aaab15 --- /dev/null +++ b/include/babeltrace/ctf-ir/packet.h @@ -0,0 +1,62 @@ +#ifndef BABELTRACE_CTF_IR_PACKET_H +#define BABELTRACE_CTF_IR_PACKET_H + +/* + * BabelTrace - CTF IR: Stream packet + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_stream; +struct bt_ctf_packet; + +extern struct bt_ctf_packet *bt_ctf_packet_create( + struct bt_ctf_stream *stream); + +extern struct bt_ctf_stream *bt_ctf_packet_get_stream( + struct bt_ctf_packet *packet); + +extern struct bt_ctf_field *bt_ctf_packet_get_header( + struct bt_ctf_packet *packet); + +extern int bt_ctf_packet_set_header( + struct bt_ctf_packet *packet, struct bt_ctf_field *header); + +extern struct bt_ctf_field *bt_ctf_packet_get_context( + struct bt_ctf_packet *context); + +extern int bt_ctf_packet_set_context( + struct bt_ctf_packet *packet, struct bt_ctf_field *context); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_PACKET_H */ diff --git a/include/babeltrace/ctf-ir/resolve-internal.h b/include/babeltrace/ctf-ir/resolve-internal.h new file mode 100644 index 00000000..5479d44f --- /dev/null +++ b/include/babeltrace/ctf-ir/resolve-internal.h @@ -0,0 +1,72 @@ +#ifndef BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H +#define BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H + +/* + * Babeltrace - CTF IR: Type resolving internal + * + * Copyright 2015 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * Authors: Jérémie Galarneau + * Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +enum bt_ctf_resolve_flag { + BT_CTF_RESOLVE_FLAG_PACKET_HEADER = 0x01, + BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT = 0x02, + BT_CTF_RESOLVE_FLAG_EVENT_HEADER = 0x04, + BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX = 0x08, + BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT = 0x10, + BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD = 0x20, +}; + +/* + * Resolves CTF IR field types: recursively locates the tag and length + * field types of resp. variant and sequence field types. + * + * All `*_type` parameters may be resolved, and may as well serve as + * resolving targets. + * + * Resolving is performed based on the flags in `flags`. + * + * It is expected that, amongst all the provided types, no common + * references to sequence variant field types exist. In other words, + * this function does not copy field types. + * + * All parameters are owned by the caller. + */ +BT_HIDDEN +int bt_ctf_resolve_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *event_payload_type, + enum bt_ctf_resolve_flag flags); + +#endif /* BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H */ diff --git a/include/babeltrace/ctf-writer/stream-internal.h b/include/babeltrace/ctf-ir/stream-class-internal.h similarity index 60% rename from include/babeltrace/ctf-writer/stream-internal.h rename to include/babeltrace/ctf-ir/stream-class-internal.h index 57dd992d..1bd1ea18 100644 --- a/include/babeltrace/ctf-writer/stream-internal.h +++ b/include/babeltrace/ctf-ir/stream-class-internal.h @@ -1,10 +1,10 @@ -#ifndef BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H -#define BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H +#ifndef BABELTRACE_CTF_IR_STREAM_CLASS_INTERNAL_H +#define BABELTRACE_CTF_IR_STREAM_CLASS_INTERNAL_H /* - * BabelTrace - CTF Writer: Stream internal + * BabelTrace - CTF IR: Stream class internal * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,18 +27,18 @@ * SOFTWARE. */ -#include #include #include #include +#include +#include #include #include +#include #include -typedef void(*flush_func)(struct bt_ctf_stream *, void *); - struct bt_ctf_stream_class { - struct bt_ctf_ref ref_count; + struct bt_object base; GString *name; struct bt_ctf_clock *clock; GPtrArray *event_classes; /* Array of pointers to bt_ctf_event_class */ @@ -46,56 +46,37 @@ struct bt_ctf_stream_class { uint32_t id; uint32_t next_event_id; uint32_t next_stream_id; - struct bt_ctf_field_type *event_header_type; - struct bt_ctf_field *event_header; struct bt_ctf_field_type *packet_context_type; - struct bt_ctf_field *packet_context; + struct bt_ctf_field_type *event_header_type; struct bt_ctf_field_type *event_context_type; - struct bt_ctf_field *event_context; int frozen; -}; + int byte_order; -struct flush_callback { - flush_func func; - void *data; -}; - -struct bt_ctf_stream { - struct bt_ctf_ref ref_count; - uint32_t id; - struct bt_ctf_stream_class *stream_class; - struct flush_callback flush; - /* Array of pointers to bt_ctf_event for the current packet */ - GPtrArray *events; - struct ctf_stream_pos pos; - unsigned int flushed_packet_count; - uint64_t events_discarded; + /* + * This flag indicates if the stream class is valid. A valid + * stream class is _always_ frozen. + */ + int valid; }; BT_HIDDEN void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class); -BT_HIDDEN -int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, - uint32_t id); - BT_HIDDEN int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, struct metadata_context *context); BT_HIDDEN -int bt_ctf_stream_class_set_byte_order(struct bt_ctf_stream_class *stream_class, - enum bt_ctf_byte_order byte_order); +void bt_ctf_stream_class_set_byte_order( + struct bt_ctf_stream_class *stream_class, int byte_order); +/* Set stream_class id without checking if the stream class is frozen */ BT_HIDDEN -struct bt_ctf_stream *bt_ctf_stream_create( - struct bt_ctf_stream_class *stream_class); - -BT_HIDDEN -int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream, - flush_func callback, void *data); +int _bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, + uint32_t id); BT_HIDDEN -int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd); +int bt_ctf_stream_class_set_id_no_check( + struct bt_ctf_stream_class *stream_class, uint32_t id); -#endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */ +#endif /* BABELTRACE_CTF_IR_STREAM_CLASS_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/stream-class.h b/include/babeltrace/ctf-ir/stream-class.h new file mode 100644 index 00000000..433fc563 --- /dev/null +++ b/include/babeltrace/ctf-ir/stream-class.h @@ -0,0 +1,278 @@ +#ifndef BABELTRACE_CTF_IR_STREAM_CLASS_H +#define BABELTRACE_CTF_IR_STREAM_CLASS_H + +/* + * BabelTrace - CTF IR: Stream Class + * + * Copyright 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_stream_class; +struct bt_ctf_clock; + +/* + * bt_ctf_stream_class_create: create a stream class. + * + * Allocate a new stream class of the given name. The creation of an event class + * sets its reference count to 1. + * + * A stream class' packet context is a structure initialized with the following + * fields: + * - uint64_t timestamp_begin + * - uint64_t timestamp_end + * - uint64_t content_size + * - uint64_t packet_size + * - uint64_t events_discarded + * + * A stream class's event header is a structure initialized the following + * fields: + * - uint32_t id + * - uint64_t timestamp + * + * @param name Stream name, NULL to create an unnamed stream class. + * + * Returns an allocated stream class on success, NULL on error. + */ +extern struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name); + +/* + * bt_ctf_stream_class_get_trace: Get a stream class' associated trace. + * + * @param stream_class Stream class. + * + * Returns the stream class' associated trace, NULL on error. + */ +extern struct bt_ctf_trace *bt_ctf_stream_class_get_trace( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_get_name: Get a stream class' name. + * + * @param stream_class Stream class. + * + * Returns the stream class' name, NULL on error. + */ +extern const char *bt_ctf_stream_class_get_name( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_name: Set a stream class' name. + * + * @param stream_class Stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_name( + struct bt_ctf_stream_class *stream_class, const char *name); + +/* + * bt_ctf_stream_class_get_clock: get the clock associated with a stream class. + * + * @param stream_class Stream class. + * + * Returns a clock instance, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_stream_class_get_clock( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_get_id: Get a stream class' id. + * + * @param stream_class Stream class. + * + * Returns the stream class' id, a negative value on error. + */ +extern int64_t bt_ctf_stream_class_get_id( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_id: Set a stream class' id. + * + * Set a stream class' id. Must be unique trace-wise. + * Note that stream classes are assigned a unique id when a stream instance + * is created for the first time from a trace or writer. + * + * @param stream_class Stream class. + * @param id Stream class id. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_id( + struct bt_ctf_stream_class *stream_class, uint32_t id); + +/* + * bt_ctf_stream_class_set_clock: assign a clock to a stream class. + * + * Add an event class to a stream class. New events can be added even after a + * stream has beem instanciated and events have been appended. However, a stream + * will not accept events of a class that has not been registered beforehand. + * The stream class will share the ownership of "event_class" by incrementing + * its reference count. + * + * Note that an event class may only be added to one stream class. It + * also becomes immutable. + * + * @param stream_class Stream class. + * @param event_class Event class to add to the provided stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_add_event_class( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_stream_class_get_event_class_count: Get a stream class' event class + * count. + * + * @param stream_class Stream class. + * + * Returns the stream class' event count, a negative value on error. + */ +extern int bt_ctf_stream_class_get_event_class_count( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_get_event_class: Get stream class event class by index. + * + * @param stream_class Stream class. + * @param index Index of field. + * + * Returns event class, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class( + struct bt_ctf_stream_class *stream_class, int index); + +/* + * bt_ctf_stream_class_get_event_class_by_name: Get stream class event class by + * name. + * + * @param stream_class Stream class. + * @param name Event name. + * + * Returns event class, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_name( + struct bt_ctf_stream_class *stream_class, const char *name); + +/* + * bt_ctf_stream_class_get_event_class_by_name: Get stream class event class by + * ID. + * + * @param stream_class Stream class. + * @param id Event class ID. + * + * Returns event class, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id( + struct bt_ctf_stream_class *stream_class, uint32_t id); + +/* + * bt_ctf_stream_class_get_packet_context_type: get the stream class' packet + * context type. + * + * @param stream_class Stream class. + * + * Returns the packet context's type (a structure), NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_packet_context_type: set the stream class' packet + * context type. + * + * @param stream_class Stream class. + * @param packet_context_type Packet context type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_packet_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type); + +/* + * bt_ctf_stream_class_get_event_header_type: get the stream class' + * event header type. + * + * @param stream_class Stream class. + * + * Returns the stream event header's type (a structure), NULL on error. + */ +extern struct bt_ctf_field_type * +bt_ctf_stream_class_get_event_header_type( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_event_header_type: set the stream class' + * event header type. + * + * @param stream_class Stream class. + * @param event_header_type Event header type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_event_header_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_header_type); + +/* + * bt_ctf_stream_class_get_event_context_type: get the stream class' + * event context type. + * + * @param stream_class Stream class. + * + * Returns the stream event context's type (a structure), NULL on error. + */ +extern struct bt_ctf_field_type * +bt_ctf_stream_class_get_event_context_type( + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_class_set_event_context_type: set the stream class' + * event context type. + * + * @param stream_class Stream class. + * @param event_context_type Event context type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_event_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_context_type); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_STREAM_CLASS_H */ diff --git a/include/babeltrace/ctf-writer/clock-internal.h b/include/babeltrace/ctf-ir/stream-internal.h similarity index 55% rename from include/babeltrace/ctf-writer/clock-internal.h rename to include/babeltrace/ctf-ir/stream-internal.h index c60e5c08..dc392f4a 100644 --- a/include/babeltrace/ctf-writer/clock-internal.h +++ b/include/babeltrace/ctf-ir/stream-internal.h @@ -1,10 +1,10 @@ -#ifndef BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H -#define BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H +#ifndef BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H +#define BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H /* - * BabelTrace - CTF Writer: Clock internal + * BabelTrace - CTF Writer: Stream internal * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,39 +27,34 @@ * SOFTWARE. */ -#include +#include +#include #include -#include +#include +#include #include +#include #include -#include -struct bt_ctf_clock { - struct bt_ctf_ref ref_count; +struct bt_ctf_stream { + struct bt_object base; + uint32_t id; + struct bt_ctf_stream_class *stream_class; + /* Array of pointers to bt_ctf_event for the current packet */ + GPtrArray *events; + struct ctf_stream_pos pos; + unsigned int flushed_packet_count; GString *name; - GString *description; - uint64_t frequency; - uint64_t precision; - uint64_t offset_s; /* Offset in seconds */ - uint64_t offset; /* Offset in ticks */ - uint64_t time; /* Current clock value */ - uuid_t uuid; - int absolute; - /* - * A clock's properties can't be modified once it is added to a stream - * class. - */ - int frozen; + struct bt_ctf_field *packet_header; + struct bt_ctf_field *packet_context; + GHashTable *clock_values; /* Maps clock addresses to (uint64_t *) */ }; BT_HIDDEN -void bt_ctf_clock_freeze(struct bt_ctf_clock *clock); +int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd); BT_HIDDEN -void bt_ctf_clock_serialize(struct bt_ctf_clock *clock, - struct metadata_context *context); +void bt_ctf_stream_update_clock_value(struct bt_ctf_stream *stream, + struct bt_ctf_field *value_field); -BT_HIDDEN -uint64_t bt_ctf_clock_get_time(struct bt_ctf_clock *clock); - -#endif /* BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H */ +#endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/stream.h b/include/babeltrace/ctf-ir/stream.h new file mode 100644 index 00000000..a08e327f --- /dev/null +++ b/include/babeltrace/ctf-ir/stream.h @@ -0,0 +1,63 @@ +#ifndef BABELTRACE_CTF_IR_STREAM_H +#define BABELTRACE_CTF_IR_STREAM_H + +/* + * BabelTrace - CTF IR: Stream + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event; +struct bt_ctf_stream; + +extern struct bt_ctf_stream *bt_ctf_stream_create( + struct bt_ctf_stream_class *stream_class, + const char *name); + +extern const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream); + +/* + * bt_ctf_stream_get_stream_class: get a stream's class. + * + * @param stream Stream instance. + * + * Returns the stream's class, NULL on error. + */ +extern struct bt_ctf_stream_class *bt_ctf_stream_get_class( + struct bt_ctf_stream *stream); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_STREAM_H */ diff --git a/include/babeltrace/ctf-ir/trace-internal.h b/include/babeltrace/ctf-ir/trace-internal.h new file mode 100644 index 00000000..f9091425 --- /dev/null +++ b/include/babeltrace/ctf-ir/trace-internal.h @@ -0,0 +1,82 @@ +#ifndef BABELTRACE_CTF_IR_TRACE_INTERNAL_H +#define BABELTRACE_CTF_IR_TRACE_INTERNAL_H + +/* + * BabelTrace - CTF IR: Trace internal + * + * Copyright 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum field_type_alias { + FIELD_TYPE_ALIAS_UINT5_T = 0, + FIELD_TYPE_ALIAS_UINT8_T, + FIELD_TYPE_ALIAS_UINT16_T, + FIELD_TYPE_ALIAS_UINT27_T, + FIELD_TYPE_ALIAS_UINT32_T, + FIELD_TYPE_ALIAS_UINT64_T, + NR_FIELD_TYPE_ALIAS, +}; + +struct bt_ctf_trace { + struct bt_object base; + int frozen; + uuid_t uuid; + int byte_order; /* A value defined in Babeltrace's "endian.h" */ + struct bt_value *environment; + GPtrArray *clocks; /* Array of pointers to bt_ctf_clock */ + GPtrArray *stream_classes; /* Array of ptrs to bt_ctf_stream_class */ + GPtrArray *streams; /* Array of ptrs to bt_ctf_stream */ + struct bt_ctf_field_type *packet_header_type; + uint64_t next_stream_id; + int is_created_by_writer; + + /* + * This flag indicates if the trace is valid. A valid + * trace is _always_ frozen. + */ + int valid; +}; + +struct metadata_context { + GString *string; + GString *field_name; + unsigned int current_indentation_level; +}; + +BT_HIDDEN +const char *get_byte_order_string(int byte_order); + +BT_HIDDEN +struct bt_ctf_field_type *get_field_type(enum field_type_alias alias); + +#endif /* BABELTRACE_CTF_IR_TRACE_INTERNAL_H */ diff --git a/include/babeltrace/ctf-ir/trace.h b/include/babeltrace/ctf-ir/trace.h new file mode 100644 index 00000000..ee740039 --- /dev/null +++ b/include/babeltrace/ctf-ir/trace.h @@ -0,0 +1,345 @@ +#ifndef BABELTRACE_CTF_IR_TRACE_H +#define BABELTRACE_CTF_IR_TRACE_H + +/* + * BabelTrace - CTF IR: Trace + * + * Copyright 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_trace; +struct bt_ctf_stream; +struct bt_ctf_stream_class; +struct bt_ctf_clock; + +/* + * bt_ctf_trace_create: create a trace instance. + * + * Allocate a new trace. + * + * A trace's default packet header is a structure initialized with the following + * fields: + * - uint32_t magic + * - uint8_t uuid[16] + * - uint32_t stream_id + * + * Returns a new trace on success, NULL on error. + */ +extern struct bt_ctf_trace *bt_ctf_trace_create(void); + +/* + * bt_ctf_trace_set_environment_field: sets an environment field to the + * trace. + * + * Sets an environment field to the trace. The name parameter is + * copied, whereas the value parameter's reference count is incremented + * (if the function succeeds). + * + * If a value exists in the environment for the specified name, it is + * replaced by the new value. + * + * The value parameter _must_ be either an integer value object or a + * string value object. Other object types are not supported. + * + * @param trace Trace instance. + * @param name Name of the environment field (will be copied). + * @param value Value of the environment field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_set_environment_field( + struct bt_ctf_trace *trace, const char *name, + struct bt_value *value); + +/* + * bt_ctf_trace_set_environment_field_string: sets a string environment + * field to the trace. + * + * Sets a string environment field to the trace. This is a helper + * function which corresponds to calling + * bt_ctf_trace_set_environment_field() with a string object. + * + * @param trace Trace instance. + * @param name Name of the environment field (will be copied). + * @param value Value of the environment field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_set_environment_field_string( + struct bt_ctf_trace *trace, const char *name, + const char *value); + +/* + * bt_ctf_trace_set_environment_field_integer: sets an integer environment + * field to the trace. + * + * Sets an integer environment field to the trace. This is a helper + * function which corresponds to calling + * bt_ctf_trace_set_environment_field() with an integer object. + * + * @param trace Trace instance. + * @param name Name of the environment field (will be copied). + * @param value Value of the environment field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_set_environment_field_integer( + struct bt_ctf_trace *trace, const char *name, + int64_t value); + +/* + * bt_ctf_trace_get_environment_field_count: get environment field count. + * + * Get the trace's environment field count. + * + * @param trace Trace instance. + * + * Returns the environment field count, a negative value on error. + */ +extern int bt_ctf_trace_get_environment_field_count( + struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_get_environment_field_name: get environment field name. + * + * Get an environment field's name. The string's ownership is not + * transferred to the caller. The string data is valid as long as + * this trace's environment is not modified. + * + * @param trace Trace instance. + * @param index Index of the environment field. + * + * Returns the environment field's name, NULL on error. + */ +extern const char * +bt_ctf_trace_get_environment_field_name(struct bt_ctf_trace *trace, + int index); + +/* + * bt_ctf_trace_get_environment_field_value: get environment + * field value (an object). + * + * Get an environment field's value (an object). The returned object's + * reference count is incremented. When done with the object, the caller + * must call bt_value_put() on it. + * + * @param trace Trace instance. + * @param index Index of the environment field. + * + * Returns the environment field's object value, NULL on error. + */ +extern struct bt_value * +bt_ctf_trace_get_environment_field_value(struct bt_ctf_trace *trace, + int index); + +/* + * bt_ctf_trace_get_environment_field_value_by_name: get environment + * field value (an object) by name. + * + * Get an environment field's value (an object) by its field name. The + * returned object's reference count is incremented. When done with the + * object, the caller must call bt_value_put() on it. + * + * @param trace Trace instance. + * @param name Environment field's name + * + * Returns the environment field's object value, NULL on error. + */ +extern struct bt_value * +bt_ctf_trace_get_environment_field_value_by_name(struct bt_ctf_trace *trace, + const char *name); + +/* + * bt_ctf_trace_add_clock: add a clock to the trace. + * + * Add a clock to the trace. Clocks assigned to stream classes must be + * added to the trace beforehand. + * + * @param trace Trace instance. + * @param clock Clock to add to the trace. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_add_clock(struct bt_ctf_trace *trace, + struct bt_ctf_clock *clock); + +/* + * bt_ctf_trace_get_clock_count: get the number of clocks + * associated with the trace. + * + * @param trace Trace instance. + * + * Returns the clock count on success, a negative value on error. + */ +extern int bt_ctf_trace_get_clock_count(struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_get_clock: get a trace's clock at index. + * + * @param trace Trace instance. + * @param index Index of the clock in the given trace. + * + * Return a clock instance on success, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_trace_get_clock( + struct bt_ctf_trace *trace, int index); + +/* + * bt_ctf_trace_add_stream_class: add a stream_class to the trace. + * + * Add a stream class to the trace. + * + * @param trace Trace instance. + * @param stream_class Stream class to add to the trace. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_trace_get_stream_class_count: get the number of stream classes + * associated with the trace. + * + * @param trace Trace instance. + * + * Returns the stream class count on success, a negative value on error. + */ +extern int bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_get_stream_class: get a trace's stream class at index. + * + * @param trace Trace instance. + * @param index Index of the stream class in the given trace. + * + * Return a stream class on success, NULL on error. + */ +extern struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class( + struct bt_ctf_trace *trace, int index); + +/* + * bt_ctf_trace_get_stream_class_by_id: get a trace's stream class by ID. + * + * @param trace Trace instance. + * @param index ID of the stream class in the given trace. + * + * Return a stream class on success, NULL on error. + */ +extern struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id( + struct bt_ctf_trace *trace, uint32_t id); + +/* + * bt_ctf_trace_get_clock_by_name: get a trace's clock by name + * + * @param trace Trace instance. + * @param name Name of the clock in the given trace. + * + * Return a clock instance on success, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_trace_get_clock_by_name( + struct bt_ctf_trace *trace, const char *name); + +/* + * bt_ctf_trace_get_metadata_string: get metadata string. + * + * Get the trace's TSDL metadata. The caller assumes the ownership of the + * returned string. + * + * @param trace Trace instance. + * + * Returns the metadata string on success, NULL on error. + */ +extern char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_get_byte_order: get a trace's byte order. + * + * Get the trace's byte order. + * + * @param trace Trace instance. + * + * Returns the trace's endianness, BT_CTF_BYTE_ORDER_UNKNOWN on error. + */ +extern enum bt_ctf_byte_order bt_ctf_trace_get_byte_order( + struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_set_byte_order: set a trace's byte order. + * + * Set the trace's byte order. Defaults to the current host's endianness. + * + * @param trace Trace instance. + * @param byte_order Trace's byte order. + * + * Returns 0 on success, a negative value on error. + * + * Note: byte_order must not be BT_CTF_BYTE_ORDER_NATIVE since, according + * to the CTF specification, is defined as "the byte order described in the + * trace description". + */ +extern int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace, + enum bt_ctf_byte_order byte_order); + +/* + * bt_ctf_trace_get_packet_header_type: get a trace's packet header type. + * + * Get the trace's packet header type. + * + * @param trace Trace instance. + * + * Returns the trace's packet header type (a structure) on success, NULL on + * error. + */ +extern struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type( + struct bt_ctf_trace *trace); + +/* + * bt_ctf_trace_set_packet_header_type: set a trace's packet header type. + * + * Set the trace's packet header type. + * + * @param trace Trace instance. + * @param packet_header_type Packet header field type (must be a structure). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace, + struct bt_ctf_field_type *packet_header_type); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_TRACE_H */ diff --git a/include/babeltrace/ctf-ir/utils.h b/include/babeltrace/ctf-ir/utils.h new file mode 100644 index 00000000..d661ed88 --- /dev/null +++ b/include/babeltrace/ctf-ir/utils.h @@ -0,0 +1,56 @@ +#ifndef BABELTRACE_CTF_IR_UTILS_H +#define BABELTRACE_CTF_IR_UTILS_H + +/* + * BabelTrace - CTF IR: Utilities + * + * Copyright 2015 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * bt_ctf_validate_identifier: validate an identifier against the CTF spec. + * + * Validate that an identifier meets the CTF specification's restrictions on + * identifiers. An identifier will be rejected if it is a keyword defined + * in the CTF specification or if it does not meet any other requirement imposed + * on identifiers. + * + * Note that this will not check whether or not the identifier clashes with + * identifiers used in a given trace. + * + * Returns 0 if the identifier is valid, a negative value on error. + */ +extern int bt_ctf_validate_identifier(const char *identifier); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_IR_UTILS_H */ diff --git a/include/babeltrace/ctf-ir/validation-internal.h b/include/babeltrace/ctf-ir/validation-internal.h new file mode 100644 index 00000000..e5636377 --- /dev/null +++ b/include/babeltrace/ctf-ir/validation-internal.h @@ -0,0 +1,124 @@ +#ifndef BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H +#define BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H + +/* + * Babeltrace - CTF IR: Validation of trace, stream class, and event class + * + * Copyright 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +enum bt_ctf_validation_flag { + BT_CTF_VALIDATION_FLAG_TRACE = 1, + BT_CTF_VALIDATION_FLAG_STREAM = 2, + BT_CTF_VALIDATION_FLAG_EVENT = 4, +}; + +/* + * Validation output structure. + * + * This is where the results of the validation function go. The field + * types are the validated ones which should replace the original field + * types of a trace, a stream class, and an event class. + * + * `valid_flags` contains the results of the validation. + */ +struct bt_ctf_validation_output { + struct bt_ctf_field_type *packet_header_type; + struct bt_ctf_field_type *packet_context_type; + struct bt_ctf_field_type *event_header_type; + struct bt_ctf_field_type *stream_event_ctx_type; + struct bt_ctf_field_type *event_context_type; + struct bt_ctf_field_type *event_payload_type; + enum bt_ctf_validation_flag valid_flags; +}; + +/* + * This function resolves and validates the field types of an event + * class, a stream class, and a trace. Copies are created if needed + * and the resulting field types to use are placed in the `output` + * validation structure, which also contains the results of the + * validation. Copies can replace the original field types of a trace, + * a stream class, and an event class using + * bt_ctf_validation_replace_types(). + * + * The current known validity of the field types of the trace, + * stream class, and event class must be indicated with the + * `trace_valid`, `stream_class_valid`, and `event_class_valid` + * parameters. If a class is valid, its field types are not copied, + * validated, or resolved during this call. + * + * The validation flags `validate_flags` indicate which classes should + * have their field types validated. + * + * All parameters are owned by the caller. + */ +BT_HIDDEN +int bt_ctf_validate_class_types(struct bt_value *environment, + struct bt_ctf_field_type *packet_header_type, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type, + struct bt_ctf_field_type *stream_event_ctx_type, + struct bt_ctf_field_type *event_context_type, + struct bt_ctf_field_type *event_payload_type, + int trace_valid, int stream_class_valid, int event_class_valid, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag validate_flags); + +/* + * This function replaces the actual field types of a trace, a stream + * class, and an event class with the appropriate field types contained + * in a validation output structure. + * + * The replace flags `replace_flags` indicate which classes should have + * their field types replaced. + * + * Note that the field types that are not used in the validation output + * structure are still owned by it at the end of this call. + * bt_ctf_validation_output_put_types() should be called to clean the + * structure. + * + * All parameters are owned by the caller. + */ +BT_HIDDEN +void bt_ctf_validation_replace_types(struct bt_ctf_trace *trace, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag replace_flags); + +/* + * This function puts all the field types contained in a given + * validation output structure. + * + * `output` is owned by the caller and is not freed here. + */ +BT_HIDDEN +void bt_ctf_validation_output_put_types( + struct bt_ctf_validation_output *output); + +#endif /* BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H */ diff --git a/include/babeltrace/ctf-writer/clock.h b/include/babeltrace/ctf-writer/clock.h index 7cfc073f..1bacc34e 100644 --- a/include/babeltrace/ctf-writer/clock.h +++ b/include/babeltrace/ctf-writer/clock.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Clock * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,122 +30,36 @@ * http://www.efficios.com/ctf */ -#include +#include #ifdef __cplusplus extern "C" { #endif -struct bt_ctf_clock; - -/* - * bt_ctf_clock_create: create a clock. - * - * Allocate a new clock setting its reference count to 1. - * - * @param name Name of the clock (will be copied). - * - * Returns an allocated clock on success, NULL on error. - */ -extern struct bt_ctf_clock *bt_ctf_clock_create(const char *name); - -/* - * bt_ctf_clock_set_description: set a clock's description. - * - * Set the clock's description. The description appears in the clock's TSDL - * meta-data. - * - * @param clock Clock instance. - * @param desc Description of the clock. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, - const char *desc); - -/* - * bt_ctf_clock_set_frequency: set a clock's frequency. - * - * Set the clock's frequency (Hz). - * - * @param clock Clock instance. - * @param freq Clock's frequency in Hz, defaults to 1 000 000 000 Hz (1ns). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, - uint64_t freq); - -/* - * bt_ctf_clock_set_precision: set a clock's precision. - * - * Set the clock's precision. - * - * @param clock Clock instance. - * @param precision Clock's precision in clock ticks, defaults to 1. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, - uint64_t precision); - -/* - * bt_ctf_clock_set_offset_s: set a clock's offset in seconds. - * - * Set the clock's offset in seconds from POSIX.1 Epoch, 1970-01-01, - * defaults to 0. - * - * @param clock Clock instance. - * @param offset_s Clock's offset in seconds, defaults to 0. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, - uint64_t offset_s); - - -/* - * bt_ctf_clock_set_offset: set a clock's offset in ticks. - * - * Set the clock's offset in ticks from Epoch + offset_s. - * - * @param clock Clock instance. - * @param offset Clock's offset in ticks from Epoch + offset_s, defaults to 0. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, - uint64_t offset); - -/* - * bt_ctf_clock_set_is_absolute: set a clock's absolute attribute. - * - * A clock is absolute if the clock is a global reference across the trace's - * other clocks. - * - * @param clock Clock instance. - * @param is_absolute Clock's absolute attribute, defaults to FALSE. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, - int is_absolute); +extern int bt_ctf_clock_get_time(struct bt_ctf_clock *clock, int64_t *time); /* * bt_ctf_clock_set_time: set a clock's current time value. * * Set the current time in nanoseconds since the clock's origin (offset and - * offset_s attributes). The clock's value will be sampled as events are - * appended to a stream. + * offset_s attributes). Defaults to 0. * * Returns 0 on success, a negative value on error. */ -extern int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, uint64_t time); +extern int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, + int64_t time); + +extern uint64_t bt_ctf_clock_get_value(struct bt_ctf_clock *clock); + +extern int bt_ctf_clock_set_value(struct bt_ctf_clock *clock, + uint64_t value); /* * bt_ctf_clock_get and bt_ctf_clock_put: increment and decrement the * refcount of the clock * + * You may also use bt_ctf_get() and bt_ctf_put() with clock objects. + * * These functions ensure that the clock won't be destroyed when it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) has to be done to diff --git a/include/babeltrace/ctf-writer/event-fields.h b/include/babeltrace/ctf-writer/event-fields.h index 8d3190b4..ce13907a 100644 --- a/include/babeltrace/ctf-writer/event-fields.h +++ b/include/babeltrace/ctf-writer/event-fields.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Event Fields * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,174 +30,18 @@ * http://www.efficios.com/ctf */ -#include +#include #ifdef __cplusplus extern "C" { #endif -struct bt_ctf_event_class; -struct bt_ctf_event; -struct bt_ctf_field; -struct bt_ctf_field_type; - -/* - * bt_ctf_field_create: create an instance of a field. - * - * Allocate a new field of the type described by the bt_ctf_field_type - * structure.The creation of a field sets its reference count to 1. - * - * @param type Field type to be instanciated. - * - * Returns an allocated field on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_create( - struct bt_ctf_field_type *type); - -/* - * bt_ctf_field_structure_get_field: get a structure's field. - * - * Get the structure's field corresponding to the provided field name. - * bt_ctf_field_put() must be called on the returned value. - * - * @param structure Structure field instance. - * @param name Name of the field in the provided structure. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_structure_get_field( - struct bt_ctf_field *structure, const char *name); - -/* - * bt_ctf_field_array_get_field: get an array's field at position "index". - * - * Return the array's field at position "index". bt_ctf_field_put() must be - * called on the returned value. - * - * @param array Array field instance. - * @param index Position of the array's desired element. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_array_get_field( - struct bt_ctf_field *array, uint64_t index); - -/* - * bt_ctf_field_sequence_set_length: set a sequence's length. - * - * Set the sequence's length field. - * - * @param sequence Sequence field instance. - * @param length_field Integer field instance indicating the sequence's length. - * - * Returns a field instance on success, NULL on error. - */ -extern int bt_ctf_field_sequence_set_length(struct bt_ctf_field *sequence, - struct bt_ctf_field *length_field); - -/* - * bt_ctf_field_sequence_get_field: get a sequence's field at position "index". - * - * Return the sequence's field at position "index". The sequence's length must - * have been set prior to calling this function using - * bt_ctf_field_sequence_set_length(). - * bt_ctf_field_put() must be called on the returned value. - * - * @param array Sequence field instance. - * @param index Position of the sequence's desired element. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_sequence_get_field( - struct bt_ctf_field *sequence, uint64_t index); - -/* - * bt_ctf_field_variant_get_field: get a variant's selected field. - * - * Return the variant's selected field. The "tag" field is the selector enum - * field. bt_ctf_field_put() must be called on the returned value. - * - * @param variant Variant field instance. - * @param tag Selector enumeration field. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_variant_get_field( - struct bt_ctf_field *variant, struct bt_ctf_field *tag); - -/* - * bt_ctf_field_enumeration_get_container: get an enumeration field's container. - * - * Return the enumeration's underlying container field (an integer). - * bt_ctf_field_put() must be called on the returned value. - * - * @param enumeration Enumeration field instance. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_field_enumeration_get_container( - struct bt_ctf_field *enumeration); - -/* - * bt_ctf_field_signed_integer_set_value: set a signed integer field's value - * - * Set a signed integer field's value. The value is checked to make sure it - * can be stored in the underlying field. - * - * @param integer Signed integer field instance. - * @param value Signed integer field value. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *integer, - int64_t value); - -/* - * bt_ctf_field_unsigned_integer_set_value: set unsigned integer field's value - * - * Set an unsigned integer field's value. The value is checked to make sure it - * can be stored in the underlying field. - * - * @param integer Unsigned integer field instance. - * @param value Unsigned integer field value. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *integer, - uint64_t value); - -/* - * bt_ctf_field_floating_point_set_value: set a floating point field's value - * - * Set a floating point field's value. The underlying type may not support the - * double's full precision. - * - * @param floating_point Floating point field instance. - * @param value Floating point field value. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_floating_point_set_value( - struct bt_ctf_field *floating_point, - double value); - -/* - * bt_ctf_field_string_set_value: set a string field's value - * - * Set a string field's value. - * - * @param string String field instance. - * @param value String field value (will be copied). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_string_set_value(struct bt_ctf_field *string, - const char *value); - /* * bt_ctf_field_get and bt_ctf_field_put: increment and decrement the * field's reference count. * + * You may also use bt_ctf_get() and bt_ctf_put() with field objects. + * * These functions ensure that the field won't be destroyed when it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) have to be done to diff --git a/include/babeltrace/ctf-writer/event-types-internal.h b/include/babeltrace/ctf-writer/event-types-internal.h deleted file mode 100644 index a937c780..00000000 --- a/include/babeltrace/ctf-writer/event-types-internal.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H -#define BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H - -/* - * BabelTrace - CTF Writer: Event types internal - * - * Copyright 2013 EfficiOS Inc. - * - * Author: Jérémie Galarneau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef void(*type_freeze_func)(struct bt_ctf_field_type *); -typedef int(*type_serialize_func)(struct bt_ctf_field_type *, - struct metadata_context *); - -struct bt_ctf_field_type { - struct bt_ctf_ref ref_count; - struct bt_declaration *declaration; - type_freeze_func freeze; - type_serialize_func serialize; - /* - * A type can't be modified once it is added to an event or after a - * a field has been instanciated from it. - */ - int frozen; -}; - -struct bt_ctf_field_type_integer { - struct bt_ctf_field_type parent; - struct declaration_integer declaration; -}; - -struct enumeration_mapping { - int64_t range_start; - int64_t range_end; - GQuark string; -}; - -struct bt_ctf_field_type_enumeration { - struct bt_ctf_field_type parent; - struct bt_ctf_field_type *container; - GPtrArray *entries; /* Array of pointers to struct enum_mapping */ - struct declaration_enum declaration; -}; - -struct bt_ctf_field_type_floating_point { - struct bt_ctf_field_type parent; - struct declaration_float declaration; - struct declaration_integer sign; - struct declaration_integer mantissa; - struct declaration_integer exp; -}; - -struct structure_field { - GQuark name; - struct bt_ctf_field_type *type; -}; - -struct bt_ctf_field_type_structure { - struct bt_ctf_field_type parent; - GHashTable *field_name_to_index; - GPtrArray *fields; /* Array of pointers to struct structure_field */ - struct declaration_enum declaration; -}; - -struct bt_ctf_field_type_variant { - struct bt_ctf_field_type parent; - GString *tag_name; - struct bt_ctf_field_type_enumeration *tag; - GHashTable *field_name_to_index; - GPtrArray *fields; /* Array of pointers to struct structure_field */ - struct declaration_variant declaration; -}; - -struct bt_ctf_field_type_array { - struct bt_ctf_field_type parent; - struct bt_ctf_field_type *element_type; - unsigned int length; /* Number of elements */ - struct declaration_array declaration; -}; - -struct bt_ctf_field_type_sequence { - struct bt_ctf_field_type parent; - struct bt_ctf_field_type *element_type; - GString *length_field_name; - struct declaration_sequence declaration; -}; - -struct bt_ctf_field_type_string { - struct bt_ctf_field_type parent; - struct declaration_string declaration; -}; - -BT_HIDDEN -void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type); - -BT_HIDDEN -enum ctf_type_id bt_ctf_field_type_get_type_id( - struct bt_ctf_field_type *type); - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_structure_get_type( - struct bt_ctf_field_type_structure *structure, - const char *name); - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( - struct bt_ctf_field_type_array *array); - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( - struct bt_ctf_field_type_sequence *sequence); - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type( - struct bt_ctf_field_type_variant *variant, int64_t tag_value); - -BT_HIDDEN -int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context); - -BT_HIDDEN -int bt_ctf_field_type_validate(struct bt_ctf_field_type *type); - -#endif /* BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H */ diff --git a/include/babeltrace/ctf-writer/event-types.h b/include/babeltrace/ctf-writer/event-types.h index cf43ed61..e19c9cde 100644 --- a/include/babeltrace/ctf-writer/event-types.h +++ b/include/babeltrace/ctf-writer/event-types.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Event Types * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,309 +30,18 @@ * http://www.efficios.com/ctf */ -#include -#include -#include +#include #ifdef __cplusplus extern "C" { #endif -struct bt_ctf_event_class; -struct bt_ctf_event; -struct bt_ctf_field_type; - -enum bt_ctf_integer_base { - BT_CTF_INTEGER_BASE_UNKNOWN = -1, - BT_CTF_INTEGER_BASE_BINARY = 2, - BT_CTF_INTEGER_BASE_OCTAL = 8, - BT_CTF_INTEGER_BASE_DECIMAL = 10, - BT_CTF_INTEGER_BASE_HEXADECIMAL = 16, -}; - -/* - * bt_ctf_field_type_integer_create: create an integer field type. - * - * Allocate a new integer field type of the given size. The creation of a field - * type sets its reference count to 1. - * - * @param size Integer field type size/length in bits. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_integer_create( - unsigned int size); - -/* - * bt_ctf_field_type_integer_set_signed: set an integer type's signedness. - * - * Set an integer type's signedness attribute. - * - * @param integer Integer type. - * @param is_signed Integer's signedness, defaults to FALSE. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_integer_set_signed( - struct bt_ctf_field_type *integer, int is_signed); - -/* - * bt_ctf_field_type_integer_set_base: set an integer type's base. - * - * Set an integer type's base used to pretty-print the resulting trace. - * - * @param integer Integer type. - * @param base Integer base, defaults to BT_CTF_INTEGER_BASE_DECIMAL. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_integer_set_base( - struct bt_ctf_field_type *integer, - enum bt_ctf_integer_base base); - -/* - * bt_ctf_field_type_integer_set_encoding: set an integer type's encoding. - * - * An integer encoding may be set to signal that the integer must be printed as - * a text character. - * - * @param integer Integer type. - * @param encoding Integer output encoding, defaults to CTF_STRING_ENCODING_NONE - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_integer_set_encoding( - struct bt_ctf_field_type *integer, - enum ctf_string_encoding encoding); - -/* - * bt_ctf_field_type_enumeration_create: create an enumeration field type. - * - * Allocate a new enumeration field type with the given underlying type. The - * creation of a field type sets its reference count to 1. - * The resulting enumeration will share the integer_container_type's ownership - * by increasing its reference count. - * - * @param integer_container_type Underlying integer type of the enumeration - * type. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( - struct bt_ctf_field_type *integer_container_type); - -/* - * bt_ctf_field_type_enumeration_add_mapping: add an enumeration mapping. - * - * Add a mapping to the enumeration. The range's values are inclusive. - * - * @param enumeration Enumeration type. - * @param string Enumeration mapping name (will be copied). - * @param range_start Enumeration mapping range start. - * @param range_end Enumeration mapping range end. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_enumeration_add_mapping( - struct bt_ctf_field_type *enumeration, const char *string, - int64_t range_start, int64_t range_end); - -/* - * bt_ctf_field_type_floating_point_create: create a floating point field type. - * - * Allocate a new floating point field type. The creation of a field type sets - * its reference count to 1. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void); - -/* - * bt_ctf_field_type_floating_point_set_exponent_digits: set exponent digit - * count. - * - * Set the number of exponent digits to use to store the floating point field. - * The only values currently supported are FLT_EXP_DIG and DBL_EXP_DIG. - * - * @param floating_point Floating point type. - * @param exponent_digits Number of digits to allocate to the exponent (defaults - * to FLT_EXP_DIG). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_floating_point_set_exponent_digits( - struct bt_ctf_field_type *floating_point, - unsigned int exponent_digits); - -/* - * bt_ctf_field_type_floating_point_set_mantissa_digits: set mantissa digit - * count. - * - * Set the number of mantissa digits to use to store the floating point field. - * The only values currently supported are FLT_MANT_DIG and DBL_MANT_DIG. - * - * @param floating_point Floating point type. - * @param mantissa_digits Number of digits to allocate to the mantissa (defaults - * to FLT_MANT_DIG). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_floating_point_set_mantissa_digits( - struct bt_ctf_field_type *floating_point, - unsigned int mantissa_digits); - -/* - * bt_ctf_field_type_structure_create: create a structure field type. - * - * Allocate a new structure field type. The creation of a field type sets - * its reference count to 1. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void); - -/* - * bt_ctf_field_type_structure_add_field: add a field to a structure. - * - * Add a field of type "field_type" to the structure. The structure will share - * field_type's ownership by increasing its reference count. - * - * @param structure Structure type. - * @param field_type Type of the field to add to the structure type. - * @param field_name Name of the structure's new field (will be copied). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_structure_add_field( - struct bt_ctf_field_type *structure, - struct bt_ctf_field_type *field_type, - const char *field_name); - -/* - * bt_ctf_field_type_variant_create: create a variant field type. - * - * Allocate a new variant field type. The creation of a field type sets - * its reference count to 1. tag_name must be the name of an enumeration - * field declared in the same scope as this variant. - * - * @param enum_tag Type of the variant's tag/selector (must be an enumeration). - * @param tag_name Name of the variant's tag/selector field (will be copied). - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_variant_create( - struct bt_ctf_field_type *enum_tag, - const char *tag_name); - -/* - * bt_ctf_field_type_variant_add_field: add a field to a variant. - * - * Add a field of type "field_type" to the variant.The variant will share - * field_type's ownership by increasing its reference count. The "field_name" - * will be copied. field_name must match a mapping in the tag/selector - * enumeration. - * - * @param variant Variant type. - * @param field_type Type of the variant type's new field. - * @param field_name Name of the variant type's new field (will be copied). - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_variant_add_field( - struct bt_ctf_field_type *variant, - struct bt_ctf_field_type *field_type, - const char *field_name); - -/* - * bt_ctf_field_type_array_create: create an array field type. - * - * Allocate a new array field type. The creation of a field type sets - * its reference count to 1. - * - * @param element_type Array's element type. - * @oaram length Array type's length. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_array_create( - struct bt_ctf_field_type *element_type, - unsigned int length); - -/* - * bt_ctf_field_type_sequence_create: create a sequence field type. - * - * Allocate a new sequence field type. The creation of a field type sets - * its reference count to 1. "length_field_name" must match an integer field - * declared in the same scope. - * - * @param element_type Sequence's element type. - * @param length_field_name Name of the sequence's length field (will be - * copied). - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( - struct bt_ctf_field_type *element_type, - const char *length_field_name); - -/* - * bt_ctf_field_type_string_create: create a string field type. - * - * Allocate a new string field type. The creation of a field type sets - * its reference count to 1. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_field_type *bt_ctf_field_type_string_create(void); - -/* - * bt_ctf_field_type_string_set_encoding: set a string type's encoding. - * - * Set the string type's encoding. - * - * @param string String type. - * @param encoding String field encoding, default CTF_STRING_ENCODING_ASCII. - * Valid values are CTF_STRING_ENCODING_ASCII and CTF_STRING_ENCODING_UTF8. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_string_set_encoding( - struct bt_ctf_field_type *string, - enum ctf_string_encoding encoding); - -/* - * bt_ctf_field_type_set_alignment: set a field type's alignment. - * - * Set the field type's alignment. - * - * @param type Field type. - * @param alignment Type's alignment. Defaults to 1 (bit-aligned). However, - * some types, such as structures and string, may impose other alignment - * constraints. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, - unsigned int alignment); - -/* - * bt_ctf_field_type_set_byte_order: set a field type's byte order. - * - * Set the field type's byte order. - * - * @param type Field type. - * @param byte_order Field type's byte order. Defaults to - * BT_CTF_BYTE_ORDER_NATIVE, the host machine's endianness. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, - enum bt_ctf_byte_order byte_order); - /* * bt_ctf_field_type_get and bt_ctf_field_type_put: increment and decrement * the field type's reference count. * + * You may also use bt_ctf_get() and bt_ctf_put() with field type objects. + * * These functions ensure that the field type won't be destroyed while it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) have to be done to diff --git a/include/babeltrace/ctf-writer/event.h b/include/babeltrace/ctf-writer/event.h index d8ef9d92..0928e083 100644 --- a/include/babeltrace/ctf-writer/event.h +++ b/include/babeltrace/ctf-writer/event.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Event * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,48 +30,38 @@ * http://www.efficios.com/ctf */ +#include +#include + #ifdef __cplusplus extern "C" { #endif -struct bt_ctf_event_class; -struct bt_ctf_event; -struct bt_ctf_field; -struct bt_ctf_field_type; - /* - * bt_ctf_event_class_create: create an event class. - * - * Allocate a new event class of the given name. The creation of an event class - * sets its reference count to 1. + * bt_ctf_event_get and bt_ctf_event_put: increment and decrement + * the event's reference count. * - * @param name Event class name (will be copied). + * You may also use bt_ctf_get() and bt_ctf_put() with event objects. * - * Returns an allocated event class on success, NULL on error. - */ -extern struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name); - -/* - * bt_ctf_event_class_add_field: add a field to an event class. - * - * Add a field of type "type" to the event class. The event class will share - * type's ownership by increasing its reference count. The "name" will be - * copied. + * These functions ensure that the event won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy an event. * - * @param event_class Event class. - * @param type Field type to add to the event class. - * @param name Name of the new field. + * When the event's reference count is decremented to 0 by a + * bt_ctf_event_put, the event is freed. * - * Returns 0 on success, a negative value on error. + * @param event Event instance. */ -extern int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, - struct bt_ctf_field_type *type, - const char *name); +extern void bt_ctf_event_get(struct bt_ctf_event *event); +extern void bt_ctf_event_put(struct bt_ctf_event *event); /* - * bt_ctf_event_class__get and bt_ctf_event_class_put: increment and decrement + * bt_ctf_event_class_get and bt_ctf_event_class_put: increment and decrement * the event class' reference count. * + * You may also use bt_ctf_get() and bt_ctf_put() with event class objects. + * * These functions ensure that the event class won't be destroyed while it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) have to be done to @@ -85,68 +75,6 @@ extern int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, extern void bt_ctf_event_class_get(struct bt_ctf_event_class *event_class); extern void bt_ctf_event_class_put(struct bt_ctf_event_class *event_class); -/* - * bt_ctf_event_create: instanciate an event. - * - * Allocate a new event of the given event class. The creation of an event - * sets its reference count to 1. Each instance shares the ownership of the - * event class using its reference count. - * - * @param event_class Event class. - * - * Returns an allocated field type on success, NULL on error. - */ -extern struct bt_ctf_event *bt_ctf_event_create( - struct bt_ctf_event_class *event_class); - -/* - * bt_ctf_event_set_payload: set an event's field. - * - * Set a manually allocated field as an event's payload. The event will share - * the field's ownership by using its reference count. - * bt_ctf_field_put() must be called on the returned value. - * - * @param event Event instance. - * @param name Event field name. - * @param value Instance of a field whose type corresponds to the event's field. - * - * Returns 0 on success, a negative value on error. - */ -extern int bt_ctf_event_set_payload(struct bt_ctf_event *event, - const char *name, - struct bt_ctf_field *value); - -/* - * bt_ctf_event_get_payload: get an event's field. - * - * Returns the field matching "name". bt_ctf_field_put() must be called on the - * returned value. - * - * @param event Event instance. - * @param name Event field name. - * - * Returns a field instance on success, NULL on error. - */ -extern struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, - const char *name); - -/* - * bt_ctf_event_get and bt_ctf_event_put: increment and decrement - * the event's reference count. - * - * These functions ensure that the event won't be destroyed while it - * is in use. The same number of get and put (plus one extra put to - * release the initial reference done at creation) have to be done to - * destroy an event. - * - * When the event's reference count is decremented to 0 by a - * bt_ctf_event_put, the event is freed. - * - * @param event Event instance. - */ -extern void bt_ctf_event_get(struct bt_ctf_event *event); -extern void bt_ctf_event_put(struct bt_ctf_event *event); - #ifdef __cplusplus } #endif diff --git a/include/babeltrace/ctf-writer/functor-internal.h b/include/babeltrace/ctf-writer/functor-internal.h index 66d3fcf8..1db2d296 100644 --- a/include/babeltrace/ctf-writer/functor-internal.h +++ b/include/babeltrace/ctf-writer/functor-internal.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Functors for use with glib data structures * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * diff --git a/include/babeltrace/ctf-writer/stream-class.h b/include/babeltrace/ctf-writer/stream-class.h new file mode 100644 index 00000000..139165a3 --- /dev/null +++ b/include/babeltrace/ctf-writer/stream-class.h @@ -0,0 +1,77 @@ +#ifndef BABELTRACE_CTF_WRITER_STREAM_CLASS_H +#define BABELTRACE_CTF_WRITER_STREAM_CLASS_H + +/* + * BabelTrace - CTF Writer: Stream Class + * + * Copyright 2014 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * bt_ctf_stream_class_set_clock: assign a clock to a stream class. + * + * Assign a clock to a stream class. This clock will be sampled each time an + * event is appended to an instance of this stream class. + * + * @param stream_class Stream class. + * @param clock Clock to assign to the provided stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_clock( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_clock *clock); + +/* + * bt_ctf_stream_class_get and bt_ctf_stream_class_put: increment and + * decrement the stream class' reference count. + * + * You may also use bt_ctf_get() and bt_ctf_put() with stream class objects. + * + * These functions ensure that the stream class won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a stream class. + * + * When the stream class' reference count is decremented to 0 by a + * bt_ctf_stream_class_put, the stream class is freed. + * + * @param stream_class Stream class. + */ +extern void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class); +extern void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_STREAM_CLASS_H */ diff --git a/include/babeltrace/ctf-writer/stream.h b/include/babeltrace/ctf-writer/stream.h index df4d0c92..f8ad7b83 100644 --- a/include/babeltrace/ctf-writer/stream.h +++ b/include/babeltrace/ctf-writer/stream.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Stream * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,112 +30,121 @@ * http://www.efficios.com/ctf */ +#include +#include + #ifdef __cplusplus extern "C" { #endif -struct bt_ctf_event; -struct bt_ctf_event_class; -struct bt_ctf_stream_class; -struct bt_ctf_stream; -struct bt_ctf_clock; - /* - * bt_ctf_stream_class_create: create a stream class. + * bt_ctf_stream_get_discarded_events_count: get the number of discarded + * events associated with this stream. * - * Allocate a new stream class of the given name. The creation of an event class - * sets its reference count to 1. + * Note that discarded events are not stored if the stream's packet + * context has no "events_discarded" field. An error will be returned + * in that case. * - * @param name Stream name. + * @param stream Stream instance. * - * Returns an allocated stream class on success, NULL on error. + * Returns the number of discarded events, a negative value on error. */ -extern struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name); +extern int bt_ctf_stream_get_discarded_events_count( + struct bt_ctf_stream *stream, uint64_t *count); /* - * bt_ctf_stream_class_set_clock: assign a clock to a stream class. - * - * Assign a clock to a stream class. This clock will be sampled each time an - * event is appended to an instance of this stream class. + * bt_ctf_stream_append_discarded_events: increment discarded events count. * - * @param stream_class Stream class. - * @param clock Clock to assign to the provided stream class. + * Increase the current packet's discarded event count. Has no effect if the + * stream class' packet context has no "events_discarded" field. * - * Returns 0 on success, a negative value on error. + * @param stream Stream instance. + * @param event_count Number of discarded events to add to the stream's current + * packet. */ -extern int bt_ctf_stream_class_set_clock( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_clock *clock); +extern void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, + uint64_t event_count); /* - * bt_ctf_stream_class_set_clock: assign a clock to a stream class. + * bt_ctf_stream_append_event: append an event to the stream. * - * Add an event class to a stream class. New events can be added even after a - * stream has beem instanciated and events have been appended. However, a stream - * will not accept events of a class that has not been registered beforehand. - * The stream class will share the ownership of "event_class" by incrementing - * its reference count. + * Append "event" to the stream's current packet. The stream's associated clock + * will be sampled during this call. The event shall not be modified after + * being appended to a stream. The stream will share the event's ownership by + * incrementing its reference count. The current packet is not flushed to disk + * until the next call to bt_ctf_stream_flush. + * + * The stream event context will be sampled for every appended event if + * a stream event context was defined. * - * @param stream_class Stream class. - * @param event_class Event class to add to the provided stream class. + * @param stream Stream instance. + * @param event Event instance to append to the stream's current packet. * * Returns 0 on success, a negative value on error. */ -extern int bt_ctf_stream_class_add_event_class( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_event_class *event_class); +extern int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, + struct bt_ctf_event *event); /* - * bt_ctf_stream_class_get and bt_ctf_stream_class_put: increment and - * decrement the stream class' reference count. - * - * These functions ensure that the stream class won't be destroyed while it - * is in use. The same number of get and put (plus one extra put to - * release the initial reference done at creation) have to be done to - * destroy a stream class. + * bt_ctf_stream_get_packet_header: get a stream's packet header. * - * When the stream class' reference count is decremented to 0 by a - * bt_ctf_stream_class_put, the stream class is freed. + * @param stream Stream instance. * - * @param stream_class Stream class. + * Returns a field instance on success, NULL on error. */ -extern void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class); -extern void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class); +extern struct bt_ctf_field *bt_ctf_stream_get_packet_header( + struct bt_ctf_stream *stream); /* - * bt_ctf_stream_append_discarded_events: increment discarded events count. + * bt_ctf_stream_set_packet_header: set a stream's packet header. * - * Increase the current packet's discarded event count. + * The packet header's type must match the trace's packet header + * type. * * @param stream Stream instance. - * @param event_count Number of discarded events to add to the stream's current - * packet. + * @param packet_header Packet header instance. + * + * Returns a field instance on success, NULL on error. */ -extern void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, - uint64_t event_count); +extern int bt_ctf_stream_set_packet_header( + struct bt_ctf_stream *stream, + struct bt_ctf_field *packet_header); /* - * bt_ctf_stream_append_event: append an event to the stream. + * bt_ctf_stream_get_packet_context: get a stream's packet context. * - * Append "event" to the stream's current packet. The stream's associated clock - * will be sampled during this call. The event shall not be modified after - * being appended to a stream. The stream will share the event's ownership by - * incrementing its reference count. The current packet is not flushed to disk - * until the next call to bt_ctf_stream_flush. + * @param stream Stream instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_stream_get_packet_context( + struct bt_ctf_stream *stream); + +/* + * bt_ctf_stream_set_packet_context: set a stream's packet context. + * + * The packet context's type must match the stream class' packet + * context type. * * @param stream Stream instance. - * @param event Event instance to append to the stream's current packet. + * @param packet_context Packet context field instance. * - * Returns 0 on success, a negative value on error. + * Returns a field instance on success, NULL on error. */ -extern int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, - struct bt_ctf_event *event); +extern int bt_ctf_stream_set_packet_context( + struct bt_ctf_stream *stream, + struct bt_ctf_field *packet_context); /* * bt_ctf_stream_flush: flush a stream. * - * The stream's current packet's events will be flushed to disk. Events - * subsequently appended to the stream will be added to a new packet. + * The stream's current packet's events will be flushed, thus closing the + * current packet. Events subsequently appended to the stream will be + * added to a new packet. + * + * Flushing will also set the packet context's default attributes if + * they remained unset while populating the current packet. These default + * attributes, along with their expected types, are detailed in stream-class.h. * * @param stream Stream instance. * @@ -147,6 +156,8 @@ extern int bt_ctf_stream_flush(struct bt_ctf_stream *stream); * bt_ctf_stream_get and bt_ctf_stream_put: increment and decrement the * stream's reference count. * + * You may also use bt_ctf_get() and bt_ctf_put() with stream objects. + * * These functions ensure that the stream won't be destroyed while it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) have to be done to diff --git a/include/babeltrace/ctf-writer/writer-internal.h b/include/babeltrace/ctf-writer/writer-internal.h index 5c682dd8..3fa03b59 100644 --- a/include/babeltrace/ctf-writer/writer-internal.h +++ b/include/babeltrace/ctf-writer/writer-internal.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Writer internal * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,61 +27,24 @@ * SOFTWARE. */ -#include #include -#include -#include #include #include #include #include -#include - -enum field_type_alias { - FIELD_TYPE_ALIAS_UINT5_T = 0, - FIELD_TYPE_ALIAS_UINT8_T, - FIELD_TYPE_ALIAS_UINT16_T, - FIELD_TYPE_ALIAS_UINT27_T, - FIELD_TYPE_ALIAS_UINT32_T, - FIELD_TYPE_ALIAS_UINT64_T, - NR_FIELD_TYPE_ALIAS, -}; +#include +#include struct bt_ctf_writer { - struct bt_ctf_ref ref_count; + struct bt_object base; int frozen; /* Protects attributes that can't be changed mid-trace */ + struct bt_ctf_trace *trace; GString *path; - uuid_t uuid; - int byte_order; int trace_dir_fd; int metadata_fd; - GPtrArray *environment; /* Array of pointers to environment_variable */ - GPtrArray *clocks; /* Array of pointers to bt_ctf_clock */ - GPtrArray *stream_classes; /* Array of pointers to bt_ctf_stream_class */ - GPtrArray *streams; /* Array of pointers to bt_ctf_stream */ - struct bt_ctf_field_type *trace_packet_header_type; - struct bt_ctf_field *trace_packet_header; - uint32_t next_stream_id; -}; - -struct environment_variable { - GString *name, *value; -}; - -struct metadata_context { - GString *string; - GString *field_name; - unsigned int current_indentation_level; }; -/* Checks that the string does not contain a reserved keyword */ -BT_HIDDEN -int validate_identifier(const char *string); - -BT_HIDDEN -const char *get_byte_order_string(int byte_order); - BT_HIDDEN -struct bt_ctf_field_type *get_field_type(enum field_type_alias alias); +void bt_ctf_writer_freeze(struct bt_ctf_writer *writer); #endif /* BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H */ diff --git a/include/babeltrace/ctf-writer/writer.h b/include/babeltrace/ctf-writer/writer.h index 953921f2..140bc5fd 100644 --- a/include/babeltrace/ctf-writer/writer.h +++ b/include/babeltrace/ctf-writer/writer.h @@ -4,7 +4,7 @@ /* * BabelTrace - CTF Writer: Writer * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -30,6 +30,9 @@ * http://www.efficios.com/ctf */ +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -39,13 +42,6 @@ struct bt_ctf_stream; struct bt_ctf_stream_class; struct bt_ctf_clock; -enum bt_ctf_byte_order { - BT_CTF_BYTE_ORDER_NATIVE = 0, - BT_CTF_BYTE_ORDER_LITTLE_ENDIAN, - BT_CTF_BYTE_ORDER_BIG_ENDIAN, - BT_CTF_BYTE_ORDER_NETWORK, -}; - /* * bt_ctf_writer_create: create a writer instance. * @@ -58,6 +54,16 @@ enum bt_ctf_byte_order { */ extern struct bt_ctf_writer *bt_ctf_writer_create(const char *path); +/* + * bt_ctf_writer_get_trace: Get a writer's associated trace. + * + * @param writer Writer instance. + * + * Return the writer's associated instance, NULL on error. + */ +extern struct bt_ctf_trace *bt_ctf_writer_get_trace( + struct bt_ctf_writer *writer); + /* * bt_ctf_writer_create_stream: create a stream instance. * @@ -89,6 +95,23 @@ extern int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, const char *name, const char *value); +/* + * bt_ctf_writer_add_environment_field_int64: add an environment field to the trace. + * + * Add an environment field to the trace. The name and value parameters are + * copied. + * + * @param writer Writer instance. + * @param name Name of the environment field (will be copied). + * @param value Value of the environment field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_writer_add_environment_field_int64( + struct bt_ctf_writer *writer, + const char *name, + int64_t value); + /* * bt_ctf_writer_add_clock: add a clock to the trace. * @@ -129,13 +152,16 @@ extern void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer); /* * bt_ctf_writer_set_byte_order: set a field type's byte order. * - * Set the trace's byte order. Defaults to BT_CTF_BYTE_ORDER_NATIVE, - * the host machine's endianness. + * Set the trace's byte order. Defaults to the host machine's endianness. * * @param writer Writer instance. * @param byte_order Trace's byte order. * * Returns 0 on success, a negative value on error. + * + * Note: byte_order must not be BT_CTF_BYTE_ORDER_NATIVE since, according + * to the CTF specification, is defined as "the byte order described in the + * trace description". */ extern int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, enum bt_ctf_byte_order byte_order); @@ -144,6 +170,8 @@ extern int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, * bt_ctf_writer_get and bt_ctf_writer_put: increment and decrement the * writer's reference count. * + * You may also use bt_ctf_get() and bt_ctf_put() with writer objects. + * * These functions ensure that the writer won't be destroyed while it * is in use. The same number of get and put (plus one extra put to * release the initial reference done at creation) have to be done to diff --git a/include/babeltrace/object-internal.h b/include/babeltrace/object-internal.h new file mode 100644 index 00000000..747950f7 --- /dev/null +++ b/include/babeltrace/object-internal.h @@ -0,0 +1,117 @@ +#ifndef BABELTRACE_OBJECT_INTERNAL_H +#define BABELTRACE_OBJECT_INTERNAL_H + +/* + * Babeltrace - Base object + * + * Copyright 2015 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +/** + * All objects publicly exposed by Babeltrace APIs must contain this structure + * as their first member. This allows the unification of all ref counting + * mechanism and may be used to provide more base functionality to all + * objects. + */ +struct bt_object { + struct bt_ref ref_count; + /* Class-specific release function. */ + bt_object_release_func release; + /* @see doc/ref-counting.md */ + struct bt_object *parent; +}; + +static inline +long bt_object_get_ref_count(const void *); +static inline +void bt_object_set_parent(void *, void *); + +static +void bt_object_release(void *ptr) +{ + struct bt_object *obj = ptr; + + if (obj && obj->release && !bt_object_get_ref_count(obj)) { + obj->release(obj); + } +} + +static +void generic_release(struct bt_object *obj) +{ + if (obj->parent) { + /* The release function will be invoked by the parent. */ + bt_put(obj->parent); + } else { + bt_object_release(obj); + } +} + +static inline +struct bt_object *bt_object_get_parent(void *ptr) +{ + struct bt_object *obj = ptr; + + return ptr ? bt_get(obj->parent) : NULL; +} + +static inline +void bt_object_set_parent(void *child_ptr, void *parent) +{ + struct bt_object *child = child_ptr; + + if (!child) { + return; + } + + /* + * It is assumed that a "child" being "parented" is publicly reachable. + * Therefore, a reference to its parent must be taken. The reference + * to the parent will be released once the object's reference count + * falls to zero. + */ + child->parent = bt_get(parent); +} + +static inline +void bt_object_init(void *ptr, bt_object_release_func release) +{ + struct bt_object *obj = ptr; + + obj->release = release; + obj->parent = NULL; + bt_ref_init(&obj->ref_count, generic_release); +} + +static inline +long bt_object_get_ref_count(const void *ptr) +{ + const struct bt_object *obj = ptr; + + return obj->ref_count.count; +} + +#endif /* BABELTRACE_OBJECT_INTERNAL_H */ diff --git a/include/babeltrace/ctf-writer/ref-internal.h b/include/babeltrace/ref-internal.h similarity index 61% rename from include/babeltrace/ctf-writer/ref-internal.h rename to include/babeltrace/ref-internal.h index 486e243c..224e9229 100644 --- a/include/babeltrace/ctf-writer/ref-internal.h +++ b/include/babeltrace/ref-internal.h @@ -1,10 +1,10 @@ -#ifndef BABELTRACE_CTF_WRITER_REF_INTERNAL_H -#define BABELTRACE_CTF_WRITER_REF_INTERNAL_H +#ifndef BABELTRACE_REF_INTERNAL_H +#define BABELTRACE_REF_INTERNAL_H /* - * BabelTrace - CTF Writer: Reference count + * Babeltrace - Reference Counting * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -27,35 +27,41 @@ * SOFTWARE. */ +#include #include -struct bt_ctf_ref { - long refcount; +struct bt_object; +typedef void (*bt_object_release_func)(struct bt_object *); + +struct bt_ref { + long count; + bt_object_release_func release; }; static inline -void bt_ctf_ref_init(struct bt_ctf_ref *ref) +void bt_ref_init(struct bt_ref *ref, bt_object_release_func release) { assert(ref); - ref->refcount = 1; + ref->count = 1; + ref->release = release; } static inline -void bt_ctf_ref_get(struct bt_ctf_ref *ref) +void bt_ref_get(struct bt_ref *ref) { assert(ref); - ref->refcount++; + ref->count++; } static inline -void bt_ctf_ref_put(struct bt_ctf_ref *ref, - void (*release)(struct bt_ctf_ref *)) +void bt_ref_put(struct bt_ref *ref) { assert(ref); - assert(release); - if ((--ref->refcount) == 0) { - release(ref); + /* Only assert if the object has opted-in for reference counting. */ + assert(!ref->release || ref->count > 0); + if ((--ref->count) == 0 && ref->release) { + ref->release((struct bt_object *) ref); } } -#endif /* BABELTRACE_CTF_WRITER_REF_INTERNAL_H */ +#endif /* BABELTRACE_REF_INTERNAL_H */ diff --git a/include/babeltrace/ref.h b/include/babeltrace/ref.h new file mode 100644 index 00000000..63cf2f02 --- /dev/null +++ b/include/babeltrace/ref.h @@ -0,0 +1,108 @@ +#ifndef BABELTRACE_REF_H +#define BABELTRACE_REF_H + +/* + * BabelTrace: common reference counting + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * Copyright (c) 2015 Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * BT_PUT: calls bt_put() with a variable, then sets this variable to NULL. + * + * A common action with Babeltrace objects is to create or get one, perform + * an action with it, and then put it. To avoid putting it a second time + * later (if an error occurs, for example), the variable is often reset + * to NULL after putting the object it points to. Since this is so + * common, the BT_PUT() macro can be used to do just that. + * + * It is safe to call this function with a variable containing NULL. + * + * @param obj Variable pointing to a Babeltrace object. + */ +#define BT_PUT(_obj) \ + do { \ + bt_put(_obj); \ + (_obj) = NULL; \ + } while (0) + +/* + * BT_MOVE: transfers the ownership of an object, setting the old owner to NULL. + * + * This macro sets the variable _dst to the value of the variable _src, + * then sets _src to NULL, effectively moving the ownership of an + * object from one variable to the other. + * + * Before assigning _src to _dst, it puts _dst. Therefore it is not safe to + * call this function with an uninitialized value of _dst. + * + * @param _dst Destination variable pointing to a Babeltrace object. + * @param _src Source variable pointing to a Babeltrace object. + */ +#define BT_MOVE(_dst, _src) \ + do { \ + bt_put(_dst); \ + (_dst) = (_src);\ + (_src) = NULL; \ + } while (0) + +/* + * bt_get: increments the reference count of a Babeltrace object. + * + * The same number of bt_get() and bt_put() (plus one extra bt_put() to release + * the initial reference acquired at creation) have to be performed to destroy a + * Babeltrace object. + * + * It is safe to call this function with a NULL object. + * + * @param obj Babeltrace object. + * + * Returns obj. + */ +void *bt_get(void *obj); + +/* + * bt_put: decrements the reference count of a Babeltrace object. + * + * The same number of bt_get() and bt_put() (plus one extra bt_put() to release + * bt_put() to release the initial reference done at creation) have to be + * performed to destroy a Babeltrace object. + * + * The object is freed when its reference count is decremented to 0 by a call to + * bt_put(). + * + * It is safe to call this function with a NULL object. + * + * @param obj Babeltrace object. + */ +void bt_put(void *obj); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_REF_H */ diff --git a/include/babeltrace/values.h b/include/babeltrace/values.h new file mode 100644 index 00000000..e13cc202 --- /dev/null +++ b/include/babeltrace/values.h @@ -0,0 +1,976 @@ +#ifndef _BABELTRACE_VALUES_H +#define _BABELTRACE_VALUES_H + +/* + * Babeltrace - Value objects + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file values.h + * @brief Value objects + * + * This is a set of value objects. The following functions allow you + * to create, modify, and destroy: + * + * - \link bt_value_null null value objects\endlink + * - \link bt_value_bool_create() boolean value objects\endlink + * - \link bt_value_integer_create() integer value objects\endlink + * - \link bt_value_float_create() floating point number + * value objects\endlink + * - \link bt_value_string_create() string value objects\endlink + * - \link bt_value_array_create() array value objects\endlink, + * containing zero or more value objects + * - \link bt_value_map_create() map value objects\endlink, mapping + * string keys to value objects + * + * All the value object types above, except for null values (which + * always point to the same \link bt_value_null singleton\endlink), have + * a reference count property. Once a value object is created, its + * reference count is set to 1. When \link bt_value_array_append() + * appending a value to an array value object\endlink, or + * \link bt_value_map_insert() inserting a value object into a map + * value object\endlink, its reference count is incremented, as well as + * when getting a value object back from those structures. The + * bt_get() and bt_put() functions are to be used to handle reference counting + * Once you are done with a value object, pass it to bt_put(). + * + * Most functions of this API return a status code, one of the values in + * #bt_value_status. + * + * You can create a deep copy of any value object using the + * bt_value_copy() function. You can compare two given value objects + * using bt_value_compare(). + * + * Any value object may be frozen using bt_value_freeze(). You may get + * the raw value of a frozen value object, but you cannot modify it. + * Reference counting still works on frozen value objects. You may also + * copy and compare frozen value objects. + * + * @author Philippe Proulx + * @bug No known bugs + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Value object type. + */ +enum bt_value_type { + /** Unknown value object, used as an error code. */ + BT_VALUE_TYPE_UNKNOWN = -1, + + /** Null value object. */ + BT_VALUE_TYPE_NULL = 0, + + /** Boolean value object (holds \c true or \c false). */ + BT_VALUE_TYPE_BOOL = 1, + + /** Integer value object (holds a signed 64-bit integer raw value). */ + BT_VALUE_TYPE_INTEGER = 2, + + /** Floating point number value object (holds a \c double raw value). */ + BT_VALUE_TYPE_FLOAT = 3, + + /** String value object. */ + BT_VALUE_TYPE_STRING = 4, + + /** Array value object. */ + BT_VALUE_TYPE_ARRAY = 5, + + /** Map value object. */ + BT_VALUE_TYPE_MAP = 6, +}; + +/** + * Status codes. + */ +enum bt_value_status { + /** Value object cannot be altered because it's frozen. */ + BT_VALUE_STATUS_FROZEN = -4, + + /** Operation cancelled. */ + BT_VALUE_STATUS_CANCELLED = -3, + + /** Invalid arguments. */ + /* -22 for compatibility with -EINVAL */ + BT_VALUE_STATUS_INVAL = -22, + + /** General error. */ + BT_VALUE_STATUS_ERROR = -1, + + /** Okay, no error. */ + BT_VALUE_STATUS_OK = 0, +}; + +/** + * Value object. + */ +struct bt_value; + +/** + * The null value object singleton. + * + * Use this everytime you need a null value object. + * + * The null value object singleton has no reference count; there's only + * one. You may directly compare any value object to the null value + * object singleton to find out if it's a null value object, or + * otherwise use bt_value_is_null(). + * + * The null value object singleton is always frozen (see + * bt_value_freeze() and bt_value_is_frozen()). + * + * Functions of this API return this when the value object is actually a + * null value object (of type #BT_VALUE_TYPE_NULL), whereas \c NULL + * means an error of some sort. + */ +extern struct bt_value *bt_value_null; + +/** + * User function type for bt_value_map_foreach(). + * + * \p object is a \em weak reference; you must pass it to + * bt_get() to get your own reference. + * + * Return \c true to continue the loop, or \c false to break it. + * + * @param key Key of map entry + * @param object Value object of map entry (weak reference) + * @param data User data + * @returns \c true to continue the loop + */ +typedef bool (* bt_value_map_foreach_cb)(const char *key, + struct bt_value *object, void *data); + +/** + * Recursively freezes the value object \p object. + * + * A frozen value object cannot be modified; it is considered immutable. + * Reference counting still works on a frozen value object though: you + * may pass a frozen value object to bt_get() and bt_put(). + * + * @param object Value object to freeze + * @returns One of #bt_value_status values; if \p object + * is already frozen, though, #BT_VALUE_STATUS_OK + * is returned anyway (i.e. this function never + * returns #BT_VALUE_STATUS_FROZEN) + * + * @see bt_value_is_frozen() + */ +extern enum bt_value_status bt_value_freeze(struct bt_value *object); + +/** + * Checks whether \p object is frozen or not. + * + * @param object Value object to check + * @returns \c true if \p object is frozen + * + * @see bt_value_freeze() + */ +extern bool bt_value_is_frozen(const struct bt_value *object); + +/** + * Returns the type of \p object. + * + * @param object Value object of which to get the type + * @returns Value object's type, or #BT_VALUE_TYPE_UNKNOWN + * on error + * + * @see #bt_value_type (value object types) + * @see bt_value_is_null() + * @see bt_value_is_bool() + * @see bt_value_is_integer() + * @see bt_value_is_float() + * @see bt_value_is_string() + * @see bt_value_is_array() + * @see bt_value_is_map() + */ +extern enum bt_value_type bt_value_get_type(const struct bt_value *object); + +/** + * Checks whether \p object is a null value object. The only valid null + * value object is \ref bt_value_null. + * + * @param object Value object to check + * @returns \c true if \p object is a null value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_null(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_NULL; +} + +/** + * Checks whether \p object is a boolean value object. + * + * @param object Value object to check + * @returns \c true if \p object is a boolean value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_bool(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_BOOL; +} + +/** + * Checks whether \p object is an integer value object. + * + * @param object Value object to check + * @returns \c true if \p object is an integer value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_integer(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_INTEGER; +} + +/** + * Checks whether \p object is a floating point number value object. + * + * @param object Value object to check + * @returns \c true if \p object is a floating point + * number value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_float(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_FLOAT; +} + +/** + * Checks whether \p object is a string value object. + * + * @param object Value object to check + * @returns \c true if \p object is a string value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_string(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_STRING; +} + +/** + * Checks whether \p object is an array value object. + * + * @param object Value object to check + * @returns \c true if \p object is an array value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_array(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_ARRAY; +} + +/** + * Checks whether \p object is a map value object. + * + * @param object Value object to check + * @returns \c true if \p object is a map value object + * + * @see bt_value_get_type() + */ +static inline +bool bt_value_is_map(const struct bt_value *object) +{ + return bt_value_get_type(object) == BT_VALUE_TYPE_MAP; +} + +/** + * Creates a boolean value object. The created boolean value object's + * initial raw value is \c false. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + * + * @see bt_value_bool_create_init() (creates an initialized + * boolean value object) + */ +extern struct bt_value *bt_value_bool_create(void); + +/** + * Creates a boolean value object with its initial raw value set to + * \p val. + * + * The created value object's reference count is set to 1. + * + * @param val Initial raw value + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_bool_create_init(bool val); + +/** + * Creates an integer value object. The created integer value object's + * initial raw value is 0. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + * + * @see bt_value_integer_create_init() (creates an initialized + * integer value object) + */ +extern struct bt_value *bt_value_integer_create(void); + +/** + * Creates an integer value object with its initial raw value set to + * \p val. + * + * The created value object's reference count is set to 1. + * + * @param val Initial raw value + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_integer_create_init(int64_t val); + +/** + * Creates a floating point number value object. The created floating + * point number value object's initial raw value is 0. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + * + * @see bt_value_float_create_init() (creates an initialized floating + * point number value object) + */ +extern struct bt_value *bt_value_float_create(void); + +/** + * Creates a floating point number value object with its initial raw + * value set to \p val. + * + * The created value object's reference count is set to 1. + * + * @param val Initial raw value + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_float_create_init(double val); + +/** + * Creates a string value object. The string value object is initially + * empty. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + * + * @see bt_value_string_create_init() (creates an initialized + * string value object) + */ +extern struct bt_value *bt_value_string_create(void); + +/** + * Creates a string value object with its initial raw value set to + * \p val. + * + * On success, \p val is \em copied. + * + * The created value object's reference count is set to 1. + * + * @param val Initial raw value (copied on success) + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_string_create_init(const char *val); + +/** + * Creates an empty array value object. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_array_create(void); + +/** + * Creates an empty map value object. + * + * The created value object's reference count is set to 1. + * + * @returns Created value object on success, or \c NULL on error + */ +extern struct bt_value *bt_value_map_create(void); + +/** + * Gets the boolean raw value of the boolean value object \p bool_obj. + * + * @param bool_obj Boolean value object + * @param val Returned boolean raw value + * @returns One of #bt_value_status values + * + * @see bt_value_bool_set() + */ +extern enum bt_value_status bt_value_bool_get( + const struct bt_value *bool_obj, bool *val); + +/** + * Sets the boolean raw value of the boolean value object \p bool_obj + * to \p val. + * + * @param bool_obj Boolean value object + * @param val New boolean raw value + * @returns One of #bt_value_status values + * + * @see bt_value_bool_get() + */ +extern enum bt_value_status bt_value_bool_set(struct bt_value *bool_obj, + bool val); + +/** + * Gets the integer raw value of the integer value object + * \p integer_obj. + * + * @param integer_obj Integer value object + * @param val Returned integer raw value + * @returns One of #bt_value_status values + * + * @see bt_value_integer_set() + */ +extern enum bt_value_status bt_value_integer_get( + const struct bt_value *integer_obj, int64_t *val); + +/** + * Sets the integer raw value of the integer value object \p integer_obj + * to \p val. + * + * @param integer_obj Integer value object + * @param val New integer raw value + * @returns One of #bt_value_status values + * + * @see bt_value_integer_get() + */ +extern enum bt_value_status bt_value_integer_set( + struct bt_value *integer_obj, int64_t val); + +/** + * Gets the floating point number raw value of the floating point number + * value object \p float_obj. + * + * @param float_obj Floating point number value object + * @param val Returned floating point number raw value + * @returns One of #bt_value_status values + * + * @see bt_value_float_set() + */ +extern enum bt_value_status bt_value_float_get( + const struct bt_value *float_obj, double *val); + +/** + * Sets the floating point number raw value of the floating point number + * value object \p float_obj to \p val. + * + * @param float_obj Floating point number value object + * @param val New floating point number raw value + * @returns One of #bt_value_status values + * + * @see bt_value_float_get() + */ +extern enum bt_value_status bt_value_float_set( + struct bt_value *float_obj, double val); + +/** + * Gets the string raw value of the string value object \p string_obj. + * The returned string is valid as long as this value object exists and + * is not modified. The ownership of the returned string is \em not + * transferred to the caller. + * + * @param string_obj String value object + * @param val Returned string raw value + * @returns One of #bt_value_status values + * + * @see bt_value_string_set() + */ +extern enum bt_value_status bt_value_string_get( + const struct bt_value *string_obj, const char **val); + +/** + * Sets the string raw value of the string value object \p string_obj to + * \p val. + * + * On success, \p val is \em copied. + * + * @param string_obj String value object + * @param val New string raw value (copied on successf) + * @returns One of #bt_value_status values + * + * @see bt_value_string_get() + */ +extern enum bt_value_status bt_value_string_set(struct bt_value *string_obj, + const char *val); + +/** + * Gets the size of the array value object \p array_obj, that is, the + * number of value objects contained in \p array_obj. + * + * @param array_obj Array value object + * @returns Array size if the return value is 0 (empty) or a + * positive value, or one of + * #bt_value_status negative values otherwise + * + * @see bt_value_array_is_empty() + */ +extern int bt_value_array_size(const struct bt_value *array_obj); + +/** + * Returns \c true if the array value object \p array_obj is empty. + * + * @param array_obj Array value object + * @returns \c true if \p array_obj is empty + * + * @see bt_value_array_size() + */ +extern bool bt_value_array_is_empty(const struct bt_value *array_obj); + +/** + * Gets the value object of the array value object \p array_obj at the + * index \p index. + * + * The returned value object's reference count is incremented, unless + * it's a null value object. + * + * @param array_obj Array value object + * @param index Index of value object to get + * @returns Value object at index \p index on + * success, or \c NULL on error + */ +extern struct bt_value *bt_value_array_get(const struct bt_value *array_obj, + size_t index); + +/** + * Appends the value object \p element_obj to the array value + * object \p array_obj. + * + * The appended value object's reference count is incremented, unless + * it's a null object. + * + * @param array_obj Array value object + * @param element_obj Value object to append + * @returns One of #bt_value_status values + * + * @see bt_value_array_append_bool() + * @see bt_value_array_append_integer() + * @see bt_value_array_append_float() + * @see bt_value_array_append_string() + * @see bt_value_array_append_empty_array() + * @see bt_value_array_append_empty_map() + */ +extern enum bt_value_status bt_value_array_append(struct bt_value *array_obj, + struct bt_value *element_obj); + +/** + * Appends the boolean raw value \p val to the array value object + * \p array_obj. This is a convenience function which creates the + * underlying boolean value object before appending it. + * + * The created boolean value object's reference count is set to 1. + * + * @param array_obj Array value object + * @param val Boolean raw value to append + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_bool( + struct bt_value *array_obj, bool val); + +/** + * Appends the integer raw value \p val to the array value object + * \p array_obj. This is a convenience function which creates the + * underlying integer value object before appending it. + * + * The created integer value object's reference count is set to 1. + * + * @param array_obj Array value object + * @param val Integer raw value to append + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_integer( + struct bt_value *array_obj, int64_t val); + +/** + * Appends the floating point number raw value \p val to the array value + * object \p array_obj. This is a convenience function which creates the + * underlying floating point number value object before appending it. + * + * The created floating point number value object's reference count is + * set to 1. + * + * @param array_obj Array value object + * @param val Floating point number raw value to append + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_float( + struct bt_value *array_obj, double val); + +/** + * Appends the string raw value \p val to the array value object + * \p array_obj. This is a convenience function which creates the + * underlying string value object before appending it. + * + * On success, \p val is \em copied. + * + * The created string value object's reference count is set to 1. + * + * @param array_obj Array value object + * @param val String raw value to append (copied on success) + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_string( + struct bt_value *array_obj, const char *val); + +/** + * Appends an empty array value object to the array value object + * \p array_obj. This is a convenience function which creates the + * underlying array value object before appending it. + * + * The created array value object's reference count is set to 1. + * + * @param array_obj Array value object + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_empty_array( + struct bt_value *array_obj); + +/** + * Appends an empty map value object to the array value object + * \p array_obj. This is a convenience function which creates the + * underlying map value object before appending it. + * + * The created map value object's reference count is set to 1. + * + * @param array_obj Array value object + * @returns One of #bt_value_status values + * + * @see bt_value_array_append() + */ +extern enum bt_value_status bt_value_array_append_empty_map( + struct bt_value *array_obj); + +/** + * Replaces the value object at index \p index of the array + * value object \p array_obj by \p element_obj. + * + * The replaced value object's reference count is decremented, unless + * it's a null value object. The reference count of \p element_obj is + * incremented, unless it's a null value object. + * + * @param array_obj Array value object + * @param index Index of value object to replace + * @param element_obj New value object at position \p index of + * \p array_obj + * @returns One of #bt_value_status values + */ +extern enum bt_value_status bt_value_array_set(struct bt_value *array_obj, + size_t index, struct bt_value *element_obj); + +/** + * Gets the size of a map value object, that is, the number of entries + * contained in a map value object. + * + * @param map_obj Map value object + * @returns Map size if the return value is 0 (empty) or a + * positive value, or one of + * #bt_value_status negative values otherwise + * + * @see bt_value_map_is_empty() + */ +extern int bt_value_map_size(const struct bt_value *map_obj); + +/** + * Returns \c true if the map value object \p map_obj is empty. + * + * @param map_obj Map value object + * @returns \c true if \p map_obj is empty + * + * @see bt_value_map_size() + */ +extern bool bt_value_map_is_empty(const struct bt_value *map_obj); + +/** + * Gets the value object associated with the key \p key within the + * map value object \p map_obj. + * + * The returned value object's reference count is incremented, unless + * it's a null value object. + * + * @param map_obj Map value object + * @param key Key of the value object to get + * @returns Value object associated with the key \p key + * on success, or \c NULL on error + */ +extern struct bt_value *bt_value_map_get(const struct bt_value *map_obj, + const char *key); + +/** + * Calls a provided user function \p cb for each value object of the map + * value object \p map_obj. + * + * The value object passed to the user function is a + * weak reference: you must call bt_get() on it to obtain your own + * reference. + * + * The key passed to the user function is only valid in the scope of + * this user function call. + * + * The user function must return \c true to continue the loop, or + * \c false to break it. + * + * @param map_obj Map value object + * @param cb User function to call back + * @param data User data passed to the user function + * @returns One of #bt_value_status values; more + * specifically, #BT_VALUE_STATUS_CANCELLED is + * returned if the loop was cancelled by the user + * function + */ +extern enum bt_value_status bt_value_map_foreach( + const struct bt_value *map_obj, bt_value_map_foreach_cb cb, + void *data); + +/** + * Returns whether or not the map value object \p map_obj contains the + * key \p key. + * + * @param map_obj Map value object + * @param key Key to check + * @returns \c true if \p map_obj contains the key \p key, + * or \c false if it doesn't have \p key or + * on error + */ +extern bool bt_value_map_has_key(const struct bt_value *map_obj, + const char *key); + +/** + * Inserts the value object \p element_obj associated with the key + * \p key into the map value object \p map_obj. If \p key exists in + * \p map_obj, the associated value object is first put, and then + * replaced by \p element_obj. + * + * On success, \p key is \em copied. + * + * The inserted value object's reference count is incremented, unless + * it's a null value object. + * + * @param map_obj Map value object + * @param key Key (copied on success) of value object to insert + * @param element_obj Value object to insert, associated with the + * key \p key + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert_bool() + * @see bt_value_map_insert_integer() + * @see bt_value_map_insert_float() + * @see bt_value_map_insert_string() + * @see bt_value_map_insert_empty_array() + * @see bt_value_map_insert_empty_map() + */ +extern enum bt_value_status bt_value_map_insert( + struct bt_value *map_obj, const char *key, + struct bt_value *element_obj); + +/** + * Inserts the boolean raw value \p val associated with the key \p key + * into the map value object \p map_obj. This is a convenience function + * which creates the underlying boolean value object before + * inserting it. + * + * On success, \p key is \em copied. + * + * The created boolean value object's reference count is set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of boolean value object + * to insert + * @param val Boolean raw value to insert, associated with + * the key \p key + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_bool( + struct bt_value *map_obj, const char *key, bool val); + +/** + * Inserts the integer raw value \p val associated with the key \p key + * into the map value object \p map_obj. This is a convenience function + * which creates the underlying integer value object before inserting it. + * + * On success, \p key is \em copied. + * + * The created integer value object's reference count is set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of integer value object + * to insert + * @param val Integer raw value to insert, associated with + * the key \p key + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_integer( + struct bt_value *map_obj, const char *key, int64_t val); + +/** + * Inserts the floating point number raw value \p val associated with + * the key \p key into the map value object \p map_obj. This is a + * convenience function which creates the underlying floating point + * number value object before inserting it. + * + * On success, \p key is \em copied. + * + * The created floating point number value object's reference count is + * set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of floating point number + * value object to insert + * @param val Floating point number raw value to insert, + * associated with the key \p key + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_float( + struct bt_value *map_obj, const char *key, double val); + +/** + * Inserts the string raw value \p val associated with the key \p key + * into the map value object \p map_obj. This is a convenience function + * which creates the underlying string value object before inserting it. + * + * On success, \p val and \p key are \em copied. + * + * The created string value object's reference count is set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of string value object + * to insert + * @param val String raw value to insert (copied on success), + * associated with the key \p key + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_string( + struct bt_value *map_obj, const char *key, const char *val); + +/** + * Inserts an empty array value object associated with the key \p key + * into the map value object \p map_obj. This is a convenience function + * which creates the underlying array value object before inserting it. + * + * On success, \p key is \em copied. + * + * The created array value object's reference count is set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of empty array value + * object to insert + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_empty_array( + struct bt_value *map_obj, const char *key); + +/** + * Inserts an empty map value object associated with the key \p key into + * the map value object \p map_obj. This is a convenience function which + * creates the underlying map value object before inserting it. + * + * On success, \p key is \em copied. + * + * The created map value object's reference count is set to 1. + * + * @param map_obj Map value object + * @param key Key (copied on success) of empty map value + * object to insert + * @returns One of #bt_value_status values + * + * @see bt_value_map_insert() + */ +extern enum bt_value_status bt_value_map_insert_empty_map( + struct bt_value *map_obj, const char *key); + +/** + * Creates a deep copy of the value object \p object. + * + * The created value object's reference count is set to 1, unless + * \p object is a null value object. + * + * Copying a frozen value object is allowed: the resulting copy is + * \em not frozen. + * + * @param object Value object to copy + * @returns Deep copy of \p object on success, or \c NULL + * on error + */ +extern struct bt_value *bt_value_copy(const struct bt_value *object); + +/** + * Compares the value objects \p object_a and \p object_b and returns + * \c true if they have the same \em content (raw values). + * + * @param object_a Value object A + * @param object_b Value object B + * @returns \c true if \p object_a and \p object_b have the + * same content, or \c false if they differ or on + * error + */ +extern bool bt_value_compare(const struct bt_value *object_a, + const struct bt_value *object_b); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_VALUES_H */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 007abb78..8096d789 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -9,7 +9,9 @@ libbabeltrace_la_SOURCES = babeltrace.c \ context.c \ trace-handle.c \ trace-collection.c \ - registry.c + registry.c \ + values.c \ + ref.c libbabeltrace_la_LDFLAGS = -version-info $(BABELTRACE_LIBRARY_VERSION) diff --git a/lib/ref.c b/lib/ref.c new file mode 100644 index 00000000..ac058013 --- /dev/null +++ b/lib/ref.c @@ -0,0 +1,55 @@ +/* + * ref.c: reference counting + * + * Babeltrace Library + * + * Copyright (c) 2015 Jérémie Galarneau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +void *bt_get(void *ptr) +{ + struct bt_object *obj = ptr; + + if (!obj) { + goto end; + } + + if (obj->parent && bt_object_get_ref_count(obj) == 0) { + bt_get(obj->parent); + } + bt_ref_get(&obj->ref_count); +end: + return obj; +} + +void bt_put(void *ptr) +{ + struct bt_object *obj = ptr; + + if (!obj) { + return; + } + + bt_ref_put(&obj->ref_count); +} diff --git a/lib/values.c b/lib/values.c new file mode 100644 index 00000000..5e7f55c6 --- /dev/null +++ b/lib/values.c @@ -0,0 +1,1202 @@ +/* + * Values.c: value objects + * + * Babeltrace Library + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BT_VALUE_FROM_CONCRETE(_concrete) ((struct bt_value *) (_concrete)) +#define BT_VALUE_TO_BOOL(_base) ((struct bt_value_bool *) (_base)) +#define BT_VALUE_TO_INTEGER(_base) ((struct bt_value_integer *) (_base)) +#define BT_VALUE_TO_FLOAT(_base) ((struct bt_value_float *) (_base)) +#define BT_VALUE_TO_STRING(_base) ((struct bt_value_string *) (_base)) +#define BT_VALUE_TO_ARRAY(_base) ((struct bt_value_array *) (_base)) +#define BT_VALUE_TO_MAP(_base) ((struct bt_value_map *) (_base)) + +struct bt_value { + struct bt_object base; + enum bt_value_type type; + bool is_frozen; +}; + +static +struct bt_value bt_value_null_instance = { + .type = BT_VALUE_TYPE_NULL, + .is_frozen = true, +}; + +struct bt_value *bt_value_null = &bt_value_null_instance; + +struct bt_value_bool { + struct bt_value base; + bool value; +}; + +struct bt_value_integer { + struct bt_value base; + int64_t value; +}; + +struct bt_value_float { + struct bt_value base; + double value; +}; + +struct bt_value_string { + struct bt_value base; + GString *gstr; +}; + +struct bt_value_array { + struct bt_value base; + GPtrArray *garray; +}; + +struct bt_value_map { + struct bt_value base; + GHashTable *ght; +}; + +static +void bt_value_destroy(struct bt_object *obj); + +static +void bt_value_string_destroy(struct bt_value *object) +{ + g_string_free(BT_VALUE_TO_STRING(object)->gstr, TRUE); +} + +static +void bt_value_array_destroy(struct bt_value *object) +{ + /* + * Pointer array's registered value destructor will take care + * of putting each contained object. + */ + g_ptr_array_free(BT_VALUE_TO_ARRAY(object)->garray, TRUE); +} + +static +void bt_value_map_destroy(struct bt_value *object) +{ + /* + * Hash table's registered value destructor will take care of + * putting each contained object. Keys are GQuarks and cannot + * be destroyed anyway. + */ + g_hash_table_destroy(BT_VALUE_TO_MAP(object)->ght); +} + +static +void (* const destroy_funcs[])(struct bt_value *) = { + [BT_VALUE_TYPE_NULL] = NULL, + [BT_VALUE_TYPE_BOOL] = NULL, + [BT_VALUE_TYPE_INTEGER] = NULL, + [BT_VALUE_TYPE_FLOAT] = NULL, + [BT_VALUE_TYPE_STRING] = bt_value_string_destroy, + [BT_VALUE_TYPE_ARRAY] = bt_value_array_destroy, + [BT_VALUE_TYPE_MAP] = bt_value_map_destroy, +}; + +static +struct bt_value *bt_value_null_copy(const struct bt_value *null_obj) +{ + return bt_value_null; +} + +static +struct bt_value *bt_value_bool_copy(const struct bt_value *bool_obj) +{ + return bt_value_bool_create_init(BT_VALUE_TO_BOOL(bool_obj)->value); +} + +static +struct bt_value *bt_value_integer_copy(const struct bt_value *integer_obj) +{ + return bt_value_integer_create_init( + BT_VALUE_TO_INTEGER(integer_obj)->value); +} + +static +struct bt_value *bt_value_float_copy(const struct bt_value *float_obj) +{ + return bt_value_float_create_init( + BT_VALUE_TO_FLOAT(float_obj)->value); +} + +static +struct bt_value *bt_value_string_copy(const struct bt_value *string_obj) +{ + return bt_value_string_create_init( + BT_VALUE_TO_STRING(string_obj)->gstr->str); +} + +static +struct bt_value *bt_value_array_copy(const struct bt_value *array_obj) +{ + int i; + int ret; + struct bt_value *copy_obj; + struct bt_value_array *typed_array_obj; + + typed_array_obj = BT_VALUE_TO_ARRAY(array_obj); + copy_obj = bt_value_array_create(); + + if (!copy_obj) { + goto end; + } + + for (i = 0; i < typed_array_obj->garray->len; ++i) { + struct bt_value *element_obj_copy; + struct bt_value *element_obj = bt_value_array_get(array_obj, i); + + if (!element_obj) { + BT_PUT(copy_obj); + goto end; + } + + element_obj_copy = bt_value_copy(element_obj); + BT_PUT(element_obj); + + if (!element_obj_copy) { + BT_PUT(copy_obj); + goto end; + } + + ret = bt_value_array_append(copy_obj, element_obj_copy); + BT_PUT(element_obj_copy); + + if (ret) { + BT_PUT(copy_obj); + goto end; + } + } + +end: + return copy_obj; +} + +static +struct bt_value *bt_value_map_copy(const struct bt_value *map_obj) +{ + int ret; + GHashTableIter iter; + gpointer key, element_obj; + struct bt_value *copy_obj; + struct bt_value *element_obj_copy; + struct bt_value_map *typed_map_obj; + + typed_map_obj = BT_VALUE_TO_MAP(map_obj); + copy_obj = bt_value_map_create(); + + if (!copy_obj) { + goto end; + } + + g_hash_table_iter_init(&iter, typed_map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + const char *key_str = g_quark_to_string((unsigned long) key); + + element_obj_copy = bt_value_copy(element_obj); + + if (!element_obj_copy) { + BT_PUT(copy_obj); + goto end; + } + + ret = bt_value_map_insert(copy_obj, key_str, element_obj_copy); + BT_PUT(element_obj_copy); + + if (ret) { + BT_PUT(copy_obj); + goto end; + } + } + +end: + return copy_obj; +} + +static +struct bt_value *(* const copy_funcs[])(const struct bt_value *) = { + [BT_VALUE_TYPE_NULL] = bt_value_null_copy, + [BT_VALUE_TYPE_BOOL] = bt_value_bool_copy, + [BT_VALUE_TYPE_INTEGER] = bt_value_integer_copy, + [BT_VALUE_TYPE_FLOAT] = bt_value_float_copy, + [BT_VALUE_TYPE_STRING] = bt_value_string_copy, + [BT_VALUE_TYPE_ARRAY] = bt_value_array_copy, + [BT_VALUE_TYPE_MAP] = bt_value_map_copy, +}; + +static +bool bt_value_null_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + /* + * Always true since bt_value_compare() already checks if both + * object_a and object_b have the same type, and in the case of + * null value objects, they're always the same if it is so. + */ + return true; +} + +static +bool bt_value_bool_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + return BT_VALUE_TO_BOOL(object_a)->value == + BT_VALUE_TO_BOOL(object_b)->value; +} + +static +bool bt_value_integer_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + return BT_VALUE_TO_INTEGER(object_a)->value == + BT_VALUE_TO_INTEGER(object_b)->value; +} + +static +bool bt_value_float_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + return BT_VALUE_TO_FLOAT(object_a)->value == + BT_VALUE_TO_FLOAT(object_b)->value; +} + +static +bool bt_value_string_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + return !strcmp(BT_VALUE_TO_STRING(object_a)->gstr->str, + BT_VALUE_TO_STRING(object_b)->gstr->str); +} + +static +bool bt_value_array_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + int i; + bool ret = true; + const struct bt_value_array *array_obj_a = + BT_VALUE_TO_ARRAY(object_a); + + if (bt_value_array_size(object_a) != bt_value_array_size(object_b)) { + ret = false; + goto end; + } + + for (i = 0; i < array_obj_a->garray->len; ++i) { + struct bt_value *element_obj_a; + struct bt_value *element_obj_b; + + element_obj_a = bt_value_array_get(object_a, i); + element_obj_b = bt_value_array_get(object_b, i); + + if (!bt_value_compare(element_obj_a, element_obj_b)) { + BT_PUT(element_obj_a); + BT_PUT(element_obj_b); + ret = false; + goto end; + } + + BT_PUT(element_obj_a); + BT_PUT(element_obj_b); + } + +end: + return ret; +} + +static +bool bt_value_map_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + bool ret = true; + GHashTableIter iter; + gpointer key, element_obj_a; + const struct bt_value_map *map_obj_a = BT_VALUE_TO_MAP(object_a); + + if (bt_value_map_size(object_a) != bt_value_map_size(object_b)) { + ret = false; + goto end; + } + + g_hash_table_iter_init(&iter, map_obj_a->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) { + struct bt_value *element_obj_b; + const char *key_str = g_quark_to_string((unsigned long) key); + + element_obj_b = bt_value_map_get(object_b, key_str); + + if (!bt_value_compare(element_obj_a, element_obj_b)) { + BT_PUT(element_obj_b); + ret = false; + goto end; + } + + BT_PUT(element_obj_b); + } + +end: + return ret; +} + +static +bool (* const compare_funcs[])(const struct bt_value *, + const struct bt_value *) = { + [BT_VALUE_TYPE_NULL] = bt_value_null_compare, + [BT_VALUE_TYPE_BOOL] = bt_value_bool_compare, + [BT_VALUE_TYPE_INTEGER] = bt_value_integer_compare, + [BT_VALUE_TYPE_FLOAT] = bt_value_float_compare, + [BT_VALUE_TYPE_STRING] = bt_value_string_compare, + [BT_VALUE_TYPE_ARRAY] = bt_value_array_compare, + [BT_VALUE_TYPE_MAP] = bt_value_map_compare, +}; + +void bt_value_null_freeze(struct bt_value *object) +{ +} + +void bt_value_generic_freeze(struct bt_value *object) +{ + object->is_frozen = true; +} + +void bt_value_array_freeze(struct bt_value *object) +{ + int i; + struct bt_value_array *typed_array_obj = + BT_VALUE_TO_ARRAY(object); + + for (i = 0; i < typed_array_obj->garray->len; ++i) { + struct bt_value *element_obj = + g_ptr_array_index(typed_array_obj->garray, i); + + bt_value_freeze(element_obj); + } + + bt_value_generic_freeze(object); +} + +void bt_value_map_freeze(struct bt_value *object) +{ + GHashTableIter iter; + gpointer key, element_obj; + const struct bt_value_map *map_obj = BT_VALUE_TO_MAP(object); + + g_hash_table_iter_init(&iter, map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + bt_value_freeze(element_obj); + } + + bt_value_generic_freeze(object); +} + +static +void (* const freeze_funcs[])(struct bt_value *) = { + [BT_VALUE_TYPE_NULL] = bt_value_null_freeze, + [BT_VALUE_TYPE_BOOL] = bt_value_generic_freeze, + [BT_VALUE_TYPE_INTEGER] = bt_value_generic_freeze, + [BT_VALUE_TYPE_FLOAT] = bt_value_generic_freeze, + [BT_VALUE_TYPE_STRING] = bt_value_generic_freeze, + [BT_VALUE_TYPE_ARRAY] = bt_value_array_freeze, + [BT_VALUE_TYPE_MAP] = bt_value_map_freeze, +}; + +static +void bt_value_destroy(struct bt_object *obj) +{ + struct bt_value *value; + + value = container_of(obj, struct bt_value, base); + assert(value->type != BT_VALUE_TYPE_UNKNOWN); + + if (bt_value_is_null(value)) { + return; + } + + if (destroy_funcs[value->type]) { + destroy_funcs[value->type](value); + } + + g_free(value); +} + +enum bt_value_status bt_value_freeze(struct bt_value *object) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + + if (!object) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + freeze_funcs[object->type](object); + +end: + return ret; +} + +bool bt_value_is_frozen(const struct bt_value *object) +{ + return object && object->is_frozen; +} + +enum bt_value_type bt_value_get_type(const struct bt_value *object) +{ + if (!object) { + return BT_VALUE_TYPE_UNKNOWN; + } + + return object->type; +} + +static +struct bt_value bt_value_create_base(enum bt_value_type type) +{ + struct bt_value base; + + base.type = type; + base.is_frozen = false; + bt_object_init(&base, bt_value_destroy); + + return base; +} + +struct bt_value *bt_value_bool_create_init(bool val) +{ + struct bt_value_bool *bool_obj; + + bool_obj = g_new0(struct bt_value_bool, 1); + + if (!bool_obj) { + goto end; + } + + bool_obj->base = bt_value_create_base(BT_VALUE_TYPE_BOOL); + bool_obj->value = val; + +end: + return BT_VALUE_FROM_CONCRETE(bool_obj); +} + +struct bt_value *bt_value_bool_create(void) +{ + return bt_value_bool_create_init(false); +} + +struct bt_value *bt_value_integer_create_init(int64_t val) +{ + struct bt_value_integer *integer_obj; + + integer_obj = g_new0(struct bt_value_integer, 1); + + if (!integer_obj) { + goto end; + } + + integer_obj->base = bt_value_create_base(BT_VALUE_TYPE_INTEGER); + integer_obj->value = val; + +end: + return BT_VALUE_FROM_CONCRETE(integer_obj); +} + +struct bt_value *bt_value_integer_create(void) +{ + return bt_value_integer_create_init(0); +} + +struct bt_value *bt_value_float_create_init(double val) +{ + struct bt_value_float *float_obj; + + float_obj = g_new0(struct bt_value_float, 1); + + if (!float_obj) { + goto end; + } + + float_obj->base = bt_value_create_base(BT_VALUE_TYPE_FLOAT); + float_obj->value = val; + +end: + return BT_VALUE_FROM_CONCRETE(float_obj); +} + +struct bt_value *bt_value_float_create(void) +{ + return bt_value_float_create_init(0.); +} + +struct bt_value *bt_value_string_create_init(const char *val) +{ + struct bt_value_string *string_obj = NULL; + + if (!val) { + goto end; + } + + string_obj = g_new0(struct bt_value_string, 1); + + if (!string_obj) { + goto end; + } + + string_obj->base = bt_value_create_base(BT_VALUE_TYPE_STRING); + string_obj->gstr = g_string_new(val); + + if (!string_obj->gstr) { + g_free(string_obj); + string_obj = NULL; + goto end; + } + +end: + return BT_VALUE_FROM_CONCRETE(string_obj); +} + +struct bt_value *bt_value_string_create(void) +{ + return bt_value_string_create_init(""); +} + +struct bt_value *bt_value_array_create(void) +{ + struct bt_value_array *array_obj; + + array_obj = g_new0(struct bt_value_array, 1); + + if (!array_obj) { + goto end; + } + + array_obj->base = bt_value_create_base(BT_VALUE_TYPE_ARRAY); + array_obj->garray = babeltrace_g_ptr_array_new_full(0, + (GDestroyNotify) bt_put); + + if (!array_obj->garray) { + g_free(array_obj); + array_obj = NULL; + goto end; + } + +end: + return BT_VALUE_FROM_CONCRETE(array_obj); +} + +struct bt_value *bt_value_map_create(void) +{ + struct bt_value_map *map_obj; + + map_obj = g_new0(struct bt_value_map, 1); + + if (!map_obj) { + goto end; + } + + map_obj->base = bt_value_create_base(BT_VALUE_TYPE_MAP); + map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) bt_put); + + if (!map_obj->ght) { + g_free(map_obj); + map_obj = NULL; + goto end; + } + +end: + return BT_VALUE_FROM_CONCRETE(map_obj); +} + +enum bt_value_status bt_value_bool_get(const struct bt_value *bool_obj, + bool *val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_bool *typed_bool_obj = BT_VALUE_TO_BOOL(bool_obj); + + if (!bool_obj || !bt_value_is_bool(bool_obj) || !val) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + *val = typed_bool_obj->value; + +end: + return ret; +} + +enum bt_value_status bt_value_bool_set(struct bt_value *bool_obj, bool val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_bool *typed_bool_obj = BT_VALUE_TO_BOOL(bool_obj); + + if (!bool_obj || !bt_value_is_bool(bool_obj)) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (bool_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + typed_bool_obj->value = val; + +end: + return ret; +} + +enum bt_value_status bt_value_integer_get(const struct bt_value *integer_obj, + int64_t *val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_integer *typed_integer_obj = + BT_VALUE_TO_INTEGER(integer_obj); + + if (!integer_obj || !bt_value_is_integer(integer_obj) || !val) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + *val = typed_integer_obj->value; + +end: + return ret; +} + +enum bt_value_status bt_value_integer_set(struct bt_value *integer_obj, + int64_t val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_integer *typed_integer_obj = + BT_VALUE_TO_INTEGER(integer_obj); + + if (!integer_obj || !bt_value_is_integer(integer_obj)) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (integer_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + typed_integer_obj->value = val; + +end: + return ret; +} + +enum bt_value_status bt_value_float_get(const struct bt_value *float_obj, + double *val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_float *typed_float_obj = + BT_VALUE_TO_FLOAT(float_obj); + + if (!float_obj || !bt_value_is_float(float_obj) || !val) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + *val = typed_float_obj->value; + +end: + return ret; +} + +enum bt_value_status bt_value_float_set(struct bt_value *float_obj, + double val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_float *typed_float_obj = + BT_VALUE_TO_FLOAT(float_obj); + + if (!float_obj || !bt_value_is_float(float_obj)) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (float_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + typed_float_obj->value = val; + +end: + return ret; +} + +enum bt_value_status bt_value_string_get(const struct bt_value *string_obj, + const char **val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_string *typed_string_obj = + BT_VALUE_TO_STRING(string_obj); + + if (!string_obj || !bt_value_is_string(string_obj) || !val) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + *val = typed_string_obj->gstr->str; + +end: + return ret; +} + +enum bt_value_status bt_value_string_set(struct bt_value *string_obj, + const char *val) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_string *typed_string_obj = + BT_VALUE_TO_STRING(string_obj); + + if (!string_obj || !bt_value_is_string(string_obj) || !val) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (string_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + g_string_assign(typed_string_obj->gstr, val); + +end: + return ret; +} + +int bt_value_array_size(const struct bt_value *array_obj) +{ + int ret; + struct bt_value_array *typed_array_obj = + BT_VALUE_TO_ARRAY(array_obj); + + if (!array_obj || !bt_value_is_array(array_obj)) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + ret = (int) typed_array_obj->garray->len; + +end: + return ret; +} + +bool bt_value_array_is_empty(const struct bt_value *array_obj) +{ + return bt_value_array_size(array_obj) == 0; +} + +struct bt_value *bt_value_array_get(const struct bt_value *array_obj, + size_t index) +{ + struct bt_value *ret; + struct bt_value_array *typed_array_obj = + BT_VALUE_TO_ARRAY(array_obj); + + if (!array_obj || !bt_value_is_array(array_obj) || + index >= typed_array_obj->garray->len) { + ret = NULL; + goto end; + } + + ret = g_ptr_array_index(typed_array_obj->garray, index); + bt_get(ret); + +end: + return ret; +} + +enum bt_value_status bt_value_array_append(struct bt_value *array_obj, + struct bt_value *element_obj) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_array *typed_array_obj = + BT_VALUE_TO_ARRAY(array_obj); + + if (!array_obj || !bt_value_is_array(array_obj) || !element_obj) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (array_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + g_ptr_array_add(typed_array_obj->garray, element_obj); + bt_get(element_obj); + +end: + return ret; +} + +enum bt_value_status bt_value_array_append_bool(struct bt_value *array_obj, + bool val) +{ + enum bt_value_status ret; + struct bt_value *bool_obj = NULL; + + bool_obj = bt_value_bool_create_init(val); + ret = bt_value_array_append(array_obj, bool_obj); + bt_put(bool_obj); + + return ret; +} + +enum bt_value_status bt_value_array_append_integer( + struct bt_value *array_obj, int64_t val) +{ + enum bt_value_status ret; + struct bt_value *integer_obj = NULL; + + integer_obj = bt_value_integer_create_init(val); + ret = bt_value_array_append(array_obj, integer_obj); + bt_put(integer_obj); + + return ret; +} + +enum bt_value_status bt_value_array_append_float(struct bt_value *array_obj, + double val) +{ + enum bt_value_status ret; + struct bt_value *float_obj = NULL; + + float_obj = bt_value_float_create_init(val); + ret = bt_value_array_append(array_obj, float_obj); + bt_put(float_obj); + + return ret; +} + +enum bt_value_status bt_value_array_append_string(struct bt_value *array_obj, + const char *val) +{ + enum bt_value_status ret; + struct bt_value *string_obj = NULL; + + string_obj = bt_value_string_create_init(val); + ret = bt_value_array_append(array_obj, string_obj); + bt_put(string_obj); + + return ret; +} + +enum bt_value_status bt_value_array_append_empty_array( + struct bt_value *array_obj) +{ + enum bt_value_status ret; + struct bt_value *empty_array_obj = NULL; + + empty_array_obj = bt_value_array_create(); + ret = bt_value_array_append(array_obj, empty_array_obj); + bt_put(empty_array_obj); + + return ret; +} + +enum bt_value_status bt_value_array_append_empty_map(struct bt_value *array_obj) +{ + enum bt_value_status ret; + struct bt_value *map_obj = NULL; + + map_obj = bt_value_map_create(); + ret = bt_value_array_append(array_obj, map_obj); + bt_put(map_obj); + + return ret; +} + +enum bt_value_status bt_value_array_set(struct bt_value *array_obj, + size_t index, struct bt_value *element_obj) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_array *typed_array_obj = + BT_VALUE_TO_ARRAY(array_obj); + + if (!array_obj || !bt_value_is_array(array_obj) || !element_obj || + index >= typed_array_obj->garray->len) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (array_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + bt_put(g_ptr_array_index(typed_array_obj->garray, index)); + g_ptr_array_index(typed_array_obj->garray, index) = element_obj; + bt_get(element_obj); + +end: + return ret; +} + +int bt_value_map_size(const struct bt_value *map_obj) +{ + int ret; + struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj); + + if (!map_obj || !bt_value_is_map(map_obj)) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + ret = (int) g_hash_table_size(typed_map_obj->ght); + +end: + return ret; +} + +bool bt_value_map_is_empty(const struct bt_value *map_obj) +{ + return bt_value_map_size(map_obj) == 0; +} + +struct bt_value *bt_value_map_get(const struct bt_value *map_obj, + const char *key) +{ + GQuark quark; + struct bt_value *ret; + struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj); + + if (!map_obj || !bt_value_is_map(map_obj) || !key) { + ret = NULL; + goto end; + } + + quark = g_quark_from_string(key); + ret = g_hash_table_lookup(typed_map_obj->ght, GUINT_TO_POINTER(quark)); + + if (ret) { + bt_get(ret); + } + +end: + return ret; +} + +bool bt_value_map_has_key(const struct bt_value *map_obj, const char *key) +{ + bool ret; + GQuark quark; + struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj); + + if (!map_obj || !bt_value_is_map(map_obj) || !key) { + ret = false; + goto end; + } + + quark = g_quark_from_string(key); + ret = babeltrace_g_hash_table_contains(typed_map_obj->ght, + GUINT_TO_POINTER(quark)); + +end: + return ret; +} + +enum bt_value_status bt_value_map_insert(struct bt_value *map_obj, + const char *key, struct bt_value *element_obj) +{ + GQuark quark; + enum bt_value_status ret = BT_VALUE_STATUS_OK; + struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj); + + if (!map_obj || !bt_value_is_map(map_obj) || !key || !element_obj) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + if (map_obj->is_frozen) { + ret = BT_VALUE_STATUS_FROZEN; + goto end; + } + + quark = g_quark_from_string(key); + g_hash_table_insert(typed_map_obj->ght, + GUINT_TO_POINTER(quark), element_obj); + bt_get(element_obj); + +end: + return ret; +} + +enum bt_value_status bt_value_map_insert_bool(struct bt_value *map_obj, + const char *key, bool val) +{ + enum bt_value_status ret; + struct bt_value *bool_obj = NULL; + + bool_obj = bt_value_bool_create_init(val); + ret = bt_value_map_insert(map_obj, key, bool_obj); + bt_put(bool_obj); + + return ret; +} + +enum bt_value_status bt_value_map_insert_integer(struct bt_value *map_obj, + const char *key, int64_t val) +{ + enum bt_value_status ret; + struct bt_value *integer_obj = NULL; + + integer_obj = bt_value_integer_create_init(val); + ret = bt_value_map_insert(map_obj, key, integer_obj); + bt_put(integer_obj); + + return ret; +} + +enum bt_value_status bt_value_map_insert_float(struct bt_value *map_obj, + const char *key, double val) +{ + enum bt_value_status ret; + struct bt_value *float_obj = NULL; + + float_obj = bt_value_float_create_init(val); + ret = bt_value_map_insert(map_obj, key, float_obj); + bt_put(float_obj); + + return ret; +} + +enum bt_value_status bt_value_map_insert_string(struct bt_value *map_obj, + const char *key, const char *val) +{ + enum bt_value_status ret; + struct bt_value *string_obj = NULL; + + string_obj = bt_value_string_create_init(val); + ret = bt_value_map_insert(map_obj, key, string_obj); + bt_put(string_obj); + + return ret; +} + +enum bt_value_status bt_value_map_insert_empty_array(struct bt_value *map_obj, + const char *key) +{ + enum bt_value_status ret; + struct bt_value *array_obj = NULL; + + array_obj = bt_value_array_create(); + ret = bt_value_map_insert(map_obj, key, array_obj); + bt_put(array_obj); + + return ret; +} + +enum bt_value_status bt_value_map_insert_empty_map(struct bt_value *map_obj, + const char *key) +{ + enum bt_value_status ret; + struct bt_value *empty_map_obj = NULL; + + empty_map_obj = bt_value_map_create(); + ret = bt_value_map_insert(map_obj, key, empty_map_obj); + bt_put(empty_map_obj); + + return ret; +} + +enum bt_value_status bt_value_map_foreach(const struct bt_value *map_obj, + bt_value_map_foreach_cb cb, void *data) +{ + enum bt_value_status ret = BT_VALUE_STATUS_OK; + gpointer key, element_obj; + GHashTableIter iter; + struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj); + + if (!map_obj || !bt_value_is_map(map_obj) || !cb) { + ret = BT_VALUE_STATUS_INVAL; + goto end; + } + + g_hash_table_iter_init(&iter, typed_map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + const char *key_str = g_quark_to_string((unsigned long) key); + + if (!cb(key_str, element_obj, data)) { + ret = BT_VALUE_STATUS_CANCELLED; + break; + } + } + +end: + return ret; +} + +struct bt_value *bt_value_copy(const struct bt_value *object) +{ + struct bt_value *copy_obj = NULL; + + if (!object) { + goto end; + } + + copy_obj = copy_funcs[object->type](object); + +end: + return copy_obj; +} + +bool bt_value_compare(const struct bt_value *object_a, + const struct bt_value *object_b) +{ + bool ret = false; + + if (!object_a || !object_b) { + goto end; + } + + if (object_a->type != object_b->type) { + goto end; + } + + ret = compare_funcs[object_a->type](object_a, object_b); + +end: + return ret; +} diff --git a/tests/lib/test_ctf_writer.c b/tests/lib/test_ctf_writer.c index ee979f0b..961df795 100644 --- a/tests/lib/test_ctf_writer.c +++ b/tests/lib/test_ctf_writer.c @@ -507,8 +507,6 @@ void type_field_tests() struct bt_ctf_field_type *uint_12_type = bt_ctf_field_type_integer_create(12); struct bt_ctf_field_type *enumeration_type; - struct bt_ctf_field_type *enumeration_sequence_type; - struct bt_ctf_field_type *enumeration_array_type; ok(uint_12_type, "Create an unsigned integer type"); ok(bt_ctf_field_type_integer_set_base(uint_12_type, @@ -613,17 +611,6 @@ void type_field_tests() enumeration_type = bt_ctf_field_type_enumeration_create(uint_12_type); ok(enumeration_type, "Create an enumeration type with an unsigned 12-bit integer as container"); - enumeration_sequence_type = bt_ctf_field_type_sequence_create( - enumeration_type, "count"); - ok(!enumeration_sequence_type, - "Check enumeration types are validated when creating a sequence"); - enumeration_array_type = bt_ctf_field_type_array_create( - enumeration_type, 10); - ok(!enumeration_array_type, - "Check enumeration types are validated when creating an array"); - ok(bt_ctf_field_type_structure_add_field(composite_structure_type, - enumeration_type, "enumeration"), - "Check enumeration types are validated when adding them as structure members"); enumeration = bt_ctf_field_create(enumeration_type); ok(!enumeration, "Check enumeration types are validated before instantiation"); @@ -640,8 +627,6 @@ void type_field_tests() bt_ctf_field_type_put(int_16_type); bt_ctf_field_type_put(uint_12_type); bt_ctf_field_type_put(enumeration_type); - bt_ctf_field_type_put(enumeration_sequence_type); - bt_ctf_field_type_put(enumeration_array_type); } void packet_resize_test(struct bt_ctf_stream_class *stream_class, -- 2.34.1