From: Julien Desfossez Date: Wed, 16 Nov 2016 19:33:42 +0000 (-0500) Subject: CTF Writer sink X-Git-Tag: v2.0.0-pre1~619 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=bc506aa5ed05112f88f00cb451cba8fdf3abcb01 CTF Writer sink This plugin outputs CTF traces based on what it receives as input. Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- diff --git a/configure.ac b/configure.ac index 68d4668b..98237c58 100644 --- a/configure.ac +++ b/configure.ac @@ -424,6 +424,7 @@ AC_CONFIG_FILES([ plugins/muxer/Makefile plugins/text/Makefile plugins/trimmer/Makefile + plugins/writer/Makefile babeltrace.pc babeltrace-ctf.pc ]) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index ec8418f0..e73ad9d1 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1 +1 @@ -SUBDIRS = ctf text muxer trimmer +SUBDIRS = ctf text muxer trimmer writer diff --git a/plugins/writer/Makefile.am b/plugins/writer/Makefile.am new file mode 100644 index 00000000..33116567 --- /dev/null +++ b/plugins/writer/Makefile.am @@ -0,0 +1,17 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include + +SUBDIRS = . + +plugindir = "$(PLUGINSDIR)" +plugin_LTLIBRARIES = libbabeltrace-plugin-ctf-writer.la + +# ctf-writer plugin +libbabeltrace_plugin_ctf_writer_la_SOURCES = \ + writer.h writer.c write.c + +libbabeltrace_plugin_ctf_writer_la_LDFLAGS = \ + -version-info $(BABELTRACE_LIBRARY_VERSION) + +libbabeltrace_plugin_ctf_writer_la_LIBADD = \ + $(top_builddir)/lib/libbabeltrace.la \ + $(top_builddir)/formats/ctf/libbabeltrace-ctf.la diff --git a/plugins/writer/write.c b/plugins/writer/write.c new file mode 100644 index 00000000..442c0c48 --- /dev/null +++ b/plugins/writer/write.c @@ -0,0 +1,1180 @@ +/* + * writer.c + * + * Babeltrace CTF Writer Output Plugin Event Handling + * + * Copyright 2016 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 "writer.h" + +static +void tmp_clock(struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *writer_stream_class, + struct bt_ctf_clock *writer_clock) +{ + const char *clock_description = "This is a test clock"; + const uint64_t frequency = 1000000000ULL; + const uint64_t offset_s = 1351530929945824323; + const uint64_t precision = 10; + const int is_absolute = 0xFF; + + bt_ctf_clock_set_description(writer_clock, clock_description); + bt_ctf_clock_set_frequency(writer_clock, frequency); + bt_ctf_clock_set_offset_s(writer_clock, offset_s); + bt_ctf_clock_set_precision(writer_clock, precision); + bt_ctf_clock_set_is_absolute(writer_clock, is_absolute); + bt_ctf_writer_add_clock(writer, writer_clock); + bt_ctf_stream_class_set_clock(writer_stream_class, writer_clock); +} + +static +enum bt_component_status copy_clock(FILE *err, struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *writer_stream_class, + struct bt_ctf_clock *clock, + struct bt_ctf_clock *writer_clock) +{ + enum bt_component_status ret; + int64_t offset, offset_s; + int int_ret; + uint64_t u64_ret; + const char *name, *description; + + name = bt_ctf_clock_get_name(clock); + if (!name) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + writer_clock = bt_ctf_clock_create(name); + if (!writer_clock) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + description = bt_ctf_clock_get_description(clock); + if (!description) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_set_description(writer_clock, + description); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + u64_ret = bt_ctf_clock_get_frequency(clock); + if (u64_ret == -1ULL) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + int_ret = bt_ctf_clock_set_frequency(writer_clock, u64_ret); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + u64_ret = bt_ctf_clock_get_precision(clock); + if (u64_ret == -1ULL) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + int_ret = bt_ctf_clock_set_precision(writer_clock, u64_ret); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_get_offset_s(clock, &offset_s); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_set_offset_s(writer_clock, offset_s); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_get_offset(clock, &offset); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_set_offset(writer_clock, offset); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + int_ret = bt_ctf_clock_get_is_absolute(clock); + if (int_ret == -1) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + int_ret = bt_ctf_clock_set_is_absolute(writer_clock, int_ret); + if (int_ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + ret = bt_ctf_writer_add_clock(writer, writer_clock); + if (ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + + ret = bt_ctf_stream_class_set_clock(writer_stream_class, + writer_clock); + if (ret != 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_destroy; + } + /* + * Ownership transferred to the writer and the stream_class. + */ + bt_put(writer_clock); + + ret = BT_COMPONENT_STATUS_OK; + goto end; + +end_destroy: + bt_put(writer_clock); +end: + return ret; +} + +static +struct bt_ctf_event_class *copy_event_class(FILE *err, struct bt_ctf_event_class *event_class) +{ + struct bt_ctf_event_class *writer_event_class = NULL; + const char *name; + struct bt_ctf_field_type *context; + int count, i, ret; + + name = bt_ctf_event_class_get_name(event_class); + if (!name) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + writer_event_class = bt_ctf_event_class_create(name); + if (!writer_event_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + count = bt_ctf_event_class_get_attribute_count(event_class); + for (i = 0; i < count; i++) { + const char *attr_name; + struct bt_value *attr_value; + int ret; + + attr_name = bt_ctf_event_class_get_attribute_name(event_class, i); + if (!attr_name) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + BT_PUT(writer_event_class); + goto end; + } + attr_value = bt_ctf_event_class_get_attribute_value(event_class, i); + if (!attr_value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + BT_PUT(writer_event_class); + goto end; + } + + ret = bt_ctf_event_class_set_attribute(writer_event_class, + attr_name, attr_value); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + BT_PUT(writer_event_class); + goto end; + } + } + + context = bt_ctf_event_class_get_context_type(event_class); + if (!context) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_event_class_set_context_type(writer_event_class, context); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + count = bt_ctf_event_class_get_field_count(event_class); + for (i = 0; i < count; i++) { + const char *field_name; + struct bt_ctf_field_type *field_type; + int ret; + + ret = bt_ctf_event_class_get_field(event_class, &field_name, + &field_type, i); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + BT_PUT(writer_event_class); + goto end; + } + + ret = bt_ctf_event_class_add_field(writer_event_class, field_type, + field_name); + if (ret < 0) { + fprintf(err, "[error] Cannot add field %s\n", field_name); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + bt_put(field_type); + BT_PUT(writer_event_class); + goto end; + } + bt_put(field_type); + } + +end: + return writer_event_class; +} + +static +enum bt_component_status copy_event_classes(FILE *err, + struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_stream_class *writer_stream_class) +{ + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + int count, i; + + count = bt_ctf_stream_class_get_event_class_count(stream_class); + if (count < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + for (i = 0; i < count; i++) { + struct bt_ctf_event_class *event_class, *writer_event_class; + int int_ret; + + event_class = bt_ctf_stream_class_get_event_class( + stream_class, i); + if (!event_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + bt_put(event_class); + goto end; + } + writer_event_class = copy_event_class(err, event_class); + if (!writer_event_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + bt_put(event_class); + goto end; + } + int_ret = bt_ctf_stream_class_add_event_class(writer_stream_class, + writer_event_class); + if (int_ret < 0) { + fprintf(err, "[error] Failed to add event class\n"); + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + bt_put(event_class); + goto end; + } + bt_put(event_class); + } + +end: + return ret; +} + +static +enum bt_component_status copy_stream_class(FILE *err, + struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_stream_class *writer_stream_class) +{ + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + struct bt_ctf_field_type *type; + int ret_int; + struct bt_ctf_clock *writer_clock; + + writer_clock = bt_ctf_clock_create("monotonic"); + if (!writer_clock) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] Failed to create clock\n"); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + tmp_clock(writer, writer_stream_class, writer_clock); + + /* + * FIXME: waiting for the clock to work + * + struct bt_ctf_clock *clock; + clock = bt_ctf_stream_class_get_clock(stream_class); + if (!clock) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + ret = copy_clock(err, writer, writer_stream_class, clock, writer_clock); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end_put_clock; + } + */ + + type = bt_ctf_stream_class_get_packet_context_type(stream_class); + if (!type) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + ret_int = bt_ctf_stream_class_set_packet_context_type( + writer_stream_class, type); + if (ret_int < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + type = bt_ctf_stream_class_get_event_header_type(stream_class); + if (!type) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + ret_int = bt_ctf_stream_class_set_event_header_type( + writer_stream_class, type); + if (ret_int < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + type = bt_ctf_stream_class_get_event_context_type(stream_class); + if (!type) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + ret_int = bt_ctf_stream_class_set_event_context_type( + writer_stream_class, type); + if (ret_int < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + + ret = copy_event_classes(err, writer, stream_class, writer_stream_class); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(err, "[error] Failed to copy event classes\n"); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_clock; + } + +end_put_clock: +// bt_put(clock); +end: + return ret; +} + +static +enum bt_component_status copy_trace(FILE *err, struct bt_ctf_writer *ctf_writer, + struct bt_ctf_trace *trace) +{ + struct bt_ctf_trace *writer_trace; + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + int field_count, i, int_ret; + struct bt_ctf_field_type *header_type; + + writer_trace = bt_ctf_writer_get_trace(ctf_writer); + if (!writer_trace) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + field_count = bt_ctf_trace_get_environment_field_count(trace); + for (i = 0; i < field_count; i++) { + int ret_int; + const char *name; + struct bt_value *value; + + name = bt_ctf_trace_get_environment_field_name(trace, i); + if (!name) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_trace; + } + value = bt_ctf_trace_get_environment_field_value(trace, i); + if (!value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_trace; + } + + ret_int = bt_ctf_trace_set_environment_field(writer_trace, + name, value); + if (ret_int < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + fprintf(err, "[error] Unable to set environment field %s\n", + name); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_trace; + } + } + + header_type = bt_ctf_trace_get_packet_header_type(writer_trace); + if (!header_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_trace; + } + + int_ret = bt_ctf_trace_set_packet_header_type(writer_trace, header_type); + if (int_ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_header_type; + } + +end_put_header_type: + bt_put(header_type); +end_put_writer_trace: + bt_put(writer_trace); +end: + return ret; +} + +static +struct bt_ctf_stream_class *insert_new_stream_class( + struct writer_component *writer_component, + struct bt_ctf_writer *ctf_writer, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_stream_class *writer_stream_class; + const char *name = bt_ctf_stream_class_get_name(stream_class); + enum bt_component_status ret; + + if (strlen(name) == 0) { + name = NULL; + } + + writer_stream_class = bt_ctf_stream_class_create(name); + if (!writer_stream_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + ret = copy_stream_class(writer_component->err, + ctf_writer, stream_class, writer_stream_class); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(writer_component->err, "[error] Failed to copy stream class\n"); + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + BT_PUT(writer_stream_class); + goto end; + } + g_hash_table_insert(writer_component->stream_class_map, + (gpointer) stream_class, writer_stream_class); + +end: + return writer_stream_class; +} + +static +struct bt_ctf_stream *insert_new_stream( + struct writer_component *writer_component, + struct bt_ctf_writer *ctf_writer, + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream *writer_stream; + struct bt_ctf_stream_class *writer_stream_class; + + writer_stream_class = g_hash_table_lookup( + writer_component->stream_class_map, + (gpointer) stream_class); + if (writer_stream_class) { + if (!bt_get(writer_stream_class)) { + writer_stream = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + } else { + writer_stream_class = insert_new_stream_class( + writer_component, ctf_writer, stream_class); + if (!writer_stream_class) { + writer_stream = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + } + + writer_stream = bt_ctf_writer_create_stream(ctf_writer, + writer_stream_class); + if (!writer_stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + + g_hash_table_insert(writer_component->stream_map, (gpointer) stream, + writer_stream); + + bt_ctf_writer_flush_metadata(ctf_writer); + +end_put: + bt_put(writer_stream_class); +end: + return writer_stream; +} + +static +struct bt_ctf_stream *lookup_stream(struct writer_component *writer_component, + struct bt_ctf_stream *stream) +{ + return (struct bt_ctf_stream *) g_hash_table_lookup( + writer_component->stream_map, + (gpointer) stream); +} + +static +struct bt_ctf_event_class *get_event_class(struct writer_component *writer_component, + struct bt_ctf_stream_class *writer_stream_class, + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_stream_class_get_event_class_by_name(writer_stream_class, + bt_ctf_event_class_get_name(event_class)); +} + +struct bt_ctf_writer *insert_new_writer( + struct writer_component *writer_component, + struct bt_ctf_trace *trace) +{ + struct bt_ctf_writer *ctf_writer; + char trace_name[PATH_MAX]; + enum bt_component_status ret; + + snprintf(trace_name, PATH_MAX, "%s/%s_%03d", + writer_component->base_path, + writer_component->trace_name_base, + writer_component->trace_id++); + printf_verbose("CTF-Writer creating trace in %s\n", trace_name); + + ctf_writer = bt_ctf_writer_create(trace_name); + if (!ctf_writer) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + ret = copy_trace(writer_component->err, ctf_writer, trace); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(writer_component->err, "[error] Failed to copy trace\n"); + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + BT_PUT(ctf_writer); + goto end; + } + + g_hash_table_insert(writer_component->trace_map, (gpointer) trace, + ctf_writer); + +end: + return ctf_writer; +} + +static +struct bt_ctf_writer *get_writer(struct writer_component *writer_component, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_trace *trace; + struct bt_ctf_writer *ctf_writer; + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (!trace) { + ctf_writer = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + ctf_writer = g_hash_table_lookup(writer_component->trace_map, + (gpointer) trace); + if (ctf_writer) { + if (!bt_get(ctf_writer)) { + ctf_writer = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + } else { + ctf_writer = insert_new_writer(writer_component, trace); + } + bt_put(trace); + +end: + return ctf_writer; +} + +static +struct bt_ctf_stream *get_writer_stream( + struct writer_component *writer_component, + struct bt_ctf_packet *packet, struct bt_ctf_stream *stream) +{ + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_writer *ctf_writer; + struct bt_ctf_stream *writer_stream; + + stream_class = bt_ctf_stream_get_class(stream); + if (!stream_class) { + writer_stream = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + ctf_writer = get_writer(writer_component, stream_class); + if (!ctf_writer) { + writer_stream = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put_stream_class; + } + + writer_stream = lookup_stream(writer_component, stream); + + if (writer_stream) { + if (!bt_get(writer_stream)) { + writer_stream = NULL; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put_stream_class; + } + } else { + writer_stream = insert_new_stream(writer_component, ctf_writer, + stream_class, stream); + } + + bt_put(ctf_writer); +end_put_stream_class: + bt_put(stream_class); +end: + return writer_stream; +} + +BT_HIDDEN +enum bt_component_status writer_new_packet( + struct writer_component *writer_component, + struct bt_ctf_packet *packet) +{ + struct bt_ctf_stream *stream, *writer_stream; + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + + stream = bt_ctf_packet_get_stream(packet); + if (!stream) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + /* TODO: copy values for event discarded and packet_seq_num */ + writer_stream = get_writer_stream(writer_component, packet, stream); + if (!writer_stream) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + + bt_put(writer_stream); + +end_put: + bt_put(stream); +end: + return ret; +} + +static +enum bt_component_status copy_packet_context_field(FILE *err, + struct bt_ctf_field *field, const char *field_name, + struct bt_ctf_field *writer_packet_context, + struct bt_ctf_field_type *writer_packet_context_type) +{ + enum bt_component_status ret; + struct bt_ctf_field *writer_field; + int int_ret; + uint64_t value; + + /* + * TODO: handle the special case of the first/last packet that might + * be trimmed. In these cases, the timestamp_begin/end need to be + * explicitely set to the first/last event timestamps. + */ + + writer_field = bt_ctf_field_structure_get_field(writer_packet_context, + field_name); + if (!writer_field) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + int_ret = bt_ctf_field_unsigned_integer_get_value(field, &value); + if (int_ret < 0) { + fprintf(err, "[error] Wrong packet_context field type\n"); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_field; + } + + int_ret = bt_ctf_field_unsigned_integer_set_value(writer_field, value); + if (int_ret < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_writer_field; + } + + ret = BT_COMPONENT_STATUS_OK; + +end_put_writer_field: + bt_put(writer_field); +end: + return ret; +} + +static +enum bt_component_status copy_packet_context(FILE *err, + struct bt_ctf_packet *packet, + struct bt_ctf_stream *writer_stream) +{ + enum bt_component_status ret; + struct bt_ctf_field *packet_context, *writer_packet_context; + struct bt_ctf_field_type *struct_type, *writer_packet_context_type; + struct bt_ctf_stream_class *writer_stream_class; + int nr_fields, i, int_ret; + + packet_context = bt_ctf_packet_get_context(packet); + if (!packet_context) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + writer_stream_class = bt_ctf_stream_get_class(writer_stream); + if (!writer_stream_class) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_packet_context; + } + + writer_packet_context_type = bt_ctf_stream_class_get_packet_context_type( + writer_stream_class); + if (!writer_packet_context_type) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_writer_stream_class; + } + + struct_type = bt_ctf_field_get_type(packet_context); + if (!struct_type) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_writer_packet_context_type; + } + + writer_packet_context = bt_ctf_field_create(writer_packet_context_type); + if (!writer_packet_context) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_struct_type; + } + + nr_fields = bt_ctf_field_type_structure_get_field_count(struct_type); + for (i = 0; i < nr_fields; i++) { + struct bt_ctf_field *field; + struct bt_ctf_field_type *field_type; + const char *field_name; + + field = bt_ctf_field_structure_get_field_by_index( + packet_context, i); + if (!field) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_packet_context; + } + if (bt_ctf_field_type_structure_get_field(struct_type, + &field_name, &field_type, i) < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + bt_put(field); + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_packet_context; + } + + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) { + fprintf(err, "[error] Unexpected packet context field type\n"); + bt_put(field); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_packet_context; + } + + ret = copy_packet_context_field(err, field, field_name, + writer_packet_context, writer_packet_context_type); + bt_put(field_type); + bt_put(field); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_packet_context; + } + } + + int_ret = bt_ctf_stream_set_packet_context(writer_stream, + writer_packet_context); + if (int_ret < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put_writer_packet_context; + } + +end_put_writer_packet_context: + bt_put(writer_packet_context); +end_put_struct_type: + bt_put(struct_type); +end_put_writer_packet_context_type: + bt_put(writer_packet_context_type); +end_put_writer_stream_class: + bt_put(writer_stream_class); +end_put_packet_context: + bt_put(packet_context); +end: + return ret; +} + +BT_HIDDEN +enum bt_component_status writer_close_packet( + struct writer_component *writer_component, + struct bt_ctf_packet *packet) +{ + struct bt_ctf_stream *stream, *writer_stream; + enum bt_component_status ret; + + stream = bt_ctf_packet_get_stream(packet); + if (!stream) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + writer_stream = lookup_stream(writer_component, stream); + if (!writer_stream) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + + if (!bt_get(writer_stream)) { + fprintf(writer_component->err, + "[error] Failed to get reference on writer stream\n"); + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = BT_COMPONENT_STATUS_ERROR; + goto end_put; + } + + ret = copy_packet_context(writer_component->err, packet, writer_stream); + if (ret != BT_COMPONENT_STATUS_OK) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + + ret = bt_ctf_stream_flush(writer_stream); + if (ret < 0) { + fprintf(writer_component->err, + "[error] Failed to flush packet\n"); + ret = BT_COMPONENT_STATUS_ERROR; + } + + ret = BT_COMPONENT_STATUS_OK; + + bt_put(writer_stream); + +end_put: + bt_put(stream); +end: + return ret; +} + +static +struct bt_ctf_event *copy_event(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event_class *writer_event_class) +{ + struct bt_ctf_event *writer_event; + struct bt_ctf_field *field; + int ret; + + writer_event = bt_ctf_event_create(writer_event_class); + if (!writer_event) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_event_get_header(event); + ret = bt_ctf_event_set_header(writer_event, + bt_ctf_field_copy(field)); + if (ret < 0) { + BT_PUT(writer_event); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_event_get_stream_event_context(event); + ret = bt_ctf_event_set_stream_event_context(writer_event, + bt_ctf_field_copy(field)); + if (ret < 0) { + BT_PUT(writer_event); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_event_get_event_context(event); + ret = bt_ctf_event_set_event_context(writer_event, + bt_ctf_field_copy(field)); + if (ret < 0) { + BT_PUT(writer_event); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto end; + } + + field = bt_ctf_event_get_payload_field(event); + ret = bt_ctf_event_set_payload_field(writer_event, + bt_ctf_field_copy(field)); + if (ret < 0) { + BT_PUT(writer_event); + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); + goto end; + } + +end: + return writer_event; +} + +BT_HIDDEN +enum bt_component_status writer_output_event( + struct writer_component *writer_component, + struct bt_ctf_event *event) +{ + enum bt_component_status ret; + struct bt_ctf_event_class *event_class, *writer_event_class; + struct bt_ctf_stream *stream, *writer_stream; + struct bt_ctf_stream_class *stream_class, *writer_stream_class; + struct bt_ctf_event *writer_event; + const char *event_name; + int int_ret; + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + event_name = bt_ctf_event_class_get_name(event_class); + if (!event_name) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_event_class; + } +// printf("%s\n", event_name); + + stream = bt_ctf_event_get_stream(event); + if (!stream) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_event_class; + } + + writer_stream = lookup_stream(writer_component, stream); + if (!writer_stream || !bt_get(writer_stream)) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_stream; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_stream; + } + + writer_stream_class = g_hash_table_lookup( + writer_component->stream_class_map, + (gpointer) stream_class); + if (!writer_stream_class || !bt_get(writer_stream_class)) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_stream_class; + } + + writer_event_class = get_event_class(writer_component, + writer_stream_class, event_class); + if (!writer_event_class) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_stream_class; + } + + writer_event = copy_event(writer_component->err, event, writer_event_class); + if (!writer_event) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + fprintf(writer_component->err, "[error] Failed to copy event %s\n", + bt_ctf_event_class_get_name(writer_event_class)); + goto end_put_writer_event_class; + } + + int_ret = bt_ctf_stream_append_event(writer_stream, writer_event); + if (int_ret < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + fprintf(writer_component->err, "[error] Failed to append event %s\n", + bt_ctf_event_class_get_name(writer_event_class)); + goto end_put_writer_event; + } + + ret = BT_COMPONENT_STATUS_OK; + +end_put_writer_event: + bt_put(writer_event); +end_put_writer_event_class: + bt_put(writer_event_class); +end_put_writer_stream_class: + bt_put(writer_stream_class); +end_put_stream_class: + bt_put(stream_class); +end_put_writer_stream: + bt_put(writer_stream); +end_put_stream: + bt_put(stream); +end_put_event_class: + bt_put(event_class); +end: + return ret; +} diff --git a/plugins/writer/writer.c b/plugins/writer/writer.c new file mode 100644 index 00000000..c9ec3479 --- /dev/null +++ b/plugins/writer/writer.c @@ -0,0 +1,272 @@ +/* + * writer.c + * + * Babeltrace CTF Writer Output Plugin + * + * Copyright 2016 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 "writer.h" + +static +void destroy_writer_component_data(struct writer_component *writer_component) +{ + g_hash_table_destroy(writer_component->stream_map); + g_hash_table_destroy(writer_component->stream_class_map); + g_hash_table_destroy(writer_component->trace_map); +} + +static +void destroy_writer_component(struct bt_component *component) +{ + struct writer_component *writer_component = (struct writer_component *) + bt_component_get_private_data(component); + + destroy_writer_component_data(writer_component); + g_free(writer_component); +} + +static +void unref_stream_class(struct bt_ctf_stream_class *writer_stream_class) +{ + BT_PUT(writer_stream_class); + g_free(writer_stream_class); +} + +static +void unref_stream(struct bt_ctf_stream_class *writer_stream) +{ + BT_PUT(writer_stream); + g_free(writer_stream); +} + +static +void unref_trace(struct bt_ctf_writer *writer) +{ + BT_PUT(writer); + g_free(writer); +} + +static +struct writer_component *create_writer_component(void) +{ + struct writer_component *writer_component; + + writer_component = g_new0(struct writer_component, 1); + if (!writer_component) { + goto end; + } + + writer_component->err = stderr; + writer_component->trace_id = 0; + snprintf(writer_component->trace_name_base, NAME_MAX, "trace"); + + /* + * Reader to writer corresponding structures. + */ + writer_component->trace_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_trace); + writer_component->stream_class_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_stream_class); + writer_component->stream_map = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) unref_stream); + +end: + return writer_component; +} + +static +enum bt_component_status handle_notification( + struct writer_component *writer_component, + struct bt_notification *notification) +{ + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + + if (!writer_component) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + switch (bt_notification_get_type(notification)) { + case BT_NOTIFICATION_TYPE_PACKET_START: + { + struct bt_ctf_packet *packet = + bt_notification_packet_start_get_packet(notification); + + if (!packet) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + ret = writer_new_packet(writer_component, packet); + bt_put(packet); + break; + } + case BT_NOTIFICATION_TYPE_PACKET_END: + { + struct bt_ctf_packet *packet = + bt_notification_packet_start_get_packet(notification); + + if (!packet) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + ret = writer_close_packet(writer_component, packet); + bt_put(packet); + break; + } + case BT_NOTIFICATION_TYPE_EVENT: + { + struct bt_ctf_event *event = bt_notification_event_get_event( + notification); + + if (!event) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + ret = BT_COMPONENT_STATUS_OK; + ret = writer_output_event(writer_component, event); + bt_put(event); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + break; + } + case BT_NOTIFICATION_TYPE_STREAM_END: + break; + default: + puts("Unhandled notification type"); + } +end: + return ret; +} + +static +enum bt_component_status run(struct bt_component *component) +{ + enum bt_component_status ret; + struct bt_notification *notification = NULL; + struct bt_notification_iterator *it; + struct writer_component *writer_component = + bt_component_get_private_data(component); + + ret = bt_component_sink_get_input_iterator(component, 0, &it); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + ret = bt_notification_iterator_next(it); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + notification = bt_notification_iterator_get_notification(it); + if (!notification) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + ret = handle_notification(writer_component, notification); +end: + bt_put(it); + bt_put(notification); + return ret; +} + +static +enum bt_component_status writer_component_init( + struct bt_component *component, struct bt_value *params) +{ + enum bt_component_status ret; + enum bt_value_status value_ret; + struct writer_component *writer_component = create_writer_component(); + struct bt_value *value = NULL; + const char *path; + + if (!writer_component) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + value = bt_value_map_get(params, "path"); + if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { + fprintf(writer_component->err, + "[error] output path parameter required\n"); + ret = BT_COMPONENT_STATUS_INVALID; + goto error; + } + + value_ret = bt_value_string_get(value, &path); + if (value_ret != BT_VALUE_STATUS_OK) { + ret = BT_COMPONENT_STATUS_INVALID; + goto error; + } + + strncpy(writer_component->base_path, path, PATH_MAX); + + ret = bt_component_set_destroy_cb(component, + destroy_writer_component); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + + ret = bt_component_set_private_data(component, writer_component); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + + ret = bt_component_sink_set_consume_cb(component, + run); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + +end: + return ret; +error: + destroy_writer_component_data(writer_component); + return ret; +} + +/* Initialize plug-in entry points. */ +BT_PLUGIN_NAME("writer"); +BT_PLUGIN_DESCRIPTION("Babeltrace CTF-Writer output plug-in."); +BT_PLUGIN_AUTHOR("Jérémie Galarneau"); +BT_PLUGIN_LICENSE("MIT"); + +BT_PLUGIN_COMPONENT_CLASSES_BEGIN +BT_PLUGIN_SINK_COMPONENT_CLASS_ENTRY("writer", + "Formats CTF-IR to CTF.", + writer_component_init) +BT_PLUGIN_COMPONENT_CLASSES_END diff --git a/plugins/writer/writer.h b/plugins/writer/writer.h new file mode 100644 index 00000000..2b44435f --- /dev/null +++ b/plugins/writer/writer.h @@ -0,0 +1,59 @@ +#ifndef BABELTRACE_PLUGIN_WRITER_H +#define BABELTRACE_PLUGIN_WRITER_H + +/* + * BabelTrace - CTF Writer Output Plug-in + * + * Copyright 2016 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 + +struct writer_component { + char base_path[PATH_MAX]; + char trace_name_base[NAME_MAX]; + /* For the directory name suffix. */ + int trace_id; + /* Map between struct bt_ctf_trace and struct bt_ctf_writer. */ + GHashTable *trace_map; + /* Map between reader and writer stream. */ + GHashTable *stream_map; + /* Map between reader and writer stream class. */ + GHashTable *stream_class_map; + FILE *err; +}; + +BT_HIDDEN +enum bt_component_status writer_output_event(struct writer_component *writer, + struct bt_ctf_event *event); +BT_HIDDEN +enum bt_component_status writer_new_packet(struct writer_component *writer, + struct bt_ctf_packet *packet); +BT_HIDDEN +enum bt_component_status writer_close_packet(struct writer_component *writer, + struct bt_ctf_packet *packet); + +#endif /* BABELTRACE_PLUGIN_WRITER_H */