From: Philippe Proulx Date: Fri, 5 May 2017 17:54:23 +0000 (-0400) Subject: Rename writer.writer -> ctf.fs (sink) and standardize plugin descriptions X-Git-Tag: v2.0.0-pre1~314 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=d8866baa7f1ae173ac9d9fac0ad55cb28f883cbf Rename writer.writer -> ctf.fs (sink) and standardize plugin descriptions Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- diff --git a/configure.ac b/configure.ac index 8890f4ab..0ca41afb 100644 --- a/configure.ac +++ b/configure.ac @@ -496,11 +496,11 @@ AC_CONFIG_FILES([ plugins/ctf/common/btr/Makefile plugins/ctf/common/metadata/Makefile plugins/ctf/common/notif-iter/Makefile - plugins/ctf/fs/Makefile + plugins/ctf/fs-src/Makefile + plugins/ctf/fs-sink/Makefile plugins/ctf/lttng-live/Makefile plugins/text/Makefile plugins/text/pretty/Makefile - plugins/writer/Makefile plugins/utils/Makefile plugins/utils/dummy/Makefile plugins/utils/trimmer/Makefile diff --git a/plugins/Makefile.am b/plugins/Makefile.am index c6249c4d..be2de4e7 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = libctfcopytrace ctf text utils writer +SUBDIRS = libctfcopytrace ctf text utils if ENABLE_DEBUG_INFO SUBDIRS += lttng-utils diff --git a/plugins/ctf/Makefile.am b/plugins/ctf/Makefile.am index f53a6ab3..566577ae 100644 --- a/plugins/ctf/Makefile.am +++ b/plugins/ctf/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -SUBDIRS = common fs lttng-live +SUBDIRS = common fs-src fs-sink lttng-live plugindir = "$(PLUGINSDIR)" plugin_LTLIBRARIES = libbabeltrace-plugin-ctf.la @@ -13,5 +13,6 @@ libbabeltrace_plugin_ctf_la_LDFLAGS = \ libbabeltrace_plugin_ctf_la_LIBADD = \ $(top_builddir)/lib/libbabeltrace.la \ - fs/libbabeltrace-plugin-ctf-fs.la \ - lttng-live/libbabeltrace-plugin-ctf-lttng-live.la + fs-src/libbabeltrace-plugin-ctf-fs.la \ + lttng-live/libbabeltrace-plugin-ctf-lttng-live.la \ + fs-sink/libbabeltrace-plugin-ctf-writer.la diff --git a/plugins/ctf/fs-sink/Makefile.am b/plugins/ctf/fs-sink/Makefile.am new file mode 100644 index 00000000..62f77112 --- /dev/null +++ b/plugins/ctf/fs-sink/Makefile.am @@ -0,0 +1,8 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins \ + -I$(top_srcdir)/plugins/libctfcopytrace + +noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-writer.la + +libbabeltrace_plugin_ctf_writer_la_LIBADD = \ + $(top_builddir)/plugins/libctfcopytrace/libctfcopytrace.la +libbabeltrace_plugin_ctf_writer_la_SOURCES = writer.c writer.h write.c diff --git a/plugins/ctf/fs-sink/write.c b/plugins/ctf/fs-sink/write.c new file mode 100644 index 00000000..91b92899 --- /dev/null +++ b/plugins/ctf/fs-sink/write.c @@ -0,0 +1,492 @@ +/* + * 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 + +#include "writer.h" + +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 = NULL; + struct bt_ctf_trace *trace = NULL, *writer_trace = NULL; + enum bt_component_status ret; + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (!trace) { + fprintf(writer_component->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + writer_trace = bt_ctf_writer_get_trace(ctf_writer); + if (!writer_trace) { + fprintf(writer_component->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = ctf_copy_clock_classes(writer_component->err, writer_trace, + writer_stream_class, trace); + if (ret != BT_COMPONENT_STATUS_OK) { + fprintf(writer_component->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + writer_stream_class = ctf_copy_stream_class(writer_component->err, + stream_class, writer_trace, true); + if (!writer_stream_class) { + fprintf(writer_component->err, "[error] Failed to copy stream class\n"); + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + g_hash_table_insert(writer_component->stream_class_map, + (gpointer) stream_class, writer_stream_class); + + goto end; + +error: + BT_PUT(writer_stream_class); +end: + bt_put(writer_trace); + bt_put(trace); + 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 = NULL; + struct bt_ctf_stream_class *writer_stream_class = NULL; + + writer_stream_class = g_hash_table_lookup( + writer_component->stream_class_map, + (gpointer) stream_class); + if (!writer_stream_class) { + writer_stream_class = insert_new_stream_class( + writer_component, ctf_writer, stream_class); + if (!writer_stream_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + } + bt_get(writer_stream_class); + + 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 error; + } + + g_hash_table_insert(writer_component->stream_map, (gpointer) stream, + writer_stream); + + goto end; + +error: + BT_PUT(writer_stream); +end: + bt_put(writer_stream_class); + 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_id(writer_stream_class, + bt_ctf_event_class_get_id(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 = NULL; + struct bt_ctf_trace *writer_trace = NULL; + char trace_name[PATH_MAX]; + enum bt_component_status ret; + + /* FIXME: replace with trace name when it will work. */ + snprintf(trace_name, PATH_MAX, "%s/%s_%03d", + writer_component->base_path->str, + writer_component->trace_name_base->str, + 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 error; + } + + writer_trace = bt_ctf_writer_get_trace(ctf_writer); + if (!writer_trace) { + fprintf(writer_component->err, + "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = ctf_copy_trace(writer_component->err, trace, 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; + } + BT_PUT(writer_trace); + + g_hash_table_insert(writer_component->trace_map, (gpointer) trace, + ctf_writer); + + goto end; + +error: + bt_put(writer_trace); + BT_PUT(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 = NULL; + struct bt_ctf_writer *ctf_writer = NULL; + + 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 error; + } + + ctf_writer = g_hash_table_lookup(writer_component->trace_map, + (gpointer) trace); + if (!ctf_writer) { + ctf_writer = insert_new_writer(writer_component, trace); + } + bt_get(ctf_writer); + BT_PUT(trace); + goto end; + +error: + BT_PUT(ctf_writer); +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 = NULL; + struct bt_ctf_writer *ctf_writer = NULL; + struct bt_ctf_stream *writer_stream = NULL; + + stream_class = bt_ctf_stream_get_class(stream); + if (!stream_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + ctf_writer = get_writer(writer_component, stream_class); + if (!ctf_writer) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + writer_stream = lookup_stream(writer_component, stream); + if (!writer_stream) { + writer_stream = insert_new_stream(writer_component, ctf_writer, + stream_class, stream); + } + bt_get(writer_stream); + + goto end; + +error: + BT_PUT(writer_stream); +end: + bt_put(ctf_writer); + bt_put(stream_class); + 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 = NULL, *writer_stream = NULL; + struct bt_ctf_field *writer_packet_context = NULL; + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + int int_ret; + + stream = bt_ctf_packet_get_stream(packet); + if (!stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + writer_stream = get_writer_stream(writer_component, packet, stream); + if (!writer_stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + BT_PUT(stream); + + writer_packet_context = ctf_copy_packet_context(writer_component->err, + packet, writer_stream); + if (!writer_packet_context) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + int_ret = bt_ctf_stream_set_packet_context(writer_stream, + writer_packet_context); + if (int_ret < 0) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + BT_PUT(writer_stream); + BT_PUT(writer_packet_context); + + goto end; + +error: + ret = BT_COMPONENT_STATUS_ERROR; +end: + bt_put(writer_stream); + bt_put(writer_packet_context); + bt_put(stream); + 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 = NULL, *writer_stream = NULL; + enum bt_component_status ret; + + stream = bt_ctf_packet_get_stream(packet); + if (!stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + writer_stream = lookup_stream(writer_component, stream); + if (!writer_stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + BT_PUT(stream); + + bt_get(writer_stream); + + ret = bt_ctf_stream_flush(writer_stream); + if (ret < 0) { + fprintf(writer_component->err, + "[error] Failed to flush packet\n"); + goto error; + } + BT_PUT(writer_stream); + + ret = BT_COMPONENT_STATUS_OK; + goto end; + +error: + ret = BT_COMPONENT_STATUS_ERROR; +end: + bt_put(writer_stream); + bt_put(stream); + return ret; +} + +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 = NULL, *writer_event_class = NULL; + struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; + struct bt_ctf_stream_class *stream_class = NULL, *writer_stream_class = NULL; + struct bt_ctf_event *writer_event = NULL; + const char *event_name; + int int_ret; + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + event_name = bt_ctf_event_class_get_name(event_class); + if (!event_name) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + stream = bt_ctf_event_get_stream(event); + if (!stream) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_stream = lookup_stream(writer_component, stream); + if (!writer_stream || !bt_get(writer_stream)) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_stream_class = g_hash_table_lookup( + writer_component->stream_class_map, + (gpointer) stream_class); + if (!writer_stream_class || !bt_get(writer_stream_class)) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + + writer_event_class = get_event_class(writer_component, + writer_stream_class, event_class); + if (!writer_event_class) { + writer_event_class = ctf_copy_event_class(writer_component->err, + event_class); + if (!writer_event_class) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + int_ret = bt_ctf_stream_class_add_event_class( + writer_stream_class, writer_event_class); + if (int_ret) { + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + } + + writer_event = ctf_copy_event(writer_component->err, event, + writer_event_class, true); + if (!writer_event) { + 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 error; + } + + int_ret = bt_ctf_stream_append_event(writer_stream, writer_event); + if (int_ret < 0) { + 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 error; + } + + ret = BT_COMPONENT_STATUS_OK; + goto end; + +error: + ret = BT_COMPONENT_STATUS_ERROR; +end: + bt_put(writer_event); + bt_put(writer_event_class); + bt_put(writer_stream_class); + bt_put(stream_class); + bt_put(writer_stream); + bt_put(stream); + bt_put(event_class); + return ret; +} diff --git a/plugins/ctf/fs-sink/writer.c b/plugins/ctf/fs-sink/writer.c new file mode 100644 index 00000000..211a6a9c --- /dev/null +++ b/plugins/ctf/fs-sink/writer.c @@ -0,0 +1,317 @@ +/* + * 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 +#include +#include +#include +#include +#include "writer.h" +#include + +static +void destroy_writer_component_data(struct writer_component *writer_component) +{ + bt_put(writer_component->input_iterator); + 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); + g_string_free(writer_component->base_path, true); + g_string_free(writer_component->trace_name_base, true); +} + +BT_HIDDEN +void writer_component_finalize(struct bt_private_component *component) +{ + struct writer_component *writer_component = (struct writer_component *) + bt_private_component_get_user_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); +} + +static +void unref_stream(struct bt_ctf_stream_class *writer_stream) +{ + bt_put(writer_stream); +} + +static +void unref_trace(struct bt_ctf_writer *writer) +{ + bt_put(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; + writer_component->trace_name_base = g_string_new("trace"); + writer_component->processed_first_event = false; + if (!writer_component->trace_name_base) { + g_free(writer_component); + writer_component = NULL; + goto end; + } + + /* + * 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_BEGIN: + { + struct bt_ctf_packet *packet = + bt_notification_packet_begin_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_end_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; +} + +BT_HIDDEN +void writer_component_port_connected( + struct bt_private_component *component, + struct bt_private_port *self_port, + struct bt_port *other_port) +{ + struct bt_private_connection *connection; + struct writer_component *writer; + + writer = bt_private_component_get_user_data(component); + assert(writer); + assert(!writer->input_iterator); + connection = bt_private_port_get_private_connection(self_port); + assert(connection); + writer->input_iterator = + bt_private_connection_create_notification_iterator(connection, + NULL); + + if (!writer->input_iterator) { + writer->error = true; + } + + bt_put(connection); +} + +BT_HIDDEN +enum bt_component_status writer_run(struct bt_private_component *component) +{ + enum bt_component_status ret; + struct bt_notification *notification = NULL; + struct bt_notification_iterator *it; + struct writer_component *writer_component = + bt_private_component_get_user_data(component); + + it = writer_component->input_iterator; + assert(it); + + if (unlikely(writer_component->error)) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + if (likely(writer_component->processed_first_event)) { + enum bt_notification_iterator_status it_ret; + + it_ret = bt_notification_iterator_next(it); + switch (it_ret) { + case BT_NOTIFICATION_ITERATOR_STATUS_ERROR: + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + case BT_NOTIFICATION_ITERATOR_STATUS_END: + ret = BT_COMPONENT_STATUS_END; + BT_PUT(writer_component->input_iterator); + goto end; + default: + break; + } + } + + notification = bt_notification_iterator_get_notification(it); + if (!notification) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + ret = handle_notification(writer_component, notification); + writer_component->processed_first_event = true; +end: + bt_put(notification); + return ret; +} + +BT_HIDDEN +enum bt_component_status writer_component_init( + struct bt_private_component *component, struct bt_value *params, + UNUSED_VAR void *init_method_data) +{ + 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; + void *priv_port; + + if (!writer_component) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + priv_port = bt_private_component_sink_add_input_private_port(component, + "in", NULL); + if (!priv_port) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + bt_put(priv_port); + + 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; + } + bt_put(value); + + writer_component->base_path = g_string_new(path); + if (!writer_component) { + ret = BT_COMPONENT_STATUS_ERROR; + goto error; + } + + ret = bt_private_component_set_user_data(component, writer_component); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + +end: + return ret; +error: + destroy_writer_component_data(writer_component); + g_free(writer_component); + return ret; +} diff --git a/plugins/ctf/fs-sink/writer.h b/plugins/ctf/fs-sink/writer.h new file mode 100644 index 00000000..1765a961 --- /dev/null +++ b/plugins/ctf/fs-sink/writer.h @@ -0,0 +1,79 @@ +#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 { + GString *base_path; + GString *trace_name_base; + /* 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; + struct bt_notification_iterator *input_iterator; + bool processed_first_event; + bool error; +}; + +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); + +BT_HIDDEN +enum bt_component_status writer_component_init( + struct bt_private_component *component, struct bt_value *params, + void *init_method_data); + +BT_HIDDEN +enum bt_component_status writer_run(struct bt_private_component *component); + +BT_HIDDEN +void writer_component_port_connected( + struct bt_private_component *component, + struct bt_private_port *self_port, + struct bt_port *other_port); + +BT_HIDDEN +void writer_component_finalize(struct bt_private_component *component); + +#endif /* BABELTRACE_PLUGIN_WRITER_H */ diff --git a/plugins/ctf/fs-src/Makefile.am b/plugins/ctf/fs-src/Makefile.am new file mode 100644 index 00000000..3c5c8b6f --- /dev/null +++ b/plugins/ctf/fs-src/Makefile.am @@ -0,0 +1,17 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins + +noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-fs.la + +libbabeltrace_plugin_ctf_fs_la_LIBADD = \ + $(builddir)/../common/libbabeltrace-plugin-ctf-common.la +libbabeltrace_plugin_ctf_fs_la_SOURCES = \ + fs.c \ + data-stream.c \ + metadata.c \ + file.c \ + data-stream.h \ + file.h \ + fs.h \ + lttng-index.h \ + metadata.h \ + print.h diff --git a/plugins/ctf/fs-src/data-stream.c b/plugins/ctf/fs-src/data-stream.c new file mode 100644 index 00000000..38843d7b --- /dev/null +++ b/plugins/ctf/fs-src/data-stream.c @@ -0,0 +1,480 @@ +/* + * Copyright 2016 - Philippe Proulx + * Copyright 2016 - Jérémie Galarneau + * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation + * + * 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 "file.h" +#include "metadata.h" +#include "../common/notif-iter/notif-iter.h" +#include +#include "data-stream.h" + +#define PRINT_ERR_STREAM ctf_fs->error_fp +#define PRINT_PREFIX "ctf-fs-data-stream" +#include "print.h" + +static inline +size_t remaining_mmap_bytes(struct ctf_fs_stream *stream) +{ + return stream->mmap_valid_len - stream->request_offset; +} + +static +int stream_munmap(struct ctf_fs_stream *stream) +{ + int ret = 0; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; + + if (munmap(stream->mmap_addr, stream->mmap_len)) { + PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n", + stream->mmap_addr, stream->mmap_len, + stream->file->path->str, stream->file->fp, + strerror(errno)); + ret = -1; + goto end; + } +end: + return ret; +} + +static +enum bt_ctf_notif_iter_medium_status mmap_next(struct ctf_fs_stream *stream) +{ + enum bt_ctf_notif_iter_medium_status ret = + BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; + + /* Unmap old region */ + if (stream->mmap_addr) { + if (stream_munmap(stream)) { + goto error; + } + + stream->mmap_offset += stream->mmap_valid_len; + stream->request_offset = 0; + } + + stream->mmap_valid_len = MIN(stream->file->size - stream->mmap_offset, + stream->mmap_max_len); + if (stream->mmap_valid_len == 0) { + ret = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF; + goto end; + } + /* Round up to next page, assuming page size being a power of 2. */ + stream->mmap_len = (stream->mmap_valid_len + ctf_fs->page_size - 1) + & ~(ctf_fs->page_size - 1); + /* Map new region */ + assert(stream->mmap_len); + stream->mmap_addr = mmap((void *) 0, stream->mmap_len, + PROT_READ, MAP_PRIVATE, fileno(stream->file->fp), + stream->mmap_offset); + if (stream->mmap_addr == MAP_FAILED) { + PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n", + stream->mmap_len, stream->file->path->str, + stream->file->fp, stream->mmap_offset, + strerror(errno)); + goto error; + } + + goto end; +error: + stream_munmap(stream); + ret = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR; +end: + return ret; +} + +static +enum bt_ctf_notif_iter_medium_status medop_request_bytes( + size_t request_sz, uint8_t **buffer_addr, + size_t *buffer_sz, void *data) +{ + enum bt_ctf_notif_iter_medium_status status = + BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK; + struct ctf_fs_stream *stream = data; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; + + if (request_sz == 0) { + goto end; + } + + /* Check if we have at least one memory-mapped byte left */ + if (remaining_mmap_bytes(stream) == 0) { + /* Are we at the end of the file? */ + if (stream->mmap_offset >= stream->file->size) { + PDBG("Reached end of file \"%s\" (%p)\n", + stream->file->path->str, stream->file->fp); + status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF; + goto end; + } + + status = mmap_next(stream); + switch (status) { + case BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK: + break; + case BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF: + goto end; + default: + PERR("Cannot memory-map next region of file \"%s\" (%p)\n", + stream->file->path->str, + stream->file->fp); + goto error; + } + } + + *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz); + *buffer_addr = ((uint8_t *) stream->mmap_addr) + stream->request_offset; + stream->request_offset += *buffer_sz; + goto end; + +error: + status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR; + +end: + return status; +} + +static +struct bt_ctf_stream *medop_get_stream( + struct bt_ctf_stream_class *stream_class, void *data) +{ + struct ctf_fs_stream *fs_stream = data; + struct ctf_fs_component *ctf_fs = fs_stream->file->ctf_fs; + + if (!fs_stream->stream) { + int64_t id = bt_ctf_stream_class_get_id(stream_class); + + PDBG("Creating stream out of stream class %" PRId64 "\n", id); + fs_stream->stream = bt_ctf_stream_create(stream_class, + fs_stream->file->path->str); + if (!fs_stream->stream) { + PERR("Cannot create stream (stream class %" PRId64 ")\n", + id); + } + } + + return fs_stream->stream; +} + +static struct bt_ctf_notif_iter_medium_ops medops = { + .request_bytes = medop_request_bytes, + .get_stream = medop_get_stream, +}; + +static +int build_index_from_idx_file(struct ctf_fs_stream *stream) +{ + int ret = 0; + gchar *directory = NULL; + gchar *basename = NULL; + GString *index_basename = NULL; + gchar *index_file_path = NULL; + GMappedFile *mapped_file = NULL; + gsize filesize; + const struct ctf_packet_index_file_hdr *header; + const char *mmap_begin, *file_pos; + struct index_entry *index; + uint64_t total_packets_size = 0; + size_t file_index_entry_size; + size_t file_entry_count; + size_t i; + + /* Look for index file in relative path index/name.idx. */ + basename = g_path_get_basename(stream->file->path->str); + if (!basename) { + ret = -1; + goto end; + } + + directory = g_path_get_dirname(stream->file->path->str); + if (!directory) { + ret = -1; + goto end; + } + + index_basename = g_string_new(basename); + if (!index_basename) { + ret = -1; + goto end; + } + + g_string_append(index_basename, ".idx"); + index_file_path = g_build_filename(directory, "index", + index_basename->str, NULL); + mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL); + if (!mapped_file) { + ret = -1; + goto end; + } + filesize = g_mapped_file_get_length(mapped_file); + if (filesize < sizeof(*header)) { + printf_error("Invalid LTTng trace index: file size < header size"); + ret = -1; + goto end; + } + + mmap_begin = g_mapped_file_get_contents(mapped_file); + header = (struct ctf_packet_index_file_hdr *) mmap_begin; + + file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header); + if (be32toh(header->magic) != CTF_INDEX_MAGIC) { + printf_error("Invalid LTTng trace index: \"magic\" validation failed"); + ret = -1; + goto end; + } + + file_index_entry_size = be32toh(header->packet_index_len); + file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size; + if ((filesize - sizeof(*header)) % (file_entry_count * file_index_entry_size)) { + printf_error("Invalid index file size; not a multiple of index entry size"); + ret = -1; + goto end; + } + + stream->index.entries = g_array_sized_new(FALSE, TRUE, + sizeof(struct index_entry), file_entry_count); + if (!stream->index.entries) { + ret = -1; + goto end; + } + index = (struct index_entry *) stream->index.entries->data; + for (i = 0; i < file_entry_count; i++) { + struct ctf_packet_index *file_index = + (struct ctf_packet_index *) file_pos; + uint64_t packet_size = be64toh(file_index->packet_size); + + if (packet_size % CHAR_BIT) { + ret = -1; + printf_error("Invalid packet size encountered in index file"); + goto invalid_index; + } + + /* Convert size in bits to bytes. */ + packet_size /= CHAR_BIT; + index->packet_size = packet_size; + + index->offset = be64toh(file_index->offset); + if (i != 0 && index->offset < (index - 1)->offset) { + printf_error("Invalid, non-monotonic, packet offset encountered in index file"); + ret = -1; + goto invalid_index; + } + + index->timestamp_begin = be64toh(file_index->timestamp_begin); + index->timestamp_end = be64toh(file_index->timestamp_end); + if (index->timestamp_end < index->timestamp_begin) { + printf_error("Invalid packet time bounds encountered in index file"); + ret = -1; + goto invalid_index; + } + + total_packets_size += packet_size; + file_pos += file_index_entry_size; + index++; + } + + /* Validate that the index addresses the complete stream. */ + if (stream->file->size != total_packets_size) { + printf_error("Invalid index; indexed size != stream file size"); + ret = -1; + goto invalid_index; + } +end: + g_free(directory); + g_free(basename); + g_free(index_file_path); + if (index_basename) { + g_string_free(index_basename, TRUE); + } + if (mapped_file) { + g_mapped_file_unref(mapped_file); + } + return ret; +invalid_index: + g_array_free(stream->index.entries, TRUE); + goto end; +} + +static +int build_index_from_stream(struct ctf_fs_stream *stream) +{ + return 0; +} + +static +int init_stream_index(struct ctf_fs_stream *stream) +{ + int ret; + + ret = build_index_from_idx_file(stream); + if (!ret) { + goto end; + } + + ret = build_index_from_stream(stream); +end: + return ret; +} + +BT_HIDDEN +struct ctf_fs_stream *ctf_fs_stream_create( + struct ctf_fs_component *ctf_fs, const char *path) +{ + int ret; + struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1); + + if (!stream) { + goto error; + } + + stream->file = ctf_fs_file_create(ctf_fs); + if (!stream->file) { + goto error; + } + + stream->cc_prio_map = bt_get(ctf_fs->cc_prio_map); + g_string_assign(stream->file->path, path); + ret = ctf_fs_file_open(ctf_fs, stream->file, "rb"); + if (ret) { + goto error; + } + + stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata->trace, + ctf_fs->page_size, medops, stream, + ctf_fs->error_fp); + if (!stream->notif_iter) { + goto error; + } + + stream->mmap_max_len = ctf_fs->page_size * 2048; + ret = init_stream_index(stream); + if (ret) { + goto error; + } + goto end; +error: + /* Do not touch "borrowed" file. */ + ctf_fs_stream_destroy(stream); + stream = NULL; +end: + return stream; +} + +BT_HIDDEN +void ctf_fs_stream_destroy(struct ctf_fs_stream *stream) +{ + if (!stream) { + return; + } + + bt_put(stream->cc_prio_map); + + if (stream->file) { + ctf_fs_file_destroy(stream->file); + } + + if (stream->stream) { + BT_PUT(stream->stream); + } + + if (stream->notif_iter) { + bt_ctf_notif_iter_destroy(stream->notif_iter); + } + + if (stream->index.entries) { + g_array_free(stream->index.entries, TRUE); + } + + g_free(stream); +} + +BT_HIDDEN +struct bt_notification_iterator_next_return ctf_fs_stream_next( + struct ctf_fs_stream *stream) +{ + enum bt_ctf_notif_iter_status notif_iter_status; + struct bt_notification_iterator_next_return ret = { + .status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR, + .notification = NULL, + }; + + if (stream->end_reached) { + notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_EOF; + goto translate_status; + } + + notif_iter_status = bt_ctf_notif_iter_get_next_notification(stream->notif_iter, + stream->cc_prio_map, &ret.notification); + if (notif_iter_status != BT_CTF_NOTIF_ITER_STATUS_OK && + notif_iter_status != BT_CTF_NOTIF_ITER_STATUS_EOF) { + goto translate_status; + } + + /* Should be handled in bt_ctf_notif_iter_get_next_notification. */ + if (notif_iter_status == BT_CTF_NOTIF_ITER_STATUS_EOF) { + ret.notification = bt_notification_stream_end_create( + stream->stream); + if (!ret.notification) { + notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_ERROR; + goto translate_status; + } + + notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_OK; + stream->end_reached = true; + } + +translate_status: + switch (notif_iter_status) { + case BT_CTF_NOTIF_ITER_STATUS_EOF: + ret.status = BT_NOTIFICATION_ITERATOR_STATUS_END; + break; + case BT_CTF_NOTIF_ITER_STATUS_OK: + ret.status = BT_NOTIFICATION_ITERATOR_STATUS_OK; + break; + case BT_CTF_NOTIF_ITER_STATUS_AGAIN: + /* + * Should not make it this far as this is + * medium-specific; there is nothing for the user to do + * and it should have been handled upstream. + */ + assert(false); + case BT_CTF_NOTIF_ITER_STATUS_INVAL: + case BT_CTF_NOTIF_ITER_STATUS_ERROR: + default: + ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + break; + } + + return ret; +} diff --git a/plugins/ctf/fs-src/data-stream.h b/plugins/ctf/fs-src/data-stream.h new file mode 100644 index 00000000..3d484425 --- /dev/null +++ b/plugins/ctf/fs-src/data-stream.h @@ -0,0 +1,63 @@ +#ifndef CTF_FS_DATA_STREAM_H +#define CTF_FS_DATA_STREAM_H + +/* + * 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 "../common/notif-iter/notif-iter.h" +#include "lttng-index.h" + +struct ctf_fs_component; +struct ctf_fs_file; +struct ctf_fs_stream; + +struct index_entry { + uint64_t offset; /* in bytes. */ + uint64_t packet_size; /* in bytes. */ + /* relative to the packet context field's mapped clock. */ + uint64_t timestamp_begin, timestamp_end; +}; + +struct index { + GArray *entries; /* Array of struct index_entry. */ +}; + +BT_HIDDEN +struct ctf_fs_stream *ctf_fs_stream_create( + struct ctf_fs_component *ctf_fs, const char *path); + +BT_HIDDEN +void ctf_fs_stream_destroy(struct ctf_fs_stream *stream); + +BT_HIDDEN +int ctf_fs_data_stream_open_streams(struct ctf_fs_component *ctf_fs); + +BT_HIDDEN +struct bt_notification_iterator_next_return ctf_fs_stream_next( + struct ctf_fs_stream *stream); + +#endif /* CTF_FS_DATA_STREAM_H */ diff --git a/plugins/ctf/fs-src/file.c b/plugins/ctf/fs-src/file.c new file mode 100644 index 00000000..8b756496 --- /dev/null +++ b/plugins/ctf/fs-src/file.c @@ -0,0 +1,125 @@ +/* + * 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 + +#define PRINT_ERR_STREAM ctf_fs->error_fp +#define PRINT_PREFIX "ctf-fs-file" +#include "print.h" + +#include "file.h" + +BT_HIDDEN +void ctf_fs_file_destroy(struct ctf_fs_file *file) +{ + struct ctf_fs_component *ctf_fs;; + + if (!file) { + return; + } + + ctf_fs = file->ctf_fs; + + if (file->fp) { + PDBG("Closing file \"%s\" (%p)\n", file->path->str, file->fp); + + if (fclose(file->fp)) { + PERR("Cannot close file \"%s\": %s\n", file->path->str, + strerror(errno)); + } + } + + if (file->path) { + g_string_free(file->path, TRUE); + } + + g_free(file); +} + +BT_HIDDEN +struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs) +{ + struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1); + + if (!file) { + goto error; + } + + file->ctf_fs = ctf_fs; + file->path = g_string_new(NULL); + if (!file->path) { + goto error; + } + + goto end; + +error: + ctf_fs_file_destroy(file); + file = NULL; + +end: + return file; +} + +BT_HIDDEN +int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, + const char *mode) +{ + int ret = 0; + struct stat stat; + + PDBG("Opening file \"%s\" with mode \"%s\"\n", file->path->str, mode); + file->fp = fopen(file->path->str, mode); + if (!file->fp) { + PERR("Cannot open file \"%s\" with mode \"%s\": %s\n", + file->path->str, mode, strerror(errno)); + goto error; + } + + PDBG("Opened file: %p\n", file->fp); + + if (fstat(fileno(file->fp), &stat)) { + PERR("Cannot get file informations: %s\n", strerror(errno)); + goto error; + } + + file->size = stat.st_size; + PDBG(" File is %zu bytes\n", file->size); + goto end; + +error: + ret = -1; + + if (file->fp) { + if (fclose(file->fp)) { + PERR("Cannot close file \"%s\": %s\n", file->path->str, + strerror(errno)); + } + } + +end: + return ret; +} diff --git a/plugins/ctf/fs-src/file.h b/plugins/ctf/fs-src/file.h new file mode 100644 index 00000000..59f3d0ec --- /dev/null +++ b/plugins/ctf/fs-src/file.h @@ -0,0 +1,41 @@ +#ifndef CTF_FS_FILE_H +#define CTF_FS_FILE_H + +/* + * 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 "fs.h" + +BT_HIDDEN +void ctf_fs_file_destroy(struct ctf_fs_file *file); + +BT_HIDDEN +struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs); + +BT_HIDDEN +int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, + const char *mode); + +#endif /* CTF_FS_FILE_H */ diff --git a/plugins/ctf/fs-src/fs.c b/plugins/ctf/fs-src/fs.c new file mode 100644 index 00000000..2abd9b57 --- /dev/null +++ b/plugins/ctf/fs-src/fs.c @@ -0,0 +1,620 @@ +/* + * fs.c + * + * Babeltrace CTF file system Reader Component + * + * 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 +#include +#include "fs.h" +#include "metadata.h" +#include "data-stream.h" +#include "file.h" +#include "../common/metadata/decoder.h" + +#define PRINT_ERR_STREAM ctf_fs->error_fp +#define PRINT_PREFIX "ctf-fs" +#include "print.h" +#define METADATA_TEXT_SIG "/* CTF 1.8" + +BT_HIDDEN +bool ctf_fs_debug; + +struct bt_notification_iterator_next_return ctf_fs_iterator_next( + struct bt_private_notification_iterator *iterator) +{ + struct ctf_fs_stream *fs_stream = + bt_private_notification_iterator_get_user_data(iterator); + + return ctf_fs_stream_next(fs_stream); +} + +void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it) +{ + void *ctf_fs_stream = + bt_private_notification_iterator_get_user_data(it); + + ctf_fs_stream_destroy(ctf_fs_stream); +} + +enum bt_notification_iterator_status ctf_fs_iterator_init( + struct bt_private_notification_iterator *it, + struct bt_private_port *port) +{ + struct ctf_fs_stream *stream = NULL; + struct ctf_fs_component *ctf_fs; + struct ctf_fs_port_data *port_data; + struct bt_private_component *priv_comp = + bt_private_notification_iterator_get_private_component(it); + enum bt_notification_iterator_status ret = + BT_NOTIFICATION_ITERATOR_STATUS_OK; + + assert(priv_comp); + + ctf_fs = bt_private_component_get_user_data(priv_comp); + if (!ctf_fs) { + ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; + goto error; + } + + port_data = bt_private_port_get_user_data(port); + if (!port_data) { + ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; + goto error; + } + + stream = ctf_fs_stream_create(ctf_fs, port_data->path->str); + if (!stream) { + goto error; + } + + ret = bt_private_notification_iterator_set_user_data(it, stream); + if (ret) { + goto error; + } + + stream = NULL; + goto end; + +error: + (void) bt_private_notification_iterator_set_user_data(it, NULL); + + if (ret == BT_NOTIFICATION_ITERATOR_STATUS_OK) { + ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + } + +end: + ctf_fs_stream_destroy(stream); + bt_put(priv_comp); + return ret; +} + +static +void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs) +{ + if (!ctf_fs) { + return; + } + + if (ctf_fs->trace_path) { + g_string_free(ctf_fs->trace_path, TRUE); + } + + if (ctf_fs->port_data) { + g_ptr_array_free(ctf_fs->port_data, TRUE); + } + + if (ctf_fs->metadata) { + ctf_fs_metadata_fini(ctf_fs->metadata); + g_free(ctf_fs->metadata); + } + + bt_put(ctf_fs->cc_prio_map); + g_free(ctf_fs); +} + +void ctf_fs_finalize(struct bt_private_component *component) +{ + void *data = bt_private_component_get_user_data(component); + + ctf_fs_destroy_data(data); +} + +static +void port_data_destroy(void *data) { + struct ctf_fs_port_data *port_data = data; + + if (!port_data) { + return; + } + + if (port_data->path) { + g_string_free(port_data->path, TRUE); + } + + g_free(port_data); +} + +static +int create_one_port(struct ctf_fs_component *ctf_fs, + const char *stream_basename, const char *stream_path) +{ + int ret = 0; + struct bt_private_port *port = NULL; + struct ctf_fs_port_data *port_data = NULL; + GString *port_name = NULL; + + port_name = g_string_new(NULL); + if (!port_name) { + goto error; + } + + /* Assign the name for the new output port */ + g_string_assign(port_name, ""); + g_string_printf(port_name, "trace0-stream-%s", stream_basename); + PDBG("Creating one port named `%s` associated with path `%s`\n", + port_name->str, stream_path); + + /* Create output port for this file */ + port_data = g_new0(struct ctf_fs_port_data, 1); + if (!port_data) { + goto error; + } + + port_data->path = g_string_new(stream_path); + if (!port_data->path) { + goto error; + } + + port = bt_private_component_source_add_output_private_port( + ctf_fs->priv_comp, port_name->str, port_data); + if (!port) { + goto error; + } + + g_ptr_array_add(ctf_fs->port_data, port_data); + port_data = NULL; + goto end; + +error: + ret = -1; + +end: + if (port_name) { + g_string_free(port_name, TRUE); + } + + bt_put(port); + port_data_destroy(port_data); + return ret; +} + +static +int create_ports(struct ctf_fs_component *ctf_fs) +{ + int ret = 0; + const char *basename; + GError *error = NULL; + GDir *dir = NULL; + struct ctf_fs_file *file = NULL; + + /* Create one output port for each stream file */ + dir = g_dir_open(ctf_fs->trace_path->str, 0, &error); + if (!dir) { + PERR("Cannot open directory `%s`: %s (code %d)\n", + ctf_fs->trace_path->str, error->message, + error->code); + goto error; + } + + while ((basename = g_dir_read_name(dir))) { + if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) { + /* Ignore the metadata stream. */ + PDBG("Ignoring metadata file `%s`\n", basename); + continue; + } + + if (basename[0] == '.') { + PDBG("Ignoring hidden file `%s`\n", basename); + continue; + } + + /* Create the file. */ + file = ctf_fs_file_create(ctf_fs); + if (!file) { + PERR("Cannot create stream file object for file `%s`\n", + basename); + goto error; + } + + /* Create full path string. */ + g_string_append_printf(file->path, "%s/%s", + ctf_fs->trace_path->str, basename); + if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) { + PDBG("Ignoring non-regular file `%s`\n", basename); + ctf_fs_file_destroy(file); + file = NULL; + continue; + } + + ret = ctf_fs_file_open(ctf_fs, file, "rb"); + if (ret) { + PERR("Cannot open stream file `%s`\n", basename); + goto error; + } + + if (file->size == 0) { + /* Skip empty stream. */ + PDBG("Ignoring empty file `%s`\n", basename); + ctf_fs_file_destroy(file); + file = NULL; + continue; + } + + ret = create_one_port(ctf_fs, basename, file->path->str); + if (ret) { + PERR("Cannot create output port for file `%s`\n", + basename); + goto error; + } + + ctf_fs_file_destroy(file); + file = NULL; + } + + goto end; + +error: + ret = -1; + +end: + if (dir) { + g_dir_close(dir); + dir = NULL; + } + + if (error) { + g_error_free(error); + } + + ctf_fs_file_destroy(file); + return ret; +} + +static +int create_cc_prio_map(struct ctf_fs_component *ctf_fs) +{ + int ret = 0; + size_t i; + int count; + + assert(ctf_fs); + ctf_fs->cc_prio_map = bt_clock_class_priority_map_create(); + if (!ctf_fs->cc_prio_map) { + ret = -1; + goto end; + } + + count = bt_ctf_trace_get_clock_class_count(ctf_fs->metadata->trace); + assert(count >= 0); + + for (i = 0; i < count; i++) { + struct bt_ctf_clock_class *clock_class = + bt_ctf_trace_get_clock_class_by_index( + ctf_fs->metadata->trace, i); + + assert(clock_class); + ret = bt_clock_class_priority_map_add_clock_class( + ctf_fs->cc_prio_map, clock_class, 0); + BT_PUT(clock_class); + + if (ret) { + goto end; + } + } + +end: + return ret; +} + +static +struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, + struct bt_value *params) +{ + struct ctf_fs_component *ctf_fs; + struct bt_value *value = NULL; + const char *path; + int ret; + + ctf_fs = g_new0(struct ctf_fs_component, 1); + if (!ctf_fs) { + goto end; + } + + /* + * We don't need to get a new reference here because as long as + * our private ctf_fs_component object exists, the containing + * private component should also exist. + */ + ctf_fs->priv_comp = priv_comp; + + /* FIXME: should probably look for a source URI */ + value = bt_value_map_get(params, "path"); + if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { + goto error; + } + + ret = bt_value_string_get(value, &path); + if (ret) { + goto error; + } + + ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy); + if (!ctf_fs->port_data) { + goto error; + } + + ctf_fs->trace_path = g_string_new(path); + if (!ctf_fs->trace_path) { + BT_PUT(value); + goto error; + } + bt_put(value); + + value = bt_value_map_get(params, "offset-s"); + if (value) { + int64_t offset; + + if (!bt_value_is_integer(value)) { + fprintf(stderr, + "offset-s should be an integer\n"); + goto error; + } + ret = bt_value_integer_get(value, &offset); + if (ret != BT_VALUE_STATUS_OK) { + fprintf(stderr, + "Failed to get offset-s value\n"); + goto error; + } + ctf_fs->options.clock_offset = offset; + bt_put(value); + } + + value = bt_value_map_get(params, "offset-ns"); + if (value) { + int64_t offset; + + if (!bt_value_is_integer(value)) { + fprintf(stderr, + "offset-ns should be an integer\n"); + goto error; + } + ret = bt_value_integer_get(value, &offset); + if (ret != BT_VALUE_STATUS_OK) { + fprintf(stderr, + "Failed to get offset-ns value\n"); + goto error; + } + ctf_fs->options.clock_offset_ns = offset; + bt_put(value); + } + + ctf_fs->error_fp = stderr; + ctf_fs->page_size = (size_t) getpagesize(); + + // FIXME: check error. + ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1); + if (!ctf_fs->metadata) { + goto error; + } + + ret = ctf_fs_metadata_set_trace(ctf_fs); + if (ret) { + goto error; + } + + ret = create_cc_prio_map(ctf_fs); + if (ret) { + goto error; + } + + ret = create_ports(ctf_fs); + if (ret) { + goto error; + } + + goto end; + +error: + ctf_fs_destroy_data(ctf_fs); + ctf_fs = NULL; +end: + return ctf_fs; +} + +BT_HIDDEN +enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp, + struct bt_value *params, UNUSED_VAR void *init_method_data) +{ + struct ctf_fs_component *ctf_fs; + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + + assert(priv_comp); + ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0; + ctf_fs = ctf_fs_create(priv_comp, params); + if (!ctf_fs) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + ret = bt_private_component_set_user_data(priv_comp, ctf_fs); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } +end: + return ret; +error: + (void) bt_private_component_set_user_data(priv_comp, NULL); + ctf_fs_destroy_data(ctf_fs); + return ret; +} + +BT_HIDDEN +struct bt_value *ctf_fs_query(struct bt_component_class *comp_class, + const char *object, struct bt_value *params) +{ + struct bt_value *results = NULL; + struct bt_value *path_value = NULL; + char *metadata_text = NULL; + FILE *metadata_fp = NULL; + GString *g_metadata_text = NULL; + + if (strcmp(object, "metadata-info") == 0) { + int ret; + int bo; + const char *path; + bool is_packetized; + + results = bt_value_map_create(); + if (!results) { + goto error; + } + + if (!bt_value_is_map(params)) { + fprintf(stderr, + "Query parameters is not a map value object\n"); + goto error; + } + + path_value = bt_value_map_get(params, "path"); + ret = bt_value_string_get(path_value, &path); + if (ret) { + fprintf(stderr, + "Cannot get `path` string parameter\n"); + goto error; + } + + assert(path); + metadata_fp = ctf_fs_metadata_open_file(path); + if (!metadata_fp) { + fprintf(stderr, + "Cannot open trace at path `%s`\n", path); + goto error; + } + + is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp, + &bo); + + if (is_packetized) { + ret = ctf_metadata_decoder_packetized_file_stream_to_buf( + metadata_fp, &metadata_text, bo); + if (ret) { + fprintf(stderr, + "Cannot decode packetized metadata file\n"); + goto error; + } + } else { + long filesize; + + fseek(metadata_fp, 0, SEEK_END); + filesize = ftell(metadata_fp); + rewind(metadata_fp); + metadata_text = malloc(filesize + 1); + if (!metadata_text) { + fprintf(stderr, + "Cannot allocate buffer for metadata text\n"); + goto error; + } + + if (fread(metadata_text, filesize, 1, metadata_fp) != + 1) { + fprintf(stderr, + "Cannot read metadata file\n"); + goto error; + } + + metadata_text[filesize] = '\0'; + } + + g_metadata_text = g_string_new(NULL); + if (!g_metadata_text) { + goto error; + } + + if (strncmp(metadata_text, METADATA_TEXT_SIG, + sizeof(METADATA_TEXT_SIG) - 1) != 0) { + g_string_assign(g_metadata_text, METADATA_TEXT_SIG); + g_string_append(g_metadata_text, " */\n\n"); + } + + g_string_append(g_metadata_text, metadata_text); + + ret = bt_value_map_insert_string(results, "text", + g_metadata_text->str); + if (ret) { + fprintf(stderr, "Cannot insert metadata text into results\n"); + goto error; + } + + ret = bt_value_map_insert_bool(results, "is-packetized", + is_packetized); + if (ret) { + fprintf(stderr, "Cannot insert is packetized into results\n"); + goto error; + } + } else { + fprintf(stderr, "Unknown query object `%s`\n", object); + goto error; + } + + goto end; + +error: + BT_PUT(results); + +end: + bt_put(path_value); + free(metadata_text); + + if (g_metadata_text) { + g_string_free(g_metadata_text, TRUE); + } + + if (metadata_fp) { + fclose(metadata_fp); + } + return results; +} diff --git a/plugins/ctf/fs-src/fs.h b/plugins/ctf/fs-src/fs.h new file mode 100644 index 00000000..4619e79b --- /dev/null +++ b/plugins/ctf/fs-src/fs.h @@ -0,0 +1,121 @@ +#ifndef BABELTRACE_PLUGIN_CTF_FS_H +#define BABELTRACE_PLUGIN_CTF_FS_H + +/* + * BabelTrace - CTF on File System Component + * + * Copyright 2016 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * 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 "data-stream.h" + +BT_HIDDEN +extern bool ctf_fs_debug; + +struct ctf_fs_file { + struct ctf_fs_component *ctf_fs; + GString *path; + FILE *fp; + off_t size; +}; + +struct ctf_fs_metadata { + struct bt_ctf_trace *trace; + uint8_t uuid[16]; + bool is_uuid_set; + int bo; + char *text; +}; + +struct ctf_fs_stream { + struct ctf_fs_file *file; + struct bt_ctf_stream *stream; + struct bt_clock_class_priority_map *cc_prio_map; + struct bt_ctf_notif_iter *notif_iter; + /* A stream is assumed to be indexed. */ + struct index index; + void *mmap_addr; + /* Max length of chunk to mmap() when updating the current mapping. */ + size_t mmap_max_len; + /* Length of the current mapping. */ + size_t mmap_len; + /* Length of the current mapping which *exists* in the backing file. */ + size_t mmap_valid_len; + /* Offset in the file where the current mapping starts. */ + off_t mmap_offset; + /* + * Offset, in the current mapping, of the address to return on the next + * request. + */ + off_t request_offset; + bool end_reached; +}; + +struct ctf_fs_component_options { + uint64_t clock_offset; + uint64_t clock_offset_ns; +}; + +struct ctf_fs_port_data { + GString *path; +}; + +struct ctf_fs_component { + struct bt_private_component *priv_comp; + GString *trace_path; + FILE *error_fp; + size_t page_size; + struct ctf_fs_component_options options; + struct ctf_fs_metadata *metadata; + struct bt_clock_class_priority_map *cc_prio_map; + + /* Array of struct ctf_fs_port_data *, owned by this */ + GPtrArray *port_data; +}; + +BT_HIDDEN +enum bt_component_status ctf_fs_init(struct bt_private_component *source, + struct bt_value *params, void *init_method_data); + +BT_HIDDEN +void ctf_fs_finalize(struct bt_private_component *component); + +BT_HIDDEN +enum bt_notification_iterator_status ctf_fs_iterator_init( + struct bt_private_notification_iterator *it, + struct bt_private_port *port); + +void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it); + +struct bt_notification_iterator_next_return ctf_fs_iterator_next( + struct bt_private_notification_iterator *iterator); + +BT_HIDDEN +struct bt_value *ctf_fs_query(struct bt_component_class *comp_class, + const char *object, struct bt_value *params); + +#endif /* BABELTRACE_PLUGIN_CTF_FS_H */ diff --git a/plugins/ctf/fs-src/lttng-index.h b/plugins/ctf/fs-src/lttng-index.h new file mode 100644 index 00000000..05629f86 --- /dev/null +++ b/plugins/ctf/fs-src/lttng-index.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * David Goulet + * + * 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. + */ + +#ifndef LTTNG_INDEX_H +#define LTTNG_INDEX_H + +#include + +#define CTF_INDEX_MAGIC 0xC1F1DCC1 +#define CTF_INDEX_MAJOR 1 +#define CTF_INDEX_MINOR 1 + +/* + * Header at the beginning of each index file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index_file_hdr { + uint32_t magic; + uint32_t index_major; + uint32_t index_minor; + /* size of struct ctf_packet_index, in bytes. */ + uint32_t packet_index_len; +} __attribute__((__packed__)); + +/* + * Packet index generated for each trace packet store in a trace file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index { + uint64_t offset; /* offset of the packet in the file, in bytes */ + uint64_t packet_size; /* packet size, in bits */ + uint64_t content_size; /* content size, in bits */ + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t stream_id; + /* CTF_INDEX 1.0 limit */ + uint64_t stream_instance_id; /* ID of the channel instance */ + uint64_t packet_seq_num; /* packet sequence number */ +} __attribute__((__packed__)); + +#endif /* LTTNG_INDEX_H */ diff --git a/plugins/ctf/fs-src/metadata.c b/plugins/ctf/fs-src/metadata.c new file mode 100644 index 00000000..cd211961 --- /dev/null +++ b/plugins/ctf/fs-src/metadata.c @@ -0,0 +1,154 @@ +/* + * Copyright 2016 - Philippe Proulx + * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation + * + * Some functions are based on older functions written by Mathieu Desnoyers. + * + * 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 + +#define PRINT_ERR_STREAM ctf_fs->error_fp +#define PRINT_PREFIX "ctf-fs-metadata" +#include "print.h" + +#include "fs.h" +#include "file.h" +#include "metadata.h" +#include "../common/metadata/decoder.h" + +#define NSEC_PER_SEC 1000000000LL + +BT_HIDDEN +FILE *ctf_fs_metadata_open_file(const char *trace_path) +{ + GString *metadata_path = g_string_new(trace_path); + FILE *fp = NULL; + + if (!metadata_path) { + goto error; + } + + g_string_append(metadata_path, "/" CTF_FS_METADATA_FILENAME); + fp = fopen(metadata_path->str, "rb"); + if (!fp) { + goto error; + } + + goto end; + +error: + if (fp) { + fclose(fp); + fp = NULL; + } + +end: + g_string_free(metadata_path, TRUE); + return fp; +} + +static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs, + const char *trace_path) +{ + struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs); + + if (!file) { + goto error; + } + + g_string_append(file->path, trace_path); + g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME); + + if (ctf_fs_file_open(ctf_fs, file, "rb")) { + goto error; + } + + goto end; + +error: + if (file) { + ctf_fs_file_destroy(file); + file = NULL; + } + +end: + return file; +} + +int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) +{ + int ret = 0; + struct ctf_fs_file *file = NULL; + struct ctf_metadata_decoder *metadata_decoder = NULL; + + file = get_file(ctf_fs, ctf_fs->trace_path->str); + if (!file) { + PERR("Cannot create metadata file object\n"); + goto end; + } + + metadata_decoder = ctf_metadata_decoder_create(ctf_fs->error_fp, + ctf_fs->options.clock_offset * NSEC_PER_SEC + + ctf_fs->options.clock_offset_ns); + if (!metadata_decoder) { + PERR("Cannot create metadata decoder object\n"); + goto end; + } + + ret = ctf_metadata_decoder_decode(metadata_decoder, file->fp); + if (ret) { + PERR("Cannot decode metadata file\n"); + goto end; + } + + ctf_fs->metadata->trace = ctf_metadata_decoder_get_trace( + metadata_decoder); + assert(ctf_fs->metadata->trace); + +end: + ctf_fs_file_destroy(file); + ctf_metadata_decoder_destroy(metadata_decoder); + return ret; +} + +int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata) +{ + /* Nothing to initialize for the moment. */ + return 0; +} + +void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata) +{ + if (metadata->text) { + free(metadata->text); + } + + if (metadata->trace) { + BT_PUT(metadata->trace); + } +} diff --git a/plugins/ctf/fs-src/metadata.h b/plugins/ctf/fs-src/metadata.h new file mode 100644 index 00000000..85a77268 --- /dev/null +++ b/plugins/ctf/fs-src/metadata.h @@ -0,0 +1,53 @@ +#ifndef CTF_FS_METADATA_H +#define CTF_FS_METADATA_H + +/* + * 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 "fs.h" + +#define CTF_FS_METADATA_FILENAME "metadata" + +BT_HIDDEN +int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata); + +BT_HIDDEN +void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata); + +BT_HIDDEN +int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs); + +BT_HIDDEN +FILE *ctf_fs_metadata_open_file(const char *trace_path); + +BT_HIDDEN +bool ctf_metadata_is_packetized(FILE *fp, int *byte_order); + +BT_HIDDEN +int ctf_metadata_packetized_file_to_buf(struct ctf_fs_component *ctf_fs, + FILE *fp, uint8_t **buf, int byte_order); + +#endif /* CTF_FS_METADATA_H */ diff --git a/plugins/ctf/fs-src/print.h b/plugins/ctf/fs-src/print.h new file mode 100644 index 00000000..9daf7ea4 --- /dev/null +++ b/plugins/ctf/fs-src/print.h @@ -0,0 +1,57 @@ +#ifndef CTF_FS_PRINT_H +#define CTF_FS_PRINT_H + +/* + * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file. + * + * Copyright (c) 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 + +#define PERR(fmt, ...) \ + do { \ + if (PRINT_ERR_STREAM) { \ + fprintf(PRINT_ERR_STREAM, \ + "Error: " PRINT_PREFIX ": " fmt, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define PWARN(fmt, ...) \ + do { \ + if (PRINT_ERR_STREAM) { \ + fprintf(PRINT_ERR_STREAM, \ + "Warning: " PRINT_PREFIX ": " fmt, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define PDBG(fmt, ...) \ + do { \ + if (ctf_fs_debug) { \ + fprintf(stderr, \ + "Debug: " PRINT_PREFIX ": " fmt, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#endif /* CTF_FS_PRINT_H */ diff --git a/plugins/ctf/fs/Makefile.am b/plugins/ctf/fs/Makefile.am deleted file mode 100644 index 3c5c8b6f..00000000 --- a/plugins/ctf/fs/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins - -noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-fs.la - -libbabeltrace_plugin_ctf_fs_la_LIBADD = \ - $(builddir)/../common/libbabeltrace-plugin-ctf-common.la -libbabeltrace_plugin_ctf_fs_la_SOURCES = \ - fs.c \ - data-stream.c \ - metadata.c \ - file.c \ - data-stream.h \ - file.h \ - fs.h \ - lttng-index.h \ - metadata.h \ - print.h diff --git a/plugins/ctf/fs/data-stream.c b/plugins/ctf/fs/data-stream.c deleted file mode 100644 index 38843d7b..00000000 --- a/plugins/ctf/fs/data-stream.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright 2016 - Philippe Proulx - * Copyright 2016 - Jérémie Galarneau - * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation - * - * 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 "file.h" -#include "metadata.h" -#include "../common/notif-iter/notif-iter.h" -#include -#include "data-stream.h" - -#define PRINT_ERR_STREAM ctf_fs->error_fp -#define PRINT_PREFIX "ctf-fs-data-stream" -#include "print.h" - -static inline -size_t remaining_mmap_bytes(struct ctf_fs_stream *stream) -{ - return stream->mmap_valid_len - stream->request_offset; -} - -static -int stream_munmap(struct ctf_fs_stream *stream) -{ - int ret = 0; - struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; - - if (munmap(stream->mmap_addr, stream->mmap_len)) { - PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n", - stream->mmap_addr, stream->mmap_len, - stream->file->path->str, stream->file->fp, - strerror(errno)); - ret = -1; - goto end; - } -end: - return ret; -} - -static -enum bt_ctf_notif_iter_medium_status mmap_next(struct ctf_fs_stream *stream) -{ - enum bt_ctf_notif_iter_medium_status ret = - BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK; - struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; - - /* Unmap old region */ - if (stream->mmap_addr) { - if (stream_munmap(stream)) { - goto error; - } - - stream->mmap_offset += stream->mmap_valid_len; - stream->request_offset = 0; - } - - stream->mmap_valid_len = MIN(stream->file->size - stream->mmap_offset, - stream->mmap_max_len); - if (stream->mmap_valid_len == 0) { - ret = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF; - goto end; - } - /* Round up to next page, assuming page size being a power of 2. */ - stream->mmap_len = (stream->mmap_valid_len + ctf_fs->page_size - 1) - & ~(ctf_fs->page_size - 1); - /* Map new region */ - assert(stream->mmap_len); - stream->mmap_addr = mmap((void *) 0, stream->mmap_len, - PROT_READ, MAP_PRIVATE, fileno(stream->file->fp), - stream->mmap_offset); - if (stream->mmap_addr == MAP_FAILED) { - PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n", - stream->mmap_len, stream->file->path->str, - stream->file->fp, stream->mmap_offset, - strerror(errno)); - goto error; - } - - goto end; -error: - stream_munmap(stream); - ret = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR; -end: - return ret; -} - -static -enum bt_ctf_notif_iter_medium_status medop_request_bytes( - size_t request_sz, uint8_t **buffer_addr, - size_t *buffer_sz, void *data) -{ - enum bt_ctf_notif_iter_medium_status status = - BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK; - struct ctf_fs_stream *stream = data; - struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; - - if (request_sz == 0) { - goto end; - } - - /* Check if we have at least one memory-mapped byte left */ - if (remaining_mmap_bytes(stream) == 0) { - /* Are we at the end of the file? */ - if (stream->mmap_offset >= stream->file->size) { - PDBG("Reached end of file \"%s\" (%p)\n", - stream->file->path->str, stream->file->fp); - status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF; - goto end; - } - - status = mmap_next(stream); - switch (status) { - case BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK: - break; - case BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF: - goto end; - default: - PERR("Cannot memory-map next region of file \"%s\" (%p)\n", - stream->file->path->str, - stream->file->fp); - goto error; - } - } - - *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz); - *buffer_addr = ((uint8_t *) stream->mmap_addr) + stream->request_offset; - stream->request_offset += *buffer_sz; - goto end; - -error: - status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR; - -end: - return status; -} - -static -struct bt_ctf_stream *medop_get_stream( - struct bt_ctf_stream_class *stream_class, void *data) -{ - struct ctf_fs_stream *fs_stream = data; - struct ctf_fs_component *ctf_fs = fs_stream->file->ctf_fs; - - if (!fs_stream->stream) { - int64_t id = bt_ctf_stream_class_get_id(stream_class); - - PDBG("Creating stream out of stream class %" PRId64 "\n", id); - fs_stream->stream = bt_ctf_stream_create(stream_class, - fs_stream->file->path->str); - if (!fs_stream->stream) { - PERR("Cannot create stream (stream class %" PRId64 ")\n", - id); - } - } - - return fs_stream->stream; -} - -static struct bt_ctf_notif_iter_medium_ops medops = { - .request_bytes = medop_request_bytes, - .get_stream = medop_get_stream, -}; - -static -int build_index_from_idx_file(struct ctf_fs_stream *stream) -{ - int ret = 0; - gchar *directory = NULL; - gchar *basename = NULL; - GString *index_basename = NULL; - gchar *index_file_path = NULL; - GMappedFile *mapped_file = NULL; - gsize filesize; - const struct ctf_packet_index_file_hdr *header; - const char *mmap_begin, *file_pos; - struct index_entry *index; - uint64_t total_packets_size = 0; - size_t file_index_entry_size; - size_t file_entry_count; - size_t i; - - /* Look for index file in relative path index/name.idx. */ - basename = g_path_get_basename(stream->file->path->str); - if (!basename) { - ret = -1; - goto end; - } - - directory = g_path_get_dirname(stream->file->path->str); - if (!directory) { - ret = -1; - goto end; - } - - index_basename = g_string_new(basename); - if (!index_basename) { - ret = -1; - goto end; - } - - g_string_append(index_basename, ".idx"); - index_file_path = g_build_filename(directory, "index", - index_basename->str, NULL); - mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL); - if (!mapped_file) { - ret = -1; - goto end; - } - filesize = g_mapped_file_get_length(mapped_file); - if (filesize < sizeof(*header)) { - printf_error("Invalid LTTng trace index: file size < header size"); - ret = -1; - goto end; - } - - mmap_begin = g_mapped_file_get_contents(mapped_file); - header = (struct ctf_packet_index_file_hdr *) mmap_begin; - - file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header); - if (be32toh(header->magic) != CTF_INDEX_MAGIC) { - printf_error("Invalid LTTng trace index: \"magic\" validation failed"); - ret = -1; - goto end; - } - - file_index_entry_size = be32toh(header->packet_index_len); - file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size; - if ((filesize - sizeof(*header)) % (file_entry_count * file_index_entry_size)) { - printf_error("Invalid index file size; not a multiple of index entry size"); - ret = -1; - goto end; - } - - stream->index.entries = g_array_sized_new(FALSE, TRUE, - sizeof(struct index_entry), file_entry_count); - if (!stream->index.entries) { - ret = -1; - goto end; - } - index = (struct index_entry *) stream->index.entries->data; - for (i = 0; i < file_entry_count; i++) { - struct ctf_packet_index *file_index = - (struct ctf_packet_index *) file_pos; - uint64_t packet_size = be64toh(file_index->packet_size); - - if (packet_size % CHAR_BIT) { - ret = -1; - printf_error("Invalid packet size encountered in index file"); - goto invalid_index; - } - - /* Convert size in bits to bytes. */ - packet_size /= CHAR_BIT; - index->packet_size = packet_size; - - index->offset = be64toh(file_index->offset); - if (i != 0 && index->offset < (index - 1)->offset) { - printf_error("Invalid, non-monotonic, packet offset encountered in index file"); - ret = -1; - goto invalid_index; - } - - index->timestamp_begin = be64toh(file_index->timestamp_begin); - index->timestamp_end = be64toh(file_index->timestamp_end); - if (index->timestamp_end < index->timestamp_begin) { - printf_error("Invalid packet time bounds encountered in index file"); - ret = -1; - goto invalid_index; - } - - total_packets_size += packet_size; - file_pos += file_index_entry_size; - index++; - } - - /* Validate that the index addresses the complete stream. */ - if (stream->file->size != total_packets_size) { - printf_error("Invalid index; indexed size != stream file size"); - ret = -1; - goto invalid_index; - } -end: - g_free(directory); - g_free(basename); - g_free(index_file_path); - if (index_basename) { - g_string_free(index_basename, TRUE); - } - if (mapped_file) { - g_mapped_file_unref(mapped_file); - } - return ret; -invalid_index: - g_array_free(stream->index.entries, TRUE); - goto end; -} - -static -int build_index_from_stream(struct ctf_fs_stream *stream) -{ - return 0; -} - -static -int init_stream_index(struct ctf_fs_stream *stream) -{ - int ret; - - ret = build_index_from_idx_file(stream); - if (!ret) { - goto end; - } - - ret = build_index_from_stream(stream); -end: - return ret; -} - -BT_HIDDEN -struct ctf_fs_stream *ctf_fs_stream_create( - struct ctf_fs_component *ctf_fs, const char *path) -{ - int ret; - struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1); - - if (!stream) { - goto error; - } - - stream->file = ctf_fs_file_create(ctf_fs); - if (!stream->file) { - goto error; - } - - stream->cc_prio_map = bt_get(ctf_fs->cc_prio_map); - g_string_assign(stream->file->path, path); - ret = ctf_fs_file_open(ctf_fs, stream->file, "rb"); - if (ret) { - goto error; - } - - stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata->trace, - ctf_fs->page_size, medops, stream, - ctf_fs->error_fp); - if (!stream->notif_iter) { - goto error; - } - - stream->mmap_max_len = ctf_fs->page_size * 2048; - ret = init_stream_index(stream); - if (ret) { - goto error; - } - goto end; -error: - /* Do not touch "borrowed" file. */ - ctf_fs_stream_destroy(stream); - stream = NULL; -end: - return stream; -} - -BT_HIDDEN -void ctf_fs_stream_destroy(struct ctf_fs_stream *stream) -{ - if (!stream) { - return; - } - - bt_put(stream->cc_prio_map); - - if (stream->file) { - ctf_fs_file_destroy(stream->file); - } - - if (stream->stream) { - BT_PUT(stream->stream); - } - - if (stream->notif_iter) { - bt_ctf_notif_iter_destroy(stream->notif_iter); - } - - if (stream->index.entries) { - g_array_free(stream->index.entries, TRUE); - } - - g_free(stream); -} - -BT_HIDDEN -struct bt_notification_iterator_next_return ctf_fs_stream_next( - struct ctf_fs_stream *stream) -{ - enum bt_ctf_notif_iter_status notif_iter_status; - struct bt_notification_iterator_next_return ret = { - .status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR, - .notification = NULL, - }; - - if (stream->end_reached) { - notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_EOF; - goto translate_status; - } - - notif_iter_status = bt_ctf_notif_iter_get_next_notification(stream->notif_iter, - stream->cc_prio_map, &ret.notification); - if (notif_iter_status != BT_CTF_NOTIF_ITER_STATUS_OK && - notif_iter_status != BT_CTF_NOTIF_ITER_STATUS_EOF) { - goto translate_status; - } - - /* Should be handled in bt_ctf_notif_iter_get_next_notification. */ - if (notif_iter_status == BT_CTF_NOTIF_ITER_STATUS_EOF) { - ret.notification = bt_notification_stream_end_create( - stream->stream); - if (!ret.notification) { - notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_ERROR; - goto translate_status; - } - - notif_iter_status = BT_CTF_NOTIF_ITER_STATUS_OK; - stream->end_reached = true; - } - -translate_status: - switch (notif_iter_status) { - case BT_CTF_NOTIF_ITER_STATUS_EOF: - ret.status = BT_NOTIFICATION_ITERATOR_STATUS_END; - break; - case BT_CTF_NOTIF_ITER_STATUS_OK: - ret.status = BT_NOTIFICATION_ITERATOR_STATUS_OK; - break; - case BT_CTF_NOTIF_ITER_STATUS_AGAIN: - /* - * Should not make it this far as this is - * medium-specific; there is nothing for the user to do - * and it should have been handled upstream. - */ - assert(false); - case BT_CTF_NOTIF_ITER_STATUS_INVAL: - case BT_CTF_NOTIF_ITER_STATUS_ERROR: - default: - ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; - break; - } - - return ret; -} diff --git a/plugins/ctf/fs/data-stream.h b/plugins/ctf/fs/data-stream.h deleted file mode 100644 index 3d484425..00000000 --- a/plugins/ctf/fs/data-stream.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef CTF_FS_DATA_STREAM_H -#define CTF_FS_DATA_STREAM_H - -/* - * 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 "../common/notif-iter/notif-iter.h" -#include "lttng-index.h" - -struct ctf_fs_component; -struct ctf_fs_file; -struct ctf_fs_stream; - -struct index_entry { - uint64_t offset; /* in bytes. */ - uint64_t packet_size; /* in bytes. */ - /* relative to the packet context field's mapped clock. */ - uint64_t timestamp_begin, timestamp_end; -}; - -struct index { - GArray *entries; /* Array of struct index_entry. */ -}; - -BT_HIDDEN -struct ctf_fs_stream *ctf_fs_stream_create( - struct ctf_fs_component *ctf_fs, const char *path); - -BT_HIDDEN -void ctf_fs_stream_destroy(struct ctf_fs_stream *stream); - -BT_HIDDEN -int ctf_fs_data_stream_open_streams(struct ctf_fs_component *ctf_fs); - -BT_HIDDEN -struct bt_notification_iterator_next_return ctf_fs_stream_next( - struct ctf_fs_stream *stream); - -#endif /* CTF_FS_DATA_STREAM_H */ diff --git a/plugins/ctf/fs/file.c b/plugins/ctf/fs/file.c deleted file mode 100644 index 8b756496..00000000 --- a/plugins/ctf/fs/file.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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 - -#define PRINT_ERR_STREAM ctf_fs->error_fp -#define PRINT_PREFIX "ctf-fs-file" -#include "print.h" - -#include "file.h" - -BT_HIDDEN -void ctf_fs_file_destroy(struct ctf_fs_file *file) -{ - struct ctf_fs_component *ctf_fs;; - - if (!file) { - return; - } - - ctf_fs = file->ctf_fs; - - if (file->fp) { - PDBG("Closing file \"%s\" (%p)\n", file->path->str, file->fp); - - if (fclose(file->fp)) { - PERR("Cannot close file \"%s\": %s\n", file->path->str, - strerror(errno)); - } - } - - if (file->path) { - g_string_free(file->path, TRUE); - } - - g_free(file); -} - -BT_HIDDEN -struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs) -{ - struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1); - - if (!file) { - goto error; - } - - file->ctf_fs = ctf_fs; - file->path = g_string_new(NULL); - if (!file->path) { - goto error; - } - - goto end; - -error: - ctf_fs_file_destroy(file); - file = NULL; - -end: - return file; -} - -BT_HIDDEN -int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, - const char *mode) -{ - int ret = 0; - struct stat stat; - - PDBG("Opening file \"%s\" with mode \"%s\"\n", file->path->str, mode); - file->fp = fopen(file->path->str, mode); - if (!file->fp) { - PERR("Cannot open file \"%s\" with mode \"%s\": %s\n", - file->path->str, mode, strerror(errno)); - goto error; - } - - PDBG("Opened file: %p\n", file->fp); - - if (fstat(fileno(file->fp), &stat)) { - PERR("Cannot get file informations: %s\n", strerror(errno)); - goto error; - } - - file->size = stat.st_size; - PDBG(" File is %zu bytes\n", file->size); - goto end; - -error: - ret = -1; - - if (file->fp) { - if (fclose(file->fp)) { - PERR("Cannot close file \"%s\": %s\n", file->path->str, - strerror(errno)); - } - } - -end: - return ret; -} diff --git a/plugins/ctf/fs/file.h b/plugins/ctf/fs/file.h deleted file mode 100644 index 59f3d0ec..00000000 --- a/plugins/ctf/fs/file.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CTF_FS_FILE_H -#define CTF_FS_FILE_H - -/* - * 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 "fs.h" - -BT_HIDDEN -void ctf_fs_file_destroy(struct ctf_fs_file *file); - -BT_HIDDEN -struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs); - -BT_HIDDEN -int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, - const char *mode); - -#endif /* CTF_FS_FILE_H */ diff --git a/plugins/ctf/fs/fs.c b/plugins/ctf/fs/fs.c deleted file mode 100644 index 2abd9b57..00000000 --- a/plugins/ctf/fs/fs.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * fs.c - * - * Babeltrace CTF file system Reader Component - * - * 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 -#include -#include "fs.h" -#include "metadata.h" -#include "data-stream.h" -#include "file.h" -#include "../common/metadata/decoder.h" - -#define PRINT_ERR_STREAM ctf_fs->error_fp -#define PRINT_PREFIX "ctf-fs" -#include "print.h" -#define METADATA_TEXT_SIG "/* CTF 1.8" - -BT_HIDDEN -bool ctf_fs_debug; - -struct bt_notification_iterator_next_return ctf_fs_iterator_next( - struct bt_private_notification_iterator *iterator) -{ - struct ctf_fs_stream *fs_stream = - bt_private_notification_iterator_get_user_data(iterator); - - return ctf_fs_stream_next(fs_stream); -} - -void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it) -{ - void *ctf_fs_stream = - bt_private_notification_iterator_get_user_data(it); - - ctf_fs_stream_destroy(ctf_fs_stream); -} - -enum bt_notification_iterator_status ctf_fs_iterator_init( - struct bt_private_notification_iterator *it, - struct bt_private_port *port) -{ - struct ctf_fs_stream *stream = NULL; - struct ctf_fs_component *ctf_fs; - struct ctf_fs_port_data *port_data; - struct bt_private_component *priv_comp = - bt_private_notification_iterator_get_private_component(it); - enum bt_notification_iterator_status ret = - BT_NOTIFICATION_ITERATOR_STATUS_OK; - - assert(priv_comp); - - ctf_fs = bt_private_component_get_user_data(priv_comp); - if (!ctf_fs) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; - goto error; - } - - port_data = bt_private_port_get_user_data(port); - if (!port_data) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; - goto error; - } - - stream = ctf_fs_stream_create(ctf_fs, port_data->path->str); - if (!stream) { - goto error; - } - - ret = bt_private_notification_iterator_set_user_data(it, stream); - if (ret) { - goto error; - } - - stream = NULL; - goto end; - -error: - (void) bt_private_notification_iterator_set_user_data(it, NULL); - - if (ret == BT_NOTIFICATION_ITERATOR_STATUS_OK) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; - } - -end: - ctf_fs_stream_destroy(stream); - bt_put(priv_comp); - return ret; -} - -static -void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs) -{ - if (!ctf_fs) { - return; - } - - if (ctf_fs->trace_path) { - g_string_free(ctf_fs->trace_path, TRUE); - } - - if (ctf_fs->port_data) { - g_ptr_array_free(ctf_fs->port_data, TRUE); - } - - if (ctf_fs->metadata) { - ctf_fs_metadata_fini(ctf_fs->metadata); - g_free(ctf_fs->metadata); - } - - bt_put(ctf_fs->cc_prio_map); - g_free(ctf_fs); -} - -void ctf_fs_finalize(struct bt_private_component *component) -{ - void *data = bt_private_component_get_user_data(component); - - ctf_fs_destroy_data(data); -} - -static -void port_data_destroy(void *data) { - struct ctf_fs_port_data *port_data = data; - - if (!port_data) { - return; - } - - if (port_data->path) { - g_string_free(port_data->path, TRUE); - } - - g_free(port_data); -} - -static -int create_one_port(struct ctf_fs_component *ctf_fs, - const char *stream_basename, const char *stream_path) -{ - int ret = 0; - struct bt_private_port *port = NULL; - struct ctf_fs_port_data *port_data = NULL; - GString *port_name = NULL; - - port_name = g_string_new(NULL); - if (!port_name) { - goto error; - } - - /* Assign the name for the new output port */ - g_string_assign(port_name, ""); - g_string_printf(port_name, "trace0-stream-%s", stream_basename); - PDBG("Creating one port named `%s` associated with path `%s`\n", - port_name->str, stream_path); - - /* Create output port for this file */ - port_data = g_new0(struct ctf_fs_port_data, 1); - if (!port_data) { - goto error; - } - - port_data->path = g_string_new(stream_path); - if (!port_data->path) { - goto error; - } - - port = bt_private_component_source_add_output_private_port( - ctf_fs->priv_comp, port_name->str, port_data); - if (!port) { - goto error; - } - - g_ptr_array_add(ctf_fs->port_data, port_data); - port_data = NULL; - goto end; - -error: - ret = -1; - -end: - if (port_name) { - g_string_free(port_name, TRUE); - } - - bt_put(port); - port_data_destroy(port_data); - return ret; -} - -static -int create_ports(struct ctf_fs_component *ctf_fs) -{ - int ret = 0; - const char *basename; - GError *error = NULL; - GDir *dir = NULL; - struct ctf_fs_file *file = NULL; - - /* Create one output port for each stream file */ - dir = g_dir_open(ctf_fs->trace_path->str, 0, &error); - if (!dir) { - PERR("Cannot open directory `%s`: %s (code %d)\n", - ctf_fs->trace_path->str, error->message, - error->code); - goto error; - } - - while ((basename = g_dir_read_name(dir))) { - if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) { - /* Ignore the metadata stream. */ - PDBG("Ignoring metadata file `%s`\n", basename); - continue; - } - - if (basename[0] == '.') { - PDBG("Ignoring hidden file `%s`\n", basename); - continue; - } - - /* Create the file. */ - file = ctf_fs_file_create(ctf_fs); - if (!file) { - PERR("Cannot create stream file object for file `%s`\n", - basename); - goto error; - } - - /* Create full path string. */ - g_string_append_printf(file->path, "%s/%s", - ctf_fs->trace_path->str, basename); - if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) { - PDBG("Ignoring non-regular file `%s`\n", basename); - ctf_fs_file_destroy(file); - file = NULL; - continue; - } - - ret = ctf_fs_file_open(ctf_fs, file, "rb"); - if (ret) { - PERR("Cannot open stream file `%s`\n", basename); - goto error; - } - - if (file->size == 0) { - /* Skip empty stream. */ - PDBG("Ignoring empty file `%s`\n", basename); - ctf_fs_file_destroy(file); - file = NULL; - continue; - } - - ret = create_one_port(ctf_fs, basename, file->path->str); - if (ret) { - PERR("Cannot create output port for file `%s`\n", - basename); - goto error; - } - - ctf_fs_file_destroy(file); - file = NULL; - } - - goto end; - -error: - ret = -1; - -end: - if (dir) { - g_dir_close(dir); - dir = NULL; - } - - if (error) { - g_error_free(error); - } - - ctf_fs_file_destroy(file); - return ret; -} - -static -int create_cc_prio_map(struct ctf_fs_component *ctf_fs) -{ - int ret = 0; - size_t i; - int count; - - assert(ctf_fs); - ctf_fs->cc_prio_map = bt_clock_class_priority_map_create(); - if (!ctf_fs->cc_prio_map) { - ret = -1; - goto end; - } - - count = bt_ctf_trace_get_clock_class_count(ctf_fs->metadata->trace); - assert(count >= 0); - - for (i = 0; i < count; i++) { - struct bt_ctf_clock_class *clock_class = - bt_ctf_trace_get_clock_class_by_index( - ctf_fs->metadata->trace, i); - - assert(clock_class); - ret = bt_clock_class_priority_map_add_clock_class( - ctf_fs->cc_prio_map, clock_class, 0); - BT_PUT(clock_class); - - if (ret) { - goto end; - } - } - -end: - return ret; -} - -static -struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp, - struct bt_value *params) -{ - struct ctf_fs_component *ctf_fs; - struct bt_value *value = NULL; - const char *path; - int ret; - - ctf_fs = g_new0(struct ctf_fs_component, 1); - if (!ctf_fs) { - goto end; - } - - /* - * We don't need to get a new reference here because as long as - * our private ctf_fs_component object exists, the containing - * private component should also exist. - */ - ctf_fs->priv_comp = priv_comp; - - /* FIXME: should probably look for a source URI */ - value = bt_value_map_get(params, "path"); - if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { - goto error; - } - - ret = bt_value_string_get(value, &path); - if (ret) { - goto error; - } - - ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy); - if (!ctf_fs->port_data) { - goto error; - } - - ctf_fs->trace_path = g_string_new(path); - if (!ctf_fs->trace_path) { - BT_PUT(value); - goto error; - } - bt_put(value); - - value = bt_value_map_get(params, "offset-s"); - if (value) { - int64_t offset; - - if (!bt_value_is_integer(value)) { - fprintf(stderr, - "offset-s should be an integer\n"); - goto error; - } - ret = bt_value_integer_get(value, &offset); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(stderr, - "Failed to get offset-s value\n"); - goto error; - } - ctf_fs->options.clock_offset = offset; - bt_put(value); - } - - value = bt_value_map_get(params, "offset-ns"); - if (value) { - int64_t offset; - - if (!bt_value_is_integer(value)) { - fprintf(stderr, - "offset-ns should be an integer\n"); - goto error; - } - ret = bt_value_integer_get(value, &offset); - if (ret != BT_VALUE_STATUS_OK) { - fprintf(stderr, - "Failed to get offset-ns value\n"); - goto error; - } - ctf_fs->options.clock_offset_ns = offset; - bt_put(value); - } - - ctf_fs->error_fp = stderr; - ctf_fs->page_size = (size_t) getpagesize(); - - // FIXME: check error. - ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1); - if (!ctf_fs->metadata) { - goto error; - } - - ret = ctf_fs_metadata_set_trace(ctf_fs); - if (ret) { - goto error; - } - - ret = create_cc_prio_map(ctf_fs); - if (ret) { - goto error; - } - - ret = create_ports(ctf_fs); - if (ret) { - goto error; - } - - goto end; - -error: - ctf_fs_destroy_data(ctf_fs); - ctf_fs = NULL; -end: - return ctf_fs; -} - -BT_HIDDEN -enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp, - struct bt_value *params, UNUSED_VAR void *init_method_data) -{ - struct ctf_fs_component *ctf_fs; - enum bt_component_status ret = BT_COMPONENT_STATUS_OK; - - assert(priv_comp); - ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0; - ctf_fs = ctf_fs_create(priv_comp, params); - if (!ctf_fs) { - ret = BT_COMPONENT_STATUS_NOMEM; - goto end; - } - - ret = bt_private_component_set_user_data(priv_comp, ctf_fs); - if (ret != BT_COMPONENT_STATUS_OK) { - goto error; - } -end: - return ret; -error: - (void) bt_private_component_set_user_data(priv_comp, NULL); - ctf_fs_destroy_data(ctf_fs); - return ret; -} - -BT_HIDDEN -struct bt_value *ctf_fs_query(struct bt_component_class *comp_class, - const char *object, struct bt_value *params) -{ - struct bt_value *results = NULL; - struct bt_value *path_value = NULL; - char *metadata_text = NULL; - FILE *metadata_fp = NULL; - GString *g_metadata_text = NULL; - - if (strcmp(object, "metadata-info") == 0) { - int ret; - int bo; - const char *path; - bool is_packetized; - - results = bt_value_map_create(); - if (!results) { - goto error; - } - - if (!bt_value_is_map(params)) { - fprintf(stderr, - "Query parameters is not a map value object\n"); - goto error; - } - - path_value = bt_value_map_get(params, "path"); - ret = bt_value_string_get(path_value, &path); - if (ret) { - fprintf(stderr, - "Cannot get `path` string parameter\n"); - goto error; - } - - assert(path); - metadata_fp = ctf_fs_metadata_open_file(path); - if (!metadata_fp) { - fprintf(stderr, - "Cannot open trace at path `%s`\n", path); - goto error; - } - - is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp, - &bo); - - if (is_packetized) { - ret = ctf_metadata_decoder_packetized_file_stream_to_buf( - metadata_fp, &metadata_text, bo); - if (ret) { - fprintf(stderr, - "Cannot decode packetized metadata file\n"); - goto error; - } - } else { - long filesize; - - fseek(metadata_fp, 0, SEEK_END); - filesize = ftell(metadata_fp); - rewind(metadata_fp); - metadata_text = malloc(filesize + 1); - if (!metadata_text) { - fprintf(stderr, - "Cannot allocate buffer for metadata text\n"); - goto error; - } - - if (fread(metadata_text, filesize, 1, metadata_fp) != - 1) { - fprintf(stderr, - "Cannot read metadata file\n"); - goto error; - } - - metadata_text[filesize] = '\0'; - } - - g_metadata_text = g_string_new(NULL); - if (!g_metadata_text) { - goto error; - } - - if (strncmp(metadata_text, METADATA_TEXT_SIG, - sizeof(METADATA_TEXT_SIG) - 1) != 0) { - g_string_assign(g_metadata_text, METADATA_TEXT_SIG); - g_string_append(g_metadata_text, " */\n\n"); - } - - g_string_append(g_metadata_text, metadata_text); - - ret = bt_value_map_insert_string(results, "text", - g_metadata_text->str); - if (ret) { - fprintf(stderr, "Cannot insert metadata text into results\n"); - goto error; - } - - ret = bt_value_map_insert_bool(results, "is-packetized", - is_packetized); - if (ret) { - fprintf(stderr, "Cannot insert is packetized into results\n"); - goto error; - } - } else { - fprintf(stderr, "Unknown query object `%s`\n", object); - goto error; - } - - goto end; - -error: - BT_PUT(results); - -end: - bt_put(path_value); - free(metadata_text); - - if (g_metadata_text) { - g_string_free(g_metadata_text, TRUE); - } - - if (metadata_fp) { - fclose(metadata_fp); - } - return results; -} diff --git a/plugins/ctf/fs/fs.h b/plugins/ctf/fs/fs.h deleted file mode 100644 index 836c106c..00000000 --- a/plugins/ctf/fs/fs.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_CTF_FS_H -#define BABELTRACE_PLUGIN_CTF_FS_H - -/* - * BabelTrace - CTF on File System Component - * - * Copyright 2016 Jérémie Galarneau - * Copyright 2016 Philippe Proulx - * - * 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 "data-stream.h" - -#define CTF_FS_COMPONENT_DESCRIPTION \ - "Component used to read a CTF trace located on a file system." - -BT_HIDDEN -extern bool ctf_fs_debug; - -struct ctf_fs_file { - struct ctf_fs_component *ctf_fs; - GString *path; - FILE *fp; - off_t size; -}; - -struct ctf_fs_metadata { - struct bt_ctf_trace *trace; - uint8_t uuid[16]; - bool is_uuid_set; - int bo; - char *text; -}; - -struct ctf_fs_stream { - struct ctf_fs_file *file; - struct bt_ctf_stream *stream; - struct bt_clock_class_priority_map *cc_prio_map; - struct bt_ctf_notif_iter *notif_iter; - /* A stream is assumed to be indexed. */ - struct index index; - void *mmap_addr; - /* Max length of chunk to mmap() when updating the current mapping. */ - size_t mmap_max_len; - /* Length of the current mapping. */ - size_t mmap_len; - /* Length of the current mapping which *exists* in the backing file. */ - size_t mmap_valid_len; - /* Offset in the file where the current mapping starts. */ - off_t mmap_offset; - /* - * Offset, in the current mapping, of the address to return on the next - * request. - */ - off_t request_offset; - bool end_reached; -}; - -struct ctf_fs_component_options { - uint64_t clock_offset; - uint64_t clock_offset_ns; -}; - -struct ctf_fs_port_data { - GString *path; -}; - -struct ctf_fs_component { - struct bt_private_component *priv_comp; - GString *trace_path; - FILE *error_fp; - size_t page_size; - struct ctf_fs_component_options options; - struct ctf_fs_metadata *metadata; - struct bt_clock_class_priority_map *cc_prio_map; - - /* Array of struct ctf_fs_port_data *, owned by this */ - GPtrArray *port_data; -}; - -BT_HIDDEN -enum bt_component_status ctf_fs_init(struct bt_private_component *source, - struct bt_value *params, void *init_method_data); - -BT_HIDDEN -void ctf_fs_finalize(struct bt_private_component *component); - -BT_HIDDEN -enum bt_notification_iterator_status ctf_fs_iterator_init( - struct bt_private_notification_iterator *it, - struct bt_private_port *port); - -void ctf_fs_iterator_finalize(struct bt_private_notification_iterator *it); - -struct bt_notification_iterator_next_return ctf_fs_iterator_next( - struct bt_private_notification_iterator *iterator); - -BT_HIDDEN -struct bt_value *ctf_fs_query(struct bt_component_class *comp_class, - const char *object, struct bt_value *params); - -#endif /* BABELTRACE_PLUGIN_CTF_FS_H */ diff --git a/plugins/ctf/fs/lttng-index.h b/plugins/ctf/fs/lttng-index.h deleted file mode 100644 index 05629f86..00000000 --- a/plugins/ctf/fs/lttng-index.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 - Julien Desfossez - * Mathieu Desnoyers - * David Goulet - * - * 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. - */ - -#ifndef LTTNG_INDEX_H -#define LTTNG_INDEX_H - -#include - -#define CTF_INDEX_MAGIC 0xC1F1DCC1 -#define CTF_INDEX_MAJOR 1 -#define CTF_INDEX_MINOR 1 - -/* - * Header at the beginning of each index file. - * All integer fields are stored in big endian. - */ -struct ctf_packet_index_file_hdr { - uint32_t magic; - uint32_t index_major; - uint32_t index_minor; - /* size of struct ctf_packet_index, in bytes. */ - uint32_t packet_index_len; -} __attribute__((__packed__)); - -/* - * Packet index generated for each trace packet store in a trace file. - * All integer fields are stored in big endian. - */ -struct ctf_packet_index { - uint64_t offset; /* offset of the packet in the file, in bytes */ - uint64_t packet_size; /* packet size, in bits */ - uint64_t content_size; /* content size, in bits */ - uint64_t timestamp_begin; - uint64_t timestamp_end; - uint64_t events_discarded; - uint64_t stream_id; - /* CTF_INDEX 1.0 limit */ - uint64_t stream_instance_id; /* ID of the channel instance */ - uint64_t packet_seq_num; /* packet sequence number */ -} __attribute__((__packed__)); - -#endif /* LTTNG_INDEX_H */ diff --git a/plugins/ctf/fs/metadata.c b/plugins/ctf/fs/metadata.c deleted file mode 100644 index cd211961..00000000 --- a/plugins/ctf/fs/metadata.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2016 - Philippe Proulx - * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation - * - * Some functions are based on older functions written by Mathieu Desnoyers. - * - * 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 - -#define PRINT_ERR_STREAM ctf_fs->error_fp -#define PRINT_PREFIX "ctf-fs-metadata" -#include "print.h" - -#include "fs.h" -#include "file.h" -#include "metadata.h" -#include "../common/metadata/decoder.h" - -#define NSEC_PER_SEC 1000000000LL - -BT_HIDDEN -FILE *ctf_fs_metadata_open_file(const char *trace_path) -{ - GString *metadata_path = g_string_new(trace_path); - FILE *fp = NULL; - - if (!metadata_path) { - goto error; - } - - g_string_append(metadata_path, "/" CTF_FS_METADATA_FILENAME); - fp = fopen(metadata_path->str, "rb"); - if (!fp) { - goto error; - } - - goto end; - -error: - if (fp) { - fclose(fp); - fp = NULL; - } - -end: - g_string_free(metadata_path, TRUE); - return fp; -} - -static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs, - const char *trace_path) -{ - struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs); - - if (!file) { - goto error; - } - - g_string_append(file->path, trace_path); - g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME); - - if (ctf_fs_file_open(ctf_fs, file, "rb")) { - goto error; - } - - goto end; - -error: - if (file) { - ctf_fs_file_destroy(file); - file = NULL; - } - -end: - return file; -} - -int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) -{ - int ret = 0; - struct ctf_fs_file *file = NULL; - struct ctf_metadata_decoder *metadata_decoder = NULL; - - file = get_file(ctf_fs, ctf_fs->trace_path->str); - if (!file) { - PERR("Cannot create metadata file object\n"); - goto end; - } - - metadata_decoder = ctf_metadata_decoder_create(ctf_fs->error_fp, - ctf_fs->options.clock_offset * NSEC_PER_SEC + - ctf_fs->options.clock_offset_ns); - if (!metadata_decoder) { - PERR("Cannot create metadata decoder object\n"); - goto end; - } - - ret = ctf_metadata_decoder_decode(metadata_decoder, file->fp); - if (ret) { - PERR("Cannot decode metadata file\n"); - goto end; - } - - ctf_fs->metadata->trace = ctf_metadata_decoder_get_trace( - metadata_decoder); - assert(ctf_fs->metadata->trace); - -end: - ctf_fs_file_destroy(file); - ctf_metadata_decoder_destroy(metadata_decoder); - return ret; -} - -int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata) -{ - /* Nothing to initialize for the moment. */ - return 0; -} - -void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata) -{ - if (metadata->text) { - free(metadata->text); - } - - if (metadata->trace) { - BT_PUT(metadata->trace); - } -} diff --git a/plugins/ctf/fs/metadata.h b/plugins/ctf/fs/metadata.h deleted file mode 100644 index 85a77268..00000000 --- a/plugins/ctf/fs/metadata.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef CTF_FS_METADATA_H -#define CTF_FS_METADATA_H - -/* - * 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 "fs.h" - -#define CTF_FS_METADATA_FILENAME "metadata" - -BT_HIDDEN -int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata); - -BT_HIDDEN -void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata); - -BT_HIDDEN -int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs); - -BT_HIDDEN -FILE *ctf_fs_metadata_open_file(const char *trace_path); - -BT_HIDDEN -bool ctf_metadata_is_packetized(FILE *fp, int *byte_order); - -BT_HIDDEN -int ctf_metadata_packetized_file_to_buf(struct ctf_fs_component *ctf_fs, - FILE *fp, uint8_t **buf, int byte_order); - -#endif /* CTF_FS_METADATA_H */ diff --git a/plugins/ctf/fs/print.h b/plugins/ctf/fs/print.h deleted file mode 100644 index 9daf7ea4..00000000 --- a/plugins/ctf/fs/print.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef CTF_FS_PRINT_H -#define CTF_FS_PRINT_H - -/* - * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file. - * - * Copyright (c) 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 - -#define PERR(fmt, ...) \ - do { \ - if (PRINT_ERR_STREAM) { \ - fprintf(PRINT_ERR_STREAM, \ - "Error: " PRINT_PREFIX ": " fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) - -#define PWARN(fmt, ...) \ - do { \ - if (PRINT_ERR_STREAM) { \ - fprintf(PRINT_ERR_STREAM, \ - "Warning: " PRINT_PREFIX ": " fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) - -#define PDBG(fmt, ...) \ - do { \ - if (ctf_fs_debug) { \ - fprintf(stderr, \ - "Debug: " PRINT_PREFIX ": " fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) - -#endif /* CTF_FS_PRINT_H */ diff --git a/plugins/ctf/lttng-live/lttng-live-internal.h b/plugins/ctf/lttng-live/lttng-live-internal.h index e2f99b47..51556274 100644 --- a/plugins/ctf/lttng-live/lttng-live-internal.h +++ b/plugins/ctf/lttng-live/lttng-live-internal.h @@ -30,8 +30,6 @@ #include #include -#define LTTNG_LIVE_COMPONENT_DESCRIPTION "Component implementing an LTTng-live client." - BT_HIDDEN enum bt_component_status lttng_live_init(struct bt_private_component *source, struct bt_value *params, void *init_method_data); diff --git a/plugins/ctf/plugin.c b/plugins/ctf/plugin.c index 6d483b1d..7b18bd10 100644 --- a/plugins/ctf/plugin.c +++ b/plugins/ctf/plugin.c @@ -27,18 +27,20 @@ */ #include -#include "fs/fs.h" +#include "fs-src/fs.h" +#include "fs-sink/writer.h" #include "lttng-live/lttng-live-internal.h" /* Initialize plug-in description. */ BT_PLUGIN(ctf); -BT_PLUGIN_DESCRIPTION("Built-in Babeltrace plug-in providing CTF read support."); -BT_PLUGIN_AUTHOR("Jérémie Galarneau"); +BT_PLUGIN_DESCRIPTION("CTF source and sink support"); +BT_PLUGIN_AUTHOR("Julien Desfossez, Mathieu Desnoyers, Jérémie Galarneau, Philippe Proulx"); BT_PLUGIN_LICENSE("MIT"); -/* Declare component classes implemented by this plug-in. */ +/* ctf.fs soource */ BT_PLUGIN_SOURCE_COMPONENT_CLASS(fs, ctf_fs_iterator_next); -BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(fs, CTF_FS_COMPONENT_DESCRIPTION); +BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(fs, + "Read CTF traces from the file system."); BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD(fs, ctf_fs_init); BT_PLUGIN_SOURCE_COMPONENT_CLASS_QUERY_METHOD(fs, ctf_fs_query); BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(fs, ctf_fs_finalize); @@ -47,9 +49,18 @@ BT_PLUGIN_SOURCE_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD(fs, BT_PLUGIN_SOURCE_COMPONENT_CLASS_NOTIFICATION_ITERATOR_FINALIZE_METHOD(fs, ctf_fs_iterator_finalize); +/* ctf.lttng-live source */ BT_PLUGIN_SOURCE_COMPONENT_CLASS_WITH_ID(auto, lttng_live, "lttng-live", lttng_live_iterator_next); BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD_WITH_ID(auto, lttng_live, lttng_live_init); BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION_WITH_ID(auto, lttng_live, - LTTNG_LIVE_COMPONENT_DESCRIPTION); + "Connect to an LTTng relay daemon and receive CTF streams."); + +/* ctf.fs sink */ +BT_PLUGIN_SINK_COMPONENT_CLASS(fs, writer_run); +BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(fs, writer_component_init); +BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(fs, + writer_component_port_connected); +BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(fs, writer_component_finalize); +BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(fs, "Write CTF traces to the file system."); diff --git a/plugins/text/dmesg/Makefile.am b/plugins/text/dmesg/Makefile.am new file mode 100644 index 00000000..04df5eb7 --- /dev/null +++ b/plugins/text/dmesg/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins + +noinst_LTLIBRARIES = libbabeltrace-plugin-text-dmesg-cc.la + +libbabeltrace_plugin_text_dmesg_cc_la_SOURCES = dmesg.c dmesg.h +libbabeltrace_plugin_text_dmesg_cc_la_LIBADD = \ + $(top_builddir)/common/libbabeltrace-common.la diff --git a/plugins/text/dmesg/dmesg.c b/plugins/text/dmesg/dmesg.c new file mode 100644 index 00000000..0f8a6e76 --- /dev/null +++ b/plugins/text/dmesg/dmesg.c @@ -0,0 +1,190 @@ +/* + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation + * Copyright 2017 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 + +struct dmesg_component; + +struct dmesg_notif_iter { + struct dmesg_component *dmesg_comp; + FILE *fp; +}; + +struct dmesg_component { + struct { + GString *path; + bool read_from_stdin; + } params; + + struct bt_ctf_packet *packet; + struct bt_ctf_event_class *event_class; + struct bt_ctf_stream *stream; + struct bt_clock_class_priority_map *cc_prio_map; +}; + +static +int check_params(struct dmesg_component *dmesg_comp, struct bt_value *params) +{ + struct bt_value *read_from_stdin; + struct bt_value *path; + const char *path_str; + int ret = 0; + + if (!params || !bt_value_is_map(params)) { + fprintf(stderr, "Expecting a map value as parameters.\n"); + goto error; + } + + read_from_stdin = bt_value_map_get(params, "read-from-stdin"); + if (read_from_stdin) { + if (!bt_value_is_bool(read_from_stdin)) { + fprintf(stderr, "Expecting a boolean value for `read-from-stdin` parameter.\n"); + goto error; + } + + ret = bt_value_bool_get(read_from_stdin, + &dmesg_comp->params.read_from_stdin); + assert(ret == 0); + } + + path = bt_value_map_get(params, "path"); + if (path) { + if (dmesg_comp->params.read_from_stdin) { + fprintf(stderr, "Cannot specify both `read-from-stdin` and `path` parameters.\n"); + goto error; + } + + if (!bt_value_is_string(path)) { + fprintf(stderr, "Expecting a string value for `path` parameter.\n"); + goto error; + } + + ret = bt_value_bool_get(path, &path_str); + assert(ret == 0); + g_string_assign(dmesg_comp->params.path, path_str); + } else { + if (!dmesg_comp->params.read_from_stdin) { + fprintf(stderr, "Expecting `path` parameter or `read-from-stdin` parameter set to true.\n"); + goto error; + } + } + + goto end; + +error: + ret = -1; + +end: + bt_put(read_from_stdin); + bt_put(path); + return ret; +} + +static +int create_stream() + +static +void destroy_dmesg_component(struct dmesg_component *dmesg_comp) +{ + if (!dmesg_comp) { + return; + } + + if (dmesg_comp->params.path) { + g_string_free(dmesg_comp->params.path, TRUE); + } + + bt_put(dmesg_comp->packet); + bt_put(dmesg_comp->event_class); + bt_put(dmesg_comp->stream); + bt_put(dmesg_comp->cc_prio_map); + g_free(dmesg_comp); +} + +BT_HIDDEN +enum bt_component_status dmesg_init(struct bt_private_component *priv_comp, + struct bt_value *params, void *init_method_data) +{ + int ret = 0; + struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1); + enum bt_component_status status = BT_COMPONENT_STATUS_OK; + + if (!dmesg_comp) { + goto error; + } + + dmesg_comp->params.path = g_string_new(NULL); + if (!dmesg_comp->params.path) { + goto error; + } + + ret = check_params(dmesg_comp, params); + if (ret) { + goto error; + } + + + + goto end; + +error: + destroy_dmesg_component(dmesg_comp); + status = BT_COMPONENT_STATUS_ERROR; + +end: + return status; +} + +BT_HIDDEN +void dmesg_finalize(struct bt_private_component *priv_comp) +{ + +} + +BT_HIDDEN +enum bt_notification_iterator_status dmesg_notif_iter_init( + struct bt_private_notification_iterator *priv_notif_iter, + struct bt_private_port *priv_port) +{ + +} + +BT_HIDDEN +void dmesg_iterator_finalize( + struct bt_private_notification_iterator *priv_notif_iter) +{ + +} + +BT_HIDDEN +struct bt_notification_iterator_next_return dmesg_notif_iter_next( + struct bt_private_notification_iterator *priv_notif_iter) +{ + +} diff --git a/plugins/text/dmesg/dmesg.h b/plugins/text/dmesg/dmesg.h new file mode 100644 index 00000000..1108cb1a --- /dev/null +++ b/plugins/text/dmesg/dmesg.h @@ -0,0 +1,51 @@ +#ifndef BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H +#define BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H + +/* + * Copyright 2017 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 + +BT_HIDDEN +enum bt_component_status dmesg_init(struct bt_private_component *priv_comp, + struct bt_value *params, void *init_method_data); + +BT_HIDDEN +void dmesg_finalize(struct bt_private_component *priv_comp); + +BT_HIDDEN +enum bt_notification_iterator_status dmesg_notif_iter_init( + struct bt_private_notification_iterator *priv_notif_iter, + struct bt_private_port *priv_port); + +BT_HIDDEN +void dmesg_iterator_finalize( + struct bt_private_notification_iterator *priv_notif_iter); + +BT_HIDDEN +struct bt_notification_iterator_next_return dmesg_notif_iter_next( + struct bt_private_notification_iterator *priv_notif_iter); + +#endif /* BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H */ diff --git a/plugins/text/plugin.c b/plugins/text/plugin.c index 1449e757..ff982630 100644 --- a/plugins/text/plugin.c +++ b/plugins/text/plugin.c @@ -35,4 +35,4 @@ BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(pretty, pretty_finalize); BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(pretty, pretty_port_connected); BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(pretty, - "Pretty-printing text output (`text` format of Babeltrace 1)"); + "Pretty-printing text output (`text` format of Babeltrace 1)."); diff --git a/plugins/utils/plugin.c b/plugins/utils/plugin.c index 3f596299..c155d771 100644 --- a/plugins/utils/plugin.c +++ b/plugins/utils/plugin.c @@ -38,12 +38,12 @@ BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(dummy, dummy_finalize); BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(dummy, dummy_port_connected); BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(dummy, - "Dummy sink component class: does absolutely nothing!"); + "Consume notifications and discard them."); /* trimmer filter */ BT_PLUGIN_FILTER_COMPONENT_CLASS(trimmer, trimmer_iterator_next); BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(trimmer, - "Ensure that trace notifications outside of a given range are filtered-out."); + "Keep notifications that occur within a specific time range."); BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(trimmer, trimmer_component_init); BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(trimmer, finalize_trimmer); BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD(trimmer, @@ -56,7 +56,7 @@ BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_SEEK_TIME_METHOD(trimmer, /* muxer filter */ BT_PLUGIN_FILTER_COMPONENT_CLASS(muxer, muxer_notif_iter_next); BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(muxer, - "Notification multiplexer"); + "Sort notifications from multiple input ports to a single output port by time."); BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(muxer, muxer_init); BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(muxer, muxer_finalize); BT_PLUGIN_FILTER_COMPONENT_CLASS_PORT_DISCONNECTED_METHOD(muxer, diff --git a/plugins/writer/Makefile.am b/plugins/writer/Makefile.am deleted file mode 100644 index 5b219e33..00000000 --- a/plugins/writer/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins \ - -I$(top_srcdir)/plugins/libctfcopytrace - -SUBDIRS = . - -plugindir = "$(PLUGINSDIR)" -plugin_LTLIBRARIES = libbabeltrace-plugin-ctf-writer.la - -# ctf-writer plugin -libbabeltrace_plugin_ctf_writer_la_SOURCES = \ - writer.c \ - write.c \ - writer.h - -libbabeltrace_plugin_ctf_writer_la_LDFLAGS = \ - -version-info $(BABELTRACE_LIBRARY_VERSION) - -libbabeltrace_plugin_ctf_writer_la_LIBADD = \ - $(top_builddir)/lib/libbabeltrace.la \ - $(top_builddir)/plugins/libctfcopytrace/libctfcopytrace.la - -noinst_HEADERS = writer.h diff --git a/plugins/writer/write.c b/plugins/writer/write.c deleted file mode 100644 index 91b92899..00000000 --- a/plugins/writer/write.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * 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 - -#include "writer.h" - -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 = NULL; - struct bt_ctf_trace *trace = NULL, *writer_trace = NULL; - enum bt_component_status ret; - - trace = bt_ctf_stream_class_get_trace(stream_class); - if (!trace) { - fprintf(writer_component->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - writer_trace = bt_ctf_writer_get_trace(ctf_writer); - if (!writer_trace) { - fprintf(writer_component->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = ctf_copy_clock_classes(writer_component->err, writer_trace, - writer_stream_class, trace); - if (ret != BT_COMPONENT_STATUS_OK) { - fprintf(writer_component->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - writer_stream_class = ctf_copy_stream_class(writer_component->err, - stream_class, writer_trace, true); - if (!writer_stream_class) { - fprintf(writer_component->err, "[error] Failed to copy stream class\n"); - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - g_hash_table_insert(writer_component->stream_class_map, - (gpointer) stream_class, writer_stream_class); - - goto end; - -error: - BT_PUT(writer_stream_class); -end: - bt_put(writer_trace); - bt_put(trace); - 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 = NULL; - struct bt_ctf_stream_class *writer_stream_class = NULL; - - writer_stream_class = g_hash_table_lookup( - writer_component->stream_class_map, - (gpointer) stream_class); - if (!writer_stream_class) { - writer_stream_class = insert_new_stream_class( - writer_component, ctf_writer, stream_class); - if (!writer_stream_class) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - } - bt_get(writer_stream_class); - - 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 error; - } - - g_hash_table_insert(writer_component->stream_map, (gpointer) stream, - writer_stream); - - goto end; - -error: - BT_PUT(writer_stream); -end: - bt_put(writer_stream_class); - 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_id(writer_stream_class, - bt_ctf_event_class_get_id(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 = NULL; - struct bt_ctf_trace *writer_trace = NULL; - char trace_name[PATH_MAX]; - enum bt_component_status ret; - - /* FIXME: replace with trace name when it will work. */ - snprintf(trace_name, PATH_MAX, "%s/%s_%03d", - writer_component->base_path->str, - writer_component->trace_name_base->str, - 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 error; - } - - writer_trace = bt_ctf_writer_get_trace(ctf_writer); - if (!writer_trace) { - fprintf(writer_component->err, - "[error] %s in %s:%d\n", __func__, __FILE__, - __LINE__); - goto error; - } - - ret = ctf_copy_trace(writer_component->err, trace, 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; - } - BT_PUT(writer_trace); - - g_hash_table_insert(writer_component->trace_map, (gpointer) trace, - ctf_writer); - - goto end; - -error: - bt_put(writer_trace); - BT_PUT(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 = NULL; - struct bt_ctf_writer *ctf_writer = NULL; - - 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 error; - } - - ctf_writer = g_hash_table_lookup(writer_component->trace_map, - (gpointer) trace); - if (!ctf_writer) { - ctf_writer = insert_new_writer(writer_component, trace); - } - bt_get(ctf_writer); - BT_PUT(trace); - goto end; - -error: - BT_PUT(ctf_writer); -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 = NULL; - struct bt_ctf_writer *ctf_writer = NULL; - struct bt_ctf_stream *writer_stream = NULL; - - stream_class = bt_ctf_stream_get_class(stream); - if (!stream_class) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - ctf_writer = get_writer(writer_component, stream_class); - if (!ctf_writer) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - writer_stream = lookup_stream(writer_component, stream); - if (!writer_stream) { - writer_stream = insert_new_stream(writer_component, ctf_writer, - stream_class, stream); - } - bt_get(writer_stream); - - goto end; - -error: - BT_PUT(writer_stream); -end: - bt_put(ctf_writer); - bt_put(stream_class); - 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 = NULL, *writer_stream = NULL; - struct bt_ctf_field *writer_packet_context = NULL; - enum bt_component_status ret = BT_COMPONENT_STATUS_OK; - int int_ret; - - stream = bt_ctf_packet_get_stream(packet); - if (!stream) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - writer_stream = get_writer_stream(writer_component, packet, stream); - if (!writer_stream) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - BT_PUT(stream); - - writer_packet_context = ctf_copy_packet_context(writer_component->err, - packet, writer_stream); - if (!writer_packet_context) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - int_ret = bt_ctf_stream_set_packet_context(writer_stream, - writer_packet_context); - if (int_ret < 0) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - BT_PUT(writer_stream); - BT_PUT(writer_packet_context); - - goto end; - -error: - ret = BT_COMPONENT_STATUS_ERROR; -end: - bt_put(writer_stream); - bt_put(writer_packet_context); - bt_put(stream); - 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 = NULL, *writer_stream = NULL; - enum bt_component_status ret; - - stream = bt_ctf_packet_get_stream(packet); - if (!stream) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - - writer_stream = lookup_stream(writer_component, stream); - if (!writer_stream) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - BT_PUT(stream); - - bt_get(writer_stream); - - ret = bt_ctf_stream_flush(writer_stream); - if (ret < 0) { - fprintf(writer_component->err, - "[error] Failed to flush packet\n"); - goto error; - } - BT_PUT(writer_stream); - - ret = BT_COMPONENT_STATUS_OK; - goto end; - -error: - ret = BT_COMPONENT_STATUS_ERROR; -end: - bt_put(writer_stream); - bt_put(stream); - return ret; -} - -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 = NULL, *writer_event_class = NULL; - struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; - struct bt_ctf_stream_class *stream_class = NULL, *writer_stream_class = NULL; - struct bt_ctf_event *writer_event = NULL; - const char *event_name; - int int_ret; - - event_class = bt_ctf_event_get_class(event); - if (!event_class) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - event_name = bt_ctf_event_class_get_name(event_class); - if (!event_name) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - stream = bt_ctf_event_get_stream(event); - if (!stream) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_stream = lookup_stream(writer_component, stream); - if (!writer_stream || !bt_get(writer_stream)) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - stream_class = bt_ctf_event_class_get_stream_class(event_class); - if (!stream_class) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_stream_class = g_hash_table_lookup( - writer_component->stream_class_map, - (gpointer) stream_class); - if (!writer_stream_class || !bt_get(writer_stream_class)) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, - __FILE__, __LINE__); - goto error; - } - - writer_event_class = get_event_class(writer_component, - writer_stream_class, event_class); - if (!writer_event_class) { - writer_event_class = ctf_copy_event_class(writer_component->err, - event_class); - if (!writer_event_class) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - int_ret = bt_ctf_stream_class_add_event_class( - writer_stream_class, writer_event_class); - if (int_ret) { - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto error; - } - } - - writer_event = ctf_copy_event(writer_component->err, event, - writer_event_class, true); - if (!writer_event) { - 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 error; - } - - int_ret = bt_ctf_stream_append_event(writer_stream, writer_event); - if (int_ret < 0) { - 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 error; - } - - ret = BT_COMPONENT_STATUS_OK; - goto end; - -error: - ret = BT_COMPONENT_STATUS_ERROR; -end: - bt_put(writer_event); - bt_put(writer_event_class); - bt_put(writer_stream_class); - bt_put(stream_class); - bt_put(writer_stream); - bt_put(stream); - bt_put(event_class); - return ret; -} diff --git a/plugins/writer/writer.c b/plugins/writer/writer.c deleted file mode 100644 index 3bca09b6..00000000 --- a/plugins/writer/writer.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include "writer.h" -#include - -static -void destroy_writer_component_data(struct writer_component *writer_component) -{ - bt_put(writer_component->input_iterator); - 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); - g_string_free(writer_component->base_path, true); - g_string_free(writer_component->trace_name_base, true); -} - -static -void finalize_writer_component(struct bt_private_component *component) -{ - struct writer_component *writer_component = (struct writer_component *) - bt_private_component_get_user_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); -} - -static -void unref_stream(struct bt_ctf_stream_class *writer_stream) -{ - bt_put(writer_stream); -} - -static -void unref_trace(struct bt_ctf_writer *writer) -{ - bt_put(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; - writer_component->trace_name_base = g_string_new("trace"); - writer_component->processed_first_event = false; - if (!writer_component->trace_name_base) { - g_free(writer_component); - writer_component = NULL; - goto end; - } - - /* - * 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_BEGIN: - { - struct bt_ctf_packet *packet = - bt_notification_packet_begin_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_end_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 -void writer_component_port_connected( - struct bt_private_component *component, - struct bt_private_port *self_port, - struct bt_port *other_port) -{ - struct bt_private_connection *connection; - struct writer_component *writer; - - writer = bt_private_component_get_user_data(component); - assert(writer); - assert(!writer->input_iterator); - connection = bt_private_port_get_private_connection(self_port); - assert(connection); - writer->input_iterator = - bt_private_connection_create_notification_iterator(connection, - NULL); - - if (!writer->input_iterator) { - writer->error = true; - } - - bt_put(connection); -} - -static -enum bt_component_status run(struct bt_private_component *component) -{ - enum bt_component_status ret; - struct bt_notification *notification = NULL; - struct bt_notification_iterator *it; - struct writer_component *writer_component = - bt_private_component_get_user_data(component); - - it = writer_component->input_iterator; - assert(it); - - if (unlikely(writer_component->error)) { - ret = BT_COMPONENT_STATUS_ERROR; - goto end; - } - - if (likely(writer_component->processed_first_event)) { - enum bt_notification_iterator_status it_ret; - - it_ret = bt_notification_iterator_next(it); - switch (it_ret) { - case BT_NOTIFICATION_ITERATOR_STATUS_ERROR: - ret = BT_COMPONENT_STATUS_ERROR; - goto end; - case BT_NOTIFICATION_ITERATOR_STATUS_END: - ret = BT_COMPONENT_STATUS_END; - BT_PUT(writer_component->input_iterator); - goto end; - default: - break; - } - } - - notification = bt_notification_iterator_get_notification(it); - if (!notification) { - ret = BT_COMPONENT_STATUS_ERROR; - goto end; - } - - ret = handle_notification(writer_component, notification); - writer_component->processed_first_event = true; -end: - bt_put(notification); - return ret; -} - -static -enum bt_component_status writer_component_init( - struct bt_private_component *component, struct bt_value *params, - UNUSED_VAR void *init_method_data) -{ - 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; - void *priv_port; - - if (!writer_component) { - ret = BT_COMPONENT_STATUS_NOMEM; - goto end; - } - - priv_port = bt_private_component_sink_add_input_private_port(component, - "in", NULL); - if (!priv_port) { - ret = BT_COMPONENT_STATUS_NOMEM; - goto end; - } - - bt_put(priv_port); - - 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; - } - bt_put(value); - - writer_component->base_path = g_string_new(path); - if (!writer_component) { - ret = BT_COMPONENT_STATUS_ERROR; - goto error; - } - - ret = bt_private_component_set_user_data(component, writer_component); - if (ret != BT_COMPONENT_STATUS_OK) { - goto error; - } - -end: - return ret; -error: - destroy_writer_component_data(writer_component); - g_free(writer_component); - return ret; -} - -/* Initialize plug-in entry points. */ -BT_PLUGIN(writer); -BT_PLUGIN_DESCRIPTION("Babeltrace CTF-Writer output plug-in."); -BT_PLUGIN_AUTHOR("Jérémie Galarneau"); -BT_PLUGIN_LICENSE("MIT"); -BT_PLUGIN_SINK_COMPONENT_CLASS(writer, run); -BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(writer, writer_component_init); -BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(writer, - writer_component_port_connected); -BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(writer, finalize_writer_component); -BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(writer, "Formats CTF-IR to CTF."); diff --git a/plugins/writer/writer.h b/plugins/writer/writer.h deleted file mode 100644 index 6f6b8a49..00000000 --- a/plugins/writer/writer.h +++ /dev/null @@ -1,62 +0,0 @@ -#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 { - GString *base_path; - GString *trace_name_base; - /* 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; - struct bt_notification_iterator *input_iterator; - bool processed_first_event; - bool error; -}; - -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 */