Iterators now expose an event providing function so that a user does not need to know the input trace format to get "bt_ctf_event"s.
A context can now create a specialized iterator depending on its input trace format. Signed-off-by: Jérémie Galarneau <[email protected]> --- converter/babeltrace.c | 10 +++--- formats/ctf/ctf.c | 3 ++ formats/ctf/iterator.c | 34 +++++++++++++------- include/babeltrace/context-internal.h | 1 + include/babeltrace/context.h | 31 ++++++++++++++++++ include/babeltrace/ctf/iterator.h | 6 ++-- include/babeltrace/format.h | 14 +++++++++ include/babeltrace/iterator-internal.h | 1 + include/babeltrace/iterator.h | 11 +++++++ lib/context.c | 57 ++++++++++++++++++++++++++++++++++ lib/iterator.c | 14 +++++++++ tests/lib/test-seeks.c | 42 ++++++++++++------------- 12 files changed, 183 insertions(+), 41 deletions(-) diff --git a/converter/babeltrace.c b/converter/babeltrace.c index 8f09845..c86df93 100644 --- a/converter/babeltrace.c +++ b/converter/babeltrace.c @@ -617,19 +617,19 @@ static int convert_trace(struct bt_trace_descriptor *td_write, struct bt_context *ctx) { - struct bt_ctf_iter *iter; + struct bt_iter *iter; struct bt_iter_pos begin_pos; struct bt_ctf_event *ctf_event; int ret; const GPtrArray *out_streams = bt_trace_descriptor_get_stream_pos(td_write); begin_pos.type = BT_SEEK_BEGIN; - iter = bt_ctf_iter_create(ctx, &begin_pos, NULL); + iter = bt_context_create_iterator(ctx, &begin_pos, NULL); if (!iter) { ret = -1; goto error_iter; } - while ((ctf_event = bt_ctf_iter_read_event(iter))) { + while ((ctf_event = bt_iter_get_event(iter))) { int sout_nr; for (sout_nr = 0; sout_nr < out_streams->len; ++sout_nr) { struct bt_stream_pos *sout = @@ -643,7 +643,7 @@ int convert_trace(struct bt_trace_descriptor *td_write, goto end; } } - ret = bt_iter_next(bt_ctf_get_iter(iter)); + ret = bt_iter_next(iter); if (ret < 0) { goto end; } @@ -651,7 +651,7 @@ int convert_trace(struct bt_trace_descriptor *td_write, ret = 0; end: - bt_ctf_iter_destroy(iter); + bt_context_destroy_iterator(ctx, iter); error_iter: return ret; } diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index aee80b1..c029791 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -29,6 +29,7 @@ #include <babeltrace/format.h> #include <babeltrace/ctf/types.h> #include <babeltrace/ctf/metadata.h> +#include <babeltrace/ctf/iterator.h> #include <babeltrace/babeltrace-internal.h> #include <babeltrace/ctf/events-internal.h> #include <babeltrace/trace-handle-internal.h> @@ -144,6 +145,8 @@ struct bt_format ctf_format = { .timestamp_begin = ctf_timestamp_begin, .timestamp_end = ctf_timestamp_end, .convert_index_timestamp = ctf_convert_index_timestamp, + .iterator_create = bt_ctf_iter_create, + .iterator_destroy = bt_ctf_iter_destroy }; static diff --git a/formats/ctf/iterator.c b/formats/ctf/iterator.c index d2cd914..a294167 100644 --- a/formats/ctf/iterator.c +++ b/formats/ctf/iterator.c @@ -30,6 +30,7 @@ #include <babeltrace/babeltrace.h> #include <babeltrace/format.h> #include <babeltrace/ctf/events.h> +#include <babeltrace/ctf/iterator.h> #include <babeltrace/ctf-ir/metadata.h> #include <babeltrace/prio_heap.h> #include <babeltrace/iterator-internal.h> @@ -39,7 +40,7 @@ #include "events-private.h" -struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx, +struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx, const struct bt_iter_pos *begin_pos, const struct bt_iter_pos *end_pos) { @@ -60,10 +61,11 @@ struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx, iter->recalculate_dep_graph = 0; iter->main_callbacks.callback = NULL; iter->dep_gc = g_ptr_array_new(); - return iter; + iter->parent.get_event = bt_ctf_iter_read_event; + return &iter->parent; } -void bt_ctf_iter_destroy(struct bt_ctf_iter *iter) +void bt_ctf_iter_destroy(struct bt_iter *iter) { struct bt_stream_callbacks *bt_stream_cb; struct bt_callback_chain *bt_chain; @@ -71,13 +73,16 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter) assert(iter); + struct bt_ctf_iter *ctf_iter = + container_of(iter, struct bt_ctf_iter, parent); + /* free all events callbacks */ - if (iter->main_callbacks.callback) - g_array_free(iter->main_callbacks.callback, TRUE); + if (ctf_iter->main_callbacks.callback) + g_array_free(ctf_iter->main_callbacks.callback, TRUE); /* free per-event callbacks */ - for (i = 0; i < iter->callbacks->len; i++) { - bt_stream_cb = &g_array_index(iter->callbacks, + for (i = 0; i < ctf_iter->callbacks->len; i++) { + bt_stream_cb = &g_array_index(ctf_iter->callbacks, struct bt_stream_callbacks, i); if (!bt_stream_cb || !bt_stream_cb->per_id_callbacks) continue; @@ -90,10 +95,10 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter) } g_array_free(bt_stream_cb->per_id_callbacks, TRUE); } - g_array_free(iter->callbacks, TRUE); - g_ptr_array_free(iter->dep_gc, TRUE); + g_array_free(ctf_iter->callbacks, TRUE); + g_ptr_array_free(ctf_iter->dep_gc, TRUE); - bt_iter_fini(&iter->parent); + bt_iter_fini(iter); g_free(iter); } @@ -158,9 +163,14 @@ stop: return NULL; } -struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter) +struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter) { - return bt_ctf_iter_read_event_flags(iter, NULL); + struct bt_ctf_iter *ctf_iter; + if (!iter) { + return NULL; + } + ctf_iter = container_of(iter, struct bt_ctf_iter, parent); + return bt_ctf_iter_read_event_flags(ctf_iter, NULL); } uint64_t bt_ctf_get_lost_events_count(struct bt_ctf_iter *iter) diff --git a/include/babeltrace/context-internal.h b/include/babeltrace/context-internal.h index 17d6202..7600d8d 100644 --- a/include/babeltrace/context-internal.h +++ b/include/babeltrace/context-internal.h @@ -51,6 +51,7 @@ struct bt_context { int refcount; int last_trace_handle_id; struct bt_iter *current_iterator; + struct bt_format *input_trace_format; }; #endif /* _BABELTRACE_CONTEXT_INTERNAL_H */ diff --git a/include/babeltrace/context.h b/include/babeltrace/context.h index b28df09..6455b65 100644 --- a/include/babeltrace/context.h +++ b/include/babeltrace/context.h @@ -32,6 +32,7 @@ */ #include <unistd.h> +#include <stdio.h> #include <babeltrace/format.h> #ifdef __cplusplus @@ -96,6 +97,36 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path, int bt_context_remove_trace(struct bt_context *ctx, int trace_id); /* + * bt_context_create_iterator: Allocate an iterator on the current trace + * collection's events. + * + * begin_pos and end_pos are optional parameters to specify the position + * at which the trace collection should be seeked upon iterator + * creation, and the position at which iteration will start returning + * "EOF". + * + * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at + * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of + * trace) is the EOF criterion. + * + * Return a pointer to the newly allocated iterator. + * + * Only one iterator can be created against a context. If more than one + * iterator is being created for the same context, the second creation + * will return NULL. The previous iterator must be destroyed before + * creation of the new iterator for this function to succeed. + */ +struct bt_iter *bt_context_create_iterator(struct bt_context *ctx, + const struct bt_iter_pos *position_begin, + const struct bt_iter_pos *position_end); + +/* + * bt_context_destroy_iterator: Free a trace collection iterator. + */ +void bt_context_destroy_iterator(struct bt_context *ctx, + struct bt_iter *iterator); + +/* * bt_context_get and bt_context_put : increments and decrement the * refcount of the context * diff --git a/include/babeltrace/ctf/iterator.h b/include/babeltrace/ctf/iterator.h index ec6aac7..159e4a4 100644 --- a/include/babeltrace/ctf/iterator.h +++ b/include/babeltrace/ctf/iterator.h @@ -59,7 +59,7 @@ struct bt_ctf_event; * will return NULL. The previous iterator must be destroyed before * creation of the new iterator for this function to succeed. */ -struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx, +struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx, const struct bt_iter_pos *begin_pos, const struct bt_iter_pos *end_pos); @@ -71,7 +71,7 @@ struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter); /* * bt_ctf_iter_destroy - Free a CTF trace collection iterator. */ -void bt_ctf_iter_destroy(struct bt_ctf_iter *iter); +void bt_ctf_iter_destroy(struct bt_iter *iter); /* * bt_ctf_iter_read_event: Read the iterator's current event data. @@ -80,7 +80,7 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter); * * Return current event on success, NULL on end of trace. */ -struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter); +struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter); /* * bt_ctf_iter_read_event_flags: Read the iterator's current event data. diff --git a/include/babeltrace/format.h b/include/babeltrace/format.h index 9f3d1c8..c170d83 100644 --- a/include/babeltrace/format.h +++ b/include/babeltrace/format.h @@ -45,6 +45,9 @@ typedef int bt_intern_str; struct bt_stream_pos; struct bt_context; struct bt_trace_handle; +struct bt_trace_descriptor; +struct bt_iter; +struct bt_iter_pos; struct bt_mmap_stream { int fd; @@ -77,6 +80,17 @@ struct bt_format { uint64_t (*timestamp_end)(struct bt_trace_descriptor *descriptor, struct bt_trace_handle *handle, enum bt_clock_type type); int (*convert_index_timestamp)(struct bt_trace_descriptor *descriptor); + + /* + * Only one iterator can be created against a context. If more than one + * iterator is being created for the same context, the second creation + * will return NULL. The previous iterator must be destroyed before + * creation of the new iterator for this function to succeed. + */ + struct bt_iter *(*iterator_create)(struct bt_context *ctx, + const struct bt_iter_pos *begin_pos, + const struct bt_iter_pos *end_pos); + void (*iterator_destroy)(struct bt_iter *iterator); }; extern struct bt_format *bt_lookup_format(bt_intern_str qname); diff --git a/include/babeltrace/iterator-internal.h b/include/babeltrace/iterator-internal.h index 2b0b2f2..2008d76 100644 --- a/include/babeltrace/iterator-internal.h +++ b/include/babeltrace/iterator-internal.h @@ -39,6 +39,7 @@ struct bt_iter { struct ptr_heap *stream_heap; struct bt_context *ctx; const struct bt_iter_pos *end_pos; + struct bt_ctf_event *(*get_event)(struct bt_iter *iter); }; /* diff --git a/include/babeltrace/iterator.h b/include/babeltrace/iterator.h index 360a9c7..aa189a8 100644 --- a/include/babeltrace/iterator.h +++ b/include/babeltrace/iterator.h @@ -27,6 +27,7 @@ #include <babeltrace/format.h> #include <babeltrace/context.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -40,6 +41,7 @@ enum { /* Forward declarations */ struct bt_iter; struct bt_saved_pos; +struct bt_ctf_event; /* * bt_iter is an abstract class, each format has to implement its own @@ -123,6 +125,15 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos); struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter, uint64_t timestamp); +/* + * bt_iter_get_event: Get the iterator's current event data + * + * @iter trace collection iterator (input). Should not be NULL. + * + * Return current event on success, NULL on end of trace. + */ +struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter); + #ifdef __cplusplus } #endif diff --git a/lib/context.c b/lib/context.c index dc77366..61215a3 100644 --- a/lib/context.c +++ b/lib/context.c @@ -87,6 +87,12 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path, ret = -1; goto end; } + if (ctx->input_trace_format && ctx->input_trace_format != fmt) { + fprintf(stderr, "[error] [Context] Opening traces of different formats in the same context is not supported.\n"); + ret = -1; + goto end; + } + ctx->input_trace_format = fmt; if (path) { td = fmt->open_trace(path, O_RDONLY, packet_seek, NULL); if (!td) { @@ -211,3 +217,54 @@ void bt_context_put(struct bt_context *ctx) if (ctx->refcount == 0) bt_context_destroy(ctx); } + +struct bt_iter *bt_context_create_iterator(struct bt_context *ctx, + const struct bt_iter_pos *position_begin, + const struct bt_iter_pos *position_end) +{ + struct bt_iter *iter = NULL; + struct bt_format *fmt; + assert(ctx); + + if (!ctx->input_trace_format) { + fprintf(stderr, "[error] No trace opened in context.\n"); + goto end; + } + fmt = ctx->input_trace_format; + if (!fmt->iterator_create) { + fprintf(stderr, "[error] The %s format plug-in did not register an iterator creation function.\n", g_quark_to_string(fmt->name)); + goto end; + } + iter = fmt->iterator_create(ctx, position_begin, position_end); + + if (!ctx->current_iterator) { + fprintf(stderr, "[error] The %s format plug-in did not call bt_iter_init in its iterator creation function.\n", + g_quark_to_string(fmt->name)); + } + +end: + return iter; +} + +void bt_context_destroy_iterator(struct bt_context *ctx, + struct bt_iter *iter) +{ + struct bt_format *fmt; + assert(ctx); + + if (!ctx->input_trace_format) { + fprintf(stderr, "[error] No trace opened in context.\n"); + return; + } + fmt = ctx->input_trace_format; + if (!fmt->iterator_destroy) { + fprintf(stderr, "[error] The %s format plug-in did not register an iterator destruction function.\n", + g_quark_to_string(fmt->name)); + return; + } + fmt->iterator_destroy(iter); + if (ctx->current_iterator) { + fprintf(stderr, "[warn] The %s format plug-in did not call bt_iter_fini in its iterator destruction function.\n", + g_quark_to_string(fmt->name)); + } +} diff --git a/lib/iterator.c b/lib/iterator.c index 4190e65..b838000 100644 --- a/lib/iterator.c +++ b/lib/iterator.c @@ -805,3 +805,17 @@ int bt_iter_next(struct bt_iter *iter) end: return ret; } + +struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter) +{ + struct bt_ctf_event *event; + if (!iter->get_event) { + event = NULL; + fprintf(stderr, "[error] No get_event callback registered by the output plug-in.\n"); + goto end; + } + event = iter->get_event(iter); + +end: + return event; +} diff --git a/tests/lib/test-seeks.c b/tests/lib/test-seeks.c index 47bb42e..69e4d4b 100644 --- a/tests/lib/test-seeks.c +++ b/tests/lib/test-seeks.c @@ -37,7 +37,7 @@ void run_seek_begin(char *path, uint64_t expected_begin) { struct bt_context *ctx; - struct bt_ctf_iter *iter; + struct bt_iter *iter; struct bt_ctf_event *event; struct bt_iter_pos newpos; int ret; @@ -51,12 +51,12 @@ void run_seek_begin(char *path, uint64_t expected_begin) } /* Create iterator with null begin and end */ - iter = bt_ctf_iter_create(ctx, NULL, NULL); + iter = bt_context_create_iterator(ctx, NULL, NULL); if (!iter) { plan_skip_all("Cannot create valid iterator"); } - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid"); @@ -67,7 +67,7 @@ void run_seek_begin(char *path, uint64_t expected_begin) /* Validate that we get the same value after a seek begin */ newpos.type = BT_SEEK_BEGIN; - ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos); + ret = bt_iter_set_pos(iter, &newpos); ok(ret == 0, "Seek begin retval %d", ret); @@ -86,7 +86,7 @@ void run_seek_begin(char *path, uint64_t expected_begin) void run_seek_last(char *path, uint64_t expected_last) { struct bt_context *ctx; - struct bt_ctf_iter *iter; + struct bt_iter *iter; struct bt_ctf_event *event; struct bt_iter_pos newpos; int ret; @@ -99,18 +99,18 @@ void run_seek_last(char *path, uint64_t expected_last) } /* Create iterator with null last and end */ - iter = bt_ctf_iter_create(ctx, NULL, NULL); + iter = bt_context_create_iterator(ctx, NULL, NULL); if (!iter) { plan_skip_all("Cannot create valid iterator"); } - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid at beginning"); /* Seek to last */ newpos.type = BT_SEEK_LAST; - ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos); + ret = bt_iter_set_pos(iter, &newpos); ok(ret == 0, "Seek last retval %d", ret); @@ -123,11 +123,11 @@ void run_seek_last(char *path, uint64_t expected_last) ok1(timestamp_last == expected_last); /* Try to read next event */ - ret = bt_iter_next(bt_ctf_get_iter(iter)); + ret = bt_iter_next(iter); ok(ret == 0, "iter next should return an error"); - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event == 0, "Event after last should be invalid"); @@ -139,7 +139,7 @@ void run_seek_cycles(char *path, uint64_t expected_last) { struct bt_context *ctx; - struct bt_ctf_iter *iter; + struct bt_iter *iter; struct bt_ctf_event *event; struct bt_iter_pos newpos; int ret; @@ -152,22 +152,22 @@ void run_seek_cycles(char *path, } /* Create iterator with null last and end */ - iter = bt_ctf_iter_create(ctx, NULL, NULL); + iter = bt_context_create_iterator(ctx, NULL, NULL); if (!iter) { plan_skip_all("Cannot create valid iterator"); } - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid at beginning"); /* Seek to last */ newpos.type = BT_SEEK_LAST; - ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos); + ret = bt_iter_set_pos(iter, &newpos); ok(ret == 0, "Seek last retval %d", ret); - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid at last position"); @@ -176,21 +176,21 @@ void run_seek_cycles(char *path, ok1(timestamp == expected_last); /* Try to read next event */ - ret = bt_iter_next(bt_ctf_get_iter(iter)); + ret = bt_iter_next(iter); ok(ret == 0, "iter next should return an error"); - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event == 0, "Event after last should be invalid"); /* Seek to BEGIN */ newpos.type = BT_SEEK_BEGIN; - ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos); + ret = bt_iter_set_pos(iter, &newpos); ok(ret == 0, "Seek begin retval %d", ret); - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid at first position"); @@ -200,11 +200,11 @@ void run_seek_cycles(char *path, /* Seek last again */ newpos.type = BT_SEEK_LAST; - ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos); + ret = bt_iter_set_pos(iter, &newpos); ok(ret == 0, "Seek last retval %d", ret); - event = bt_ctf_iter_read_event(iter); + event = bt_iter_get_event(iter); ok(event, "Event valid at last position"); -- 1.8.2.3 _______________________________________________ lttng-dev mailing list [email protected] http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
