lib: make it mandatory to have seek_X if can_seek_X is defined
[babeltrace.git] / src / lib / graph / iterator.c
index 3ae5920851c9af08986c67a5fb678acd3d07882c..511a1f981ba020c18c91285ba4e139d17b806f64 100644 (file)
@@ -43,7 +43,6 @@
 #include <babeltrace2/graph/message-const.h>
 #include <babeltrace2/graph/message-iterator.h>
 #include <babeltrace2/graph/self-component-port-input-message-iterator.h>
-#include <babeltrace2/graph/port-output-message-iterator.h>
 #include <babeltrace2/graph/message-event-const.h>
 #include <babeltrace2/graph/message-message-iterator-inactivity-const.h>
 #include <babeltrace2/graph/message-packet-beginning.h>
@@ -64,7 +63,6 @@
 #include <stdlib.h>
 
 #include "component-class.h"
-#include "component-class-sink-colander.h"
 #include "component.h"
 #include "component-sink.h"
 #include "component-source.h"
@@ -103,21 +101,6 @@ void set_self_comp_port_input_msg_iterator_state(
        iterator->state = state;
 }
 
-static
-void destroy_base_message_iterator(struct bt_object *obj)
-{
-       struct bt_message_iterator *iterator = (void *) obj;
-
-       BT_ASSERT(iterator);
-
-       if (iterator->msgs) {
-               g_ptr_array_free(iterator->msgs, TRUE);
-               iterator->msgs = NULL;
-       }
-
-       g_free(iterator);
-}
-
 static
 void bt_self_component_port_input_message_iterator_destroy(struct bt_object *obj)
 {
@@ -162,13 +145,29 @@ void bt_self_component_port_input_message_iterator_destroy(struct bt_object *obj
                iterator->auto_seek.msgs = NULL;
        }
 
-       destroy_base_message_iterator(obj);
+       if (iterator->upstream_msg_iters) {
+               /*
+                * At this point the message iterator is finalized, so
+                * it's detached from any upstream message iterator.
+                */
+               BT_ASSERT(iterator->upstream_msg_iters->len == 0);
+               g_ptr_array_free(iterator->upstream_msg_iters, TRUE);
+               iterator->upstream_msg_iters = NULL;
+       }
+
+       if (iterator->msgs) {
+               g_ptr_array_free(iterator->msgs, TRUE);
+               iterator->msgs = NULL;
+       }
+
+       g_free(iterator);
 }
 
 BT_HIDDEN
 void bt_self_component_port_input_message_iterator_try_finalize(
                struct bt_self_component_port_input_message_iterator *iterator)
 {
+       uint64_t i;
        typedef void (*method_t)(void *);
 
        struct bt_component_class *comp_class = NULL;
@@ -231,6 +230,27 @@ void bt_self_component_port_input_message_iterator_try_finalize(
                method(iterator);
        }
 
+       /* Detach upstream message iterators */
+       for (i = 0; i < iterator->upstream_msg_iters->len; i++) {
+               struct bt_self_component_port_input_message_iterator *upstream_msg_iter =
+                       iterator->upstream_msg_iters->pdata[i];
+
+               upstream_msg_iter->downstream_msg_iter = NULL;
+       }
+
+       g_ptr_array_set_size(iterator->upstream_msg_iters, 0);
+
+       /* Detach downstream message iterator */
+       if (iterator->downstream_msg_iter) {
+               gboolean existed;
+
+               BT_ASSERT(iterator->downstream_msg_iter->upstream_msg_iters);
+               existed = g_ptr_array_remove_fast(
+                       iterator->downstream_msg_iter->upstream_msg_iters,
+                       iterator);
+               BT_ASSERT(existed);
+       }
+
        iterator->upstream_component = NULL;
        iterator->upstream_port = NULL;
        set_self_comp_port_input_msg_iterator_state(iterator,
@@ -253,84 +273,105 @@ void bt_self_component_port_input_message_iterator_set_connection(
 }
 
 static
-int init_message_iterator(struct bt_message_iterator *iterator,
-               enum bt_message_iterator_type type,
-               bt_object_release_func destroy)
+enum bt_message_iterator_can_seek_beginning_status can_seek_ns_from_origin_true(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin, bt_bool *can_seek)
 {
-       int ret = 0;
-
-       bt_object_init_shared(&iterator->base, destroy);
-       iterator->type = type;
-       iterator->msgs = g_ptr_array_new();
-       if (!iterator->msgs) {
-               BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
+       *can_seek = BT_TRUE;
 
-end:
-       return ret;
+       return BT_FUNC_STATUS_OK;
 }
 
 static
-bt_bool can_seek_ns_from_origin_true(
+enum bt_message_iterator_can_seek_beginning_status can_seek_beginning_true(
                struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
+               bt_bool *can_seek)
 {
-       return BT_TRUE;
-}
+       *can_seek = BT_TRUE;
 
-static
-bt_bool can_seek_beginning_true(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       return BT_TRUE;
+       return BT_FUNC_STATUS_OK;
 }
 
 static
-struct bt_self_component_port_input_message_iterator *
-bt_self_component_port_input_message_iterator_create_initial(
-               struct bt_component *upstream_comp,
-               struct bt_port *upstream_port)
+int create_self_component_input_port_message_iterator(
+               struct bt_self_message_iterator *self_downstream_msg_iter,
+               struct bt_self_component_port_input *self_port,
+               struct bt_self_component_port_input_message_iterator **message_iterator)
 {
-       int ret;
-       struct bt_self_component_port_input_message_iterator *iterator = NULL;
+       typedef enum bt_component_class_message_iterator_initialize_method_status (*init_method_t)(
+                       void *, void *, void *, void *);
 
-       BT_ASSERT(upstream_comp);
+       init_method_t init_method = NULL;
+       struct bt_self_component_port_input_message_iterator *iterator =
+               NULL;
+       struct bt_self_component_port_input_message_iterator *downstream_msg_iter =
+               (void *) self_downstream_msg_iter;
+       struct bt_port *port = (void *) self_port;
+       struct bt_port *upstream_port;
+       struct bt_component *comp;
+       struct bt_component *upstream_comp;
+       struct bt_component_class *upstream_comp_cls;
+       int status;
+
+       BT_ASSERT_PRE_NON_NULL(message_iterator, "Created message iterator");
+       BT_ASSERT_PRE_NON_NULL(port, "Input port");
+       comp = bt_port_borrow_component_inline(port);
+       BT_ASSERT_PRE(bt_port_is_connected(port),
+               "Input port is not connected: %![port-]+p", port);
+       BT_ASSERT_PRE(comp, "Input port is not part of a component: %![port-]+p",
+               port);
+       BT_ASSERT(port->connection);
+       upstream_port = port->connection->upstream_port;
        BT_ASSERT(upstream_port);
-       BT_ASSERT(bt_port_is_connected(upstream_port));
-       BT_LIB_LOGI("Creating initial message iterator on self component input port: "
-               "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
-       BT_ASSERT(bt_component_get_class_type(upstream_comp) ==
+       upstream_comp = bt_port_borrow_component_inline(upstream_port);
+       BT_ASSERT(upstream_comp);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(upstream_comp)->config_state ==
+                       BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED ||
+               bt_component_borrow_graph(upstream_comp)->config_state ==
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURED,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(upstream_comp));
+       upstream_comp_cls = upstream_comp->class;
+       BT_ASSERT(upstream_comp->class->type ==
                BT_COMPONENT_CLASS_TYPE_SOURCE ||
-               bt_component_get_class_type(upstream_comp) ==
+               upstream_comp->class->type ==
                BT_COMPONENT_CLASS_TYPE_FILTER);
+       BT_LIB_LOGI("Creating message iterator on self component input port: "
+               "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
        iterator = g_new0(
                struct bt_self_component_port_input_message_iterator, 1);
        if (!iterator) {
                BT_LIB_LOGE_APPEND_CAUSE(
                        "Failed to allocate one self component input port "
                        "message iterator.");
+               status = BT_FUNC_STATUS_MEMORY_ERROR;
                goto error;
        }
 
-       ret = init_message_iterator((void *) iterator,
-               BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
+       bt_object_init_shared(&iterator->base,
                bt_self_component_port_input_message_iterator_destroy);
-       if (ret) {
-               /* init_message_iterator() logs errors */
+       iterator->msgs = g_ptr_array_new();
+       if (!iterator->msgs) {
+               BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
+               status = BT_FUNC_STATUS_MEMORY_ERROR;
                goto error;
        }
 
+       g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
        iterator->last_ns_from_origin = INT64_MIN;
-
        iterator->auto_seek.msgs = g_queue_new();
        if (!iterator->auto_seek.msgs) {
                BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GQueue.");
-               ret = -1;
-               goto end;
+               status = BT_FUNC_STATUS_MEMORY_ERROR;
+               goto error;
+       }
+
+       iterator->upstream_msg_iters = g_ptr_array_new();
+       if (!iterator->upstream_msg_iters) {
+               BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
+               status = BT_FUNC_STATUS_MEMORY_ERROR;
+               goto error;
        }
 
        iterator->upstream_component = upstream_comp;
@@ -399,70 +440,10 @@ bt_self_component_port_input_message_iterator_create_initial(
        if (iterator->methods.seek_beginning &&
                        !iterator->methods.can_seek_beginning) {
                iterator->methods.can_seek_beginning =
-                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
+                       (bt_self_component_port_input_message_iterator_can_seek_beginning_method)
                                can_seek_beginning_true;
        }
 
-       BT_LIB_LOGI("Created initial message iterator on self component input port: "
-               "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
-               upstream_port, upstream_comp, iterator);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(iterator);
-
-end:
-       return iterator;
-}
-
-struct bt_self_component_port_input_message_iterator *
-bt_self_component_port_input_message_iterator_create(
-               struct bt_self_component_port_input *self_port)
-{
-       typedef enum bt_component_class_message_iterator_init_method_status (*init_method_t)(
-                       void *, void *, void *);
-
-       init_method_t init_method = NULL;
-       struct bt_self_component_port_input_message_iterator *iterator =
-               NULL;
-       struct bt_port *port = (void *) self_port;
-       struct bt_port *upstream_port;
-       struct bt_component *comp;
-       struct bt_component *upstream_comp;
-       struct bt_component_class *upstream_comp_cls;
-
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       comp = bt_port_borrow_component_inline(port);
-       BT_ASSERT_PRE(bt_port_is_connected(port),
-               "Port is not connected: %![port-]+p", port);
-       BT_ASSERT_PRE(comp, "Port is not part of a component: %![port-]+p",
-               port);
-       BT_ASSERT_PRE(!bt_component_graph_is_canceled(comp),
-               "Port's component's graph is canceled: "
-               "%![port-]+p, %![comp-]+c", port, comp);
-       BT_ASSERT(port->connection);
-       upstream_port = port->connection->upstream_port;
-       BT_ASSERT(upstream_port);
-       upstream_comp = bt_port_borrow_component_inline(upstream_port);
-       BT_ASSERT(upstream_comp);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(upstream_comp)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(upstream_comp));
-       upstream_comp_cls = upstream_comp->class;
-       BT_ASSERT(upstream_comp->class->type ==
-               BT_COMPONENT_CLASS_TYPE_SOURCE ||
-               upstream_comp->class->type ==
-               BT_COMPONENT_CLASS_TYPE_FILTER);
-       iterator = bt_self_component_port_input_message_iterator_create_initial(
-               upstream_comp, upstream_port);
-       if (!iterator) {
-               BT_LIB_LOGE_APPEND_CAUSE(
-                       "Cannot create self component input port message iterator.");
-               goto error;
-       }
-
        switch (upstream_comp_cls->type) {
        case BT_COMPONENT_CLASS_TYPE_SOURCE:
        {
@@ -470,7 +451,7 @@ bt_self_component_port_input_message_iterator_create(
                        (void *) upstream_comp_cls;
 
                init_method =
-                       (init_method_t) src_comp_cls->methods.msg_iter_init;
+                       (init_method_t) src_comp_cls->methods.msg_iter_initialize;
                break;
        }
        case BT_COMPONENT_CLASS_TYPE_FILTER:
@@ -479,7 +460,7 @@ bt_self_component_port_input_message_iterator_create(
                        (void *) upstream_comp_cls;
 
                init_method =
-                       (init_method_t) flt_comp_cls->methods.msg_iter_init;
+                       (init_method_t) flt_comp_cls->methods.msg_iter_initialize;
                break;
        }
        default:
@@ -488,10 +469,10 @@ bt_self_component_port_input_message_iterator_create(
        }
 
        if (init_method) {
-               enum bt_component_class_message_iterator_init_method_status iter_status;
+               enum bt_component_class_message_iterator_initialize_method_status iter_status;
 
                BT_LIB_LOGD("Calling user's initialization method: %!+i", iterator);
-               iter_status = init_method(iterator, upstream_comp,
+               iter_status = init_method(iterator, &iterator->config, upstream_comp,
                        upstream_port);
                BT_LOGD("User method returned: status=%s",
                        bt_common_func_status_string(iter_status));
@@ -501,8 +482,23 @@ bt_self_component_port_input_message_iterator_create(
                                "%![iter-]+i, status=%s",
                                iterator,
                                bt_common_func_status_string(iter_status));
+                       status = iter_status;
                        goto error;
                }
+
+               iterator->config.frozen = true;
+       }
+
+       if (downstream_msg_iter) {
+               /* Set this message iterator's downstream message iterator */
+               iterator->downstream_msg_iter = downstream_msg_iter;
+
+               /*
+                * Add this message iterator to the downstream message
+                * iterator's array of upstream message iterators.
+                */
+               g_ptr_array_add(downstream_msg_iter->upstream_msg_iters,
+                       iterator);
        }
 
        set_self_comp_port_input_msg_iterator_state(iterator,
@@ -511,13 +507,38 @@ bt_self_component_port_input_message_iterator_create(
        BT_LIB_LOGI("Created message iterator on self component input port: "
                "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
                upstream_port, upstream_comp, iterator);
+
+       *message_iterator = iterator;
+       status = BT_FUNC_STATUS_OK;
        goto end;
 
 error:
        BT_OBJECT_PUT_REF_AND_RESET(iterator);
 
 end:
-       return iterator;
+       return status;
+}
+
+bt_self_component_port_input_message_iterator_create_from_message_iterator_status
+bt_self_component_port_input_message_iterator_create_from_message_iterator(
+               struct bt_self_message_iterator *self_msg_iter,
+               struct bt_self_component_port_input *input_port,
+               struct bt_self_component_port_input_message_iterator **message_iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
+       return create_self_component_input_port_message_iterator(self_msg_iter,
+               input_port, message_iterator);
+}
+
+bt_self_component_port_input_message_iterator_create_from_sink_component_status
+bt_self_component_port_input_message_iterator_create_from_sink_component(
+               struct bt_self_component_sink *self_comp,
+               struct bt_self_component_port_input *input_port,
+               struct bt_self_component_port_input_message_iterator **message_iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(self_comp, "Sink component");
+       return create_self_component_input_port_message_iterator(NULL,
+               input_port, message_iterator);
 }
 
 void *bt_self_message_iterator_get_data(
@@ -542,6 +563,16 @@ void bt_self_message_iterator_set_data(
                "%!+i, user-data-addr=%p", iterator, data);
 }
 
+void bt_self_message_iterator_configuration_set_can_seek_forward(
+               bt_self_message_iterator_configuration *config,
+               bt_bool can_seek_forward)
+{
+       BT_ASSERT_PRE_NON_NULL(config, "Message iterator configuration");
+       BT_ASSERT_PRE_DEV_HOT(config, "Message iterator configuration", "");
+
+       config->can_seek_forward = can_seek_forward;
+}
+
 /*
  * Validate that the default clock snapshot in `msg` doesn't make us go back in
  * time.
@@ -864,7 +895,7 @@ bt_self_component_port_input_message_iterator_next(
         */
        *user_count = 0;
        status = (int) call_iterator_next_method(iterator,
-               (void *) iterator->base.msgs->pdata, MSG_BATCH_SIZE,
+               (void *) iterator->msgs->pdata, MSG_BATCH_SIZE,
                user_count);
        BT_LOGD("User method returned: status=%s, msg-count=%" PRIu64,
                bt_common_func_status_string(status), *user_count);
@@ -894,7 +925,7 @@ bt_self_component_port_input_message_iterator_next(
                        "Invalid returned message count: greater than "
                        "batch size: count=%" PRIu64 ", batch-size=%u",
                        *user_count, MSG_BATCH_SIZE);
-               *msgs = (void *) iterator->base.msgs->pdata;
+               *msgs = (void *) iterator->msgs->pdata;
                break;
        case BT_FUNC_STATUS_AGAIN:
                goto end;
@@ -911,47 +942,6 @@ end:
        return status;
 }
 
-enum bt_message_iterator_next_status bt_port_output_message_iterator_next(
-               struct bt_port_output_message_iterator *iterator,
-               bt_message_array_const *msgs_to_user,
-               uint64_t *count_to_user)
-{
-       enum bt_message_iterator_next_status status;
-       int graph_status;
-
-       BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_DEV_NON_NULL(msgs_to_user, "Message array (output)");
-       BT_ASSERT_PRE_DEV_NON_NULL(count_to_user, "Message count (output)");
-       BT_LIB_LOGD("Getting next output port message iterator's messages: "
-               "%!+i", iterator);
-       graph_status = bt_graph_consume_sink_no_check(iterator->graph,
-               iterator->colander);
-       switch (graph_status) {
-       case BT_FUNC_STATUS_CANCELED:
-       case BT_FUNC_STATUS_AGAIN:
-       case BT_FUNC_STATUS_END:
-       case BT_FUNC_STATUS_MEMORY_ERROR:
-               status = (int) graph_status;
-               break;
-       case BT_FUNC_STATUS_OK:
-               status = BT_FUNC_STATUS_OK;
-
-               /*
-                * On success, the colander sink moves the messages
-                * to this iterator's array and sets this iterator's
-                * message count: move them to the user.
-                */
-               *msgs_to_user = (void *) iterator->base.msgs->pdata;
-               *count_to_user = iterator->count;
-               break;
-       default:
-               /* Other errors */
-               status = BT_FUNC_STATUS_ERROR;
-       }
-
-       return status;
-}
-
 struct bt_component *
 bt_self_component_port_input_message_iterator_borrow_component(
                struct bt_self_component_port_input_message_iterator *iterator)
@@ -978,7 +968,7 @@ struct bt_self_component *bt_self_message_iterator_borrow_component(
        return (void *) iterator->upstream_component;
 }
 
-struct bt_self_port_output *bt_self_message_iterator_borrow_port(
+struct bt_self_component_port_output *bt_self_message_iterator_borrow_port(
                struct bt_self_message_iterator *self_iterator)
 {
        struct bt_self_component_port_input_message_iterator *iterator =
@@ -988,179 +978,15 @@ struct bt_self_port_output *bt_self_message_iterator_borrow_port(
        return (void *) iterator->upstream_port;
 }
 
-static
-void bt_port_output_message_iterator_destroy(struct bt_object *obj)
-{
-       struct bt_port_output_message_iterator *iterator = (void *) obj;
-
-       BT_LIB_LOGI("Destroying output port message iterator object: %!+i",
-               iterator);
-       BT_LOGD_STR("Putting graph.");
-       BT_OBJECT_PUT_REF_AND_RESET(iterator->graph);
-       BT_LOGD_STR("Putting colander sink component.");
-       BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
-       destroy_base_message_iterator(obj);
-}
-
-struct bt_port_output_message_iterator *
-bt_port_output_message_iterator_create(struct bt_graph *graph,
-               const struct bt_port_output *output_port)
-{
-       struct bt_port_output_message_iterator *iterator = NULL;
-       struct bt_component_class_sink *colander_comp_cls = NULL;
-       struct bt_component *output_port_comp = NULL;
-       struct bt_component_sink *colander_comp;
-       int graph_status;
-       struct bt_port_input *colander_in_port = NULL;
-       struct bt_component_class_sink_colander_data colander_data;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(output_port, "Output port");
-       output_port_comp = bt_port_borrow_component_inline(
-               (const void *) output_port);
-       BT_ASSERT_PRE(output_port_comp,
-               "Output port has no component: %!+p", output_port);
-       BT_ASSERT_PRE(bt_component_borrow_graph(output_port_comp) ==
-               (void *) graph,
-               "Output port is not part of graph: %![graph-]+g, %![port-]+p",
-               graph, output_port);
-       BT_ASSERT_PRE(!graph->has_sink,
-               "Graph already has a sink component: %![graph-]+g");
-
-       /* Create message iterator */
-       BT_LIB_LOGI("Creating message iterator on output port: "
-               "%![port-]+p, %![comp-]+c", output_port, output_port_comp);
-       iterator = g_new0(struct bt_port_output_message_iterator, 1);
-       if (!iterator) {
-               BT_LIB_LOGE_APPEND_CAUSE(
-                       "Failed to allocate one output port message iterator.");
-               goto error;
-       }
-
-       ret = init_message_iterator((void *) iterator,
-               BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT,
-               bt_port_output_message_iterator_destroy);
-       if (ret) {
-               /* init_message_iterator() logs errors */
-               BT_OBJECT_PUT_REF_AND_RESET(iterator);
-               goto end;
-       }
-
-       /* Create colander component */
-       colander_comp_cls = bt_component_class_sink_colander_get();
-       if (!colander_comp_cls) {
-               /* bt_component_class_sink_colander_get() logs errors */
-               BT_LIB_LOGE_APPEND_CAUSE(
-                       "Cannot get colander sink component class.");
-               goto error;
-       }
-
-       iterator->graph = graph;
-       bt_object_get_no_null_check(iterator->graph);
-       colander_data.msgs = (void *) iterator->base.msgs->pdata;
-       colander_data.count_addr = &iterator->count;
-
-       /*
-        * Hope that nobody uses this very unique name.
-        *
-        * We pass `BT_LOGGING_LEVEL_NONE` but the colander component
-        * class module does not use this level anyway since it belongs
-        * to the library.
-        */
-       graph_status = bt_graph_add_sink_component_with_init_method_data(
-                       (void *) graph, colander_comp_cls,
-                       "colander-36ac3409-b1a8-4d60-ab1f-4fdf341a8fb1",
-                       NULL, &colander_data, BT_LOGGING_LEVEL_NONE,
-                       (void *) &iterator->colander);
-       if (graph_status != BT_FUNC_STATUS_OK) {
-               BT_LIB_LOGE_APPEND_CAUSE(
-                       "Cannot add colander sink component to graph: "
-                       "%![graph-]+g, status=%s", graph,
-                       bt_common_func_status_string(graph_status));
-               goto error;
-       }
-
-       /*
-        * Connect provided output port to the colander component's
-        * input port.
-        */
-       colander_in_port =
-               (void *) bt_component_sink_borrow_input_port_by_index_const(
-                       (void *) iterator->colander, 0);
-       BT_ASSERT(colander_in_port);
-       graph_status = bt_graph_connect_ports(graph,
-               output_port, colander_in_port, NULL);
-       if (graph_status != BT_FUNC_STATUS_OK) {
-               BT_LIB_LOGW_APPEND_CAUSE(
-                       "Cannot connect colander sink's port: "
-                       "%![graph-]+g, %![comp-]+c, status=%s", graph,
-                       iterator->colander,
-                       bt_common_func_status_string(graph_status));
-               goto error;
-       }
-
-       /*
-        * At this point everything went fine. Make the graph
-        * nonconsumable forever so that only this message iterator
-        * can consume (thanks to bt_graph_consume_sink_no_check()).
-        * This avoids leaking the message created by the colander
-        * sink and moved to the message iterator's message
-        * member.
-        */
-       bt_graph_set_can_consume(iterator->graph, false);
-
-       /* Also set the graph as being configured. */
-       graph_status = bt_graph_configure(graph);
-       if (graph_status != BT_FUNC_STATUS_OK) {
-               BT_LIB_LOGW_APPEND_CAUSE(
-                       "Cannot configure graph after having "
-                       "added and connected colander sink: "
-                       "%![graph-]+g, %![comp-]+c, status=%s", graph,
-                       iterator->colander,
-                       bt_common_func_status_string(graph_status));
-               goto error;
-       }
-       goto end;
-
-error:
-       if (iterator && iterator->graph && iterator->colander) {
-               int ret;
-
-               /* Remove created colander component from graph if any */
-               colander_comp = iterator->colander;
-               BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
-
-               /*
-                * At this point the colander component's reference
-                * count is 0 because iterator->colander was the only
-                * owner. We also know that it is not connected because
-                * this is the last operation before this function
-                * succeeds.
-                *
-                * Since we honor the preconditions here,
-                * bt_graph_remove_unconnected_component() always
-                * succeeds.
-                */
-               ret = bt_graph_remove_unconnected_component(iterator->graph,
-                       (void *) colander_comp);
-               BT_ASSERT(ret == 0);
-       }
-
-       BT_OBJECT_PUT_REF_AND_RESET(iterator);
-
-end:
-       bt_object_put_ref(colander_comp_cls);
-       return (void *) iterator;
-}
-
-bt_bool bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+enum bt_message_iterator_can_seek_ns_from_origin_status
+bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
                struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
+               int64_t ns_from_origin, bt_bool *can_seek)
 {
-       bt_bool can = BT_FALSE;
+       enum bt_message_iterator_can_seek_ns_from_origin_status status;
 
        BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(can_seek, "Result (output)");
        BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
        BT_ASSERT_PRE(
                bt_component_borrow_graph(iterator->upstream_component)->config_state !=
@@ -1169,29 +995,66 @@ bt_bool bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
                bt_component_borrow_graph(iterator->upstream_component));
 
        if (iterator->methods.can_seek_ns_from_origin) {
-               can = iterator->methods.can_seek_ns_from_origin(iterator,
-                       ns_from_origin);
-               goto end;
+               /*
+                * Initialize to an invalid value, so we can post-assert that
+                * the method returned a valid value.
+                */
+               *can_seek = -1;
+
+               BT_LIB_LOGD("Calling user's \"can seek nanoseconds from origin\" method: %!+i",
+                       iterator);
+
+               status = (int) iterator->methods.can_seek_ns_from_origin(iterator,
+                       ns_from_origin, can_seek);
+
+               if (status != BT_FUNC_STATUS_OK) {
+                       BT_LIB_LOGW_APPEND_CAUSE(
+                               "Component input port message iterator's \"can seek nanoseconds from origin\" method failed: "
+                               "%![iter-]+i, status=%s",
+                               iterator, bt_common_func_status_string(status));
+                       goto end;
+               }
+
+               BT_ASSERT_POST(*can_seek == BT_TRUE || *can_seek == BT_FALSE,
+                       "Unexpected boolean value returned from user's \"can seek ns from origin\" method: val=%d, %![iter-]+i",
+                       *can_seek, iterator);
+
+               BT_LIB_LOGD(
+                       "User's \"can seek nanoseconds from origin\" returned successfully: "
+                       "%![iter-]+i, can-seek=%d",
+                       iterator, *can_seek);
+
+               if (*can_seek) {
+                       goto end;
+               }
        }
 
        /*
-        * Automatic seeking fall back: if we can seek to the beginning,
-        * then we can automatically seek to any message.
+        * Automatic seeking fall back: if we can seek to the beginning and the
+        * iterator supports forward seeking then we can automatically seek to
+        * any timestamp.
         */
-       if (iterator->methods.can_seek_beginning) {
-               can = iterator->methods.can_seek_beginning(iterator);
+       status = (int) bt_self_component_port_input_message_iterator_can_seek_beginning(
+               iterator, can_seek);
+       if (status != BT_FUNC_STATUS_OK) {
+               goto end;
        }
 
+       *can_seek = *can_seek && iterator->config.can_seek_forward;
+
 end:
-       return can;
+       return status;
 }
 
-bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
-               struct bt_self_component_port_input_message_iterator *iterator)
+enum bt_message_iterator_can_seek_beginning_status
+bt_self_component_port_input_message_iterator_can_seek_beginning(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               bt_bool *can_seek)
 {
-       bt_bool can = BT_FALSE;
+       enum bt_message_iterator_can_seek_beginning_status status;
 
        BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(can_seek, "Result (output)");
        BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
        BT_ASSERT_PRE(
                bt_component_borrow_graph(iterator->upstream_component)->config_state !=
@@ -1200,10 +1063,26 @@ bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
                bt_component_borrow_graph(iterator->upstream_component));
 
        if (iterator->methods.can_seek_beginning) {
-               can = iterator->methods.can_seek_beginning(iterator);
+               /*
+                * Initialize to an invalid value, so we can post-assert that
+                * the method returned a valid value.
+                */
+               *can_seek = -1;
+
+               status = (int) iterator->methods.can_seek_beginning(iterator, can_seek);
+
+               BT_ASSERT_POST(
+                       status != BT_FUNC_STATUS_OK ||
+                               *can_seek == BT_TRUE ||
+                               *can_seek == BT_FALSE,
+                       "Unexpected boolean value returned from user's \"can seek beginning\" method: val=%d, %![iter-]+i",
+                       *can_seek, iterator);
+       } else {
+               *can_seek = BT_FALSE;
+               status = BT_FUNC_STATUS_OK;
        }
 
-       return can;
+       return status;
 }
 
 static inline
@@ -1243,6 +1122,22 @@ void reset_iterator_expectations(
        iterator->clock_expectation.type = CLOCK_EXPECTATION_UNSET;
 }
 
+static
+bool message_iterator_can_seek_beginning(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       enum bt_message_iterator_can_seek_beginning_status status;
+       bt_bool can_seek;
+
+       status = bt_self_component_port_input_message_iterator_can_seek_beginning(
+               iterator, &can_seek);
+       if (status != BT_FUNC_STATUS_OK) {
+               can_seek = BT_FALSE;
+       }
+
+       return can_seek;
+}
+
 enum bt_message_iterator_seek_beginning_status
 bt_self_component_port_input_message_iterator_seek_beginning(
                struct bt_self_component_port_input_message_iterator *iterator)
@@ -1256,9 +1151,7 @@ bt_self_component_port_input_message_iterator_seek_beginning(
                        BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
                "Graph is not configured: %!+g",
                bt_component_borrow_graph(iterator->upstream_component));
-       BT_ASSERT_PRE(
-               bt_self_component_port_input_message_iterator_can_seek_beginning(
-                       iterator),
+       BT_ASSERT_PRE(message_iterator_can_seek_beginning(iterator),
                "Message iterator cannot seek beginning: %!+i", iterator);
 
        /*
@@ -1290,6 +1183,15 @@ bt_self_component_port_input_message_iterator_seek_beginning(
        return status;
 }
 
+bt_bool
+bt_self_component_port_input_message_iterator_can_seek_forward(
+               bt_self_component_port_input_message_iterator *iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+
+       return iterator->config.can_seek_forward;
+}
+
 /*
  * Structure used to record the state of a given stream during the fast-forward
  * phase of an auto-seek.
@@ -1450,7 +1352,7 @@ int auto_seek_handle_message(
                         * as we don't know if items were really
                         * discarded within the new time range.
                         */
-                       uint64_t new_begin_raw_value;
+                       uint64_t new_begin_raw_value = 0;
 
                        ret = bt_clock_class_clock_value_from_ns_from_origin(
                                msg_disc_items->default_end_cs->clock_class,
@@ -1781,6 +1683,22 @@ int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
                cc_offset_cycles, cc_freq, ns_from_origin, raw_value);
 }
 
+static
+bool message_iterator_can_seek_ns_from_origin(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       enum bt_message_iterator_can_seek_ns_from_origin_status status;
+       bt_bool can_seek;
+
+       status = bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+               iterator, ns_from_origin, &can_seek);
+       if (status != BT_FUNC_STATUS_OK) {
+               can_seek = BT_FALSE;
+       }
+
+       return can_seek;
+}
 
 enum bt_message_iterator_seek_ns_from_origin_status
 bt_self_component_port_input_message_iterator_seek_ns_from_origin(
@@ -1789,6 +1707,7 @@ bt_self_component_port_input_message_iterator_seek_ns_from_origin(
 {
        int status;
        GHashTable *stream_states = NULL;
+       bt_bool can_seek_by_itself;
 
        BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
        BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
@@ -1797,9 +1716,9 @@ bt_self_component_port_input_message_iterator_seek_ns_from_origin(
                        BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
                "Graph is not configured: %!+g",
                bt_component_borrow_graph(iterator->upstream_component));
+       /* The iterator must be able to seek ns from origin one way or another. */
        BT_ASSERT_PRE(
-               bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-                       iterator, ns_from_origin),
+               message_iterator_can_seek_ns_from_origin(iterator, ns_from_origin),
                "Message iterator cannot seek nanoseconds from origin: %!+i, "
                "ns-from-origin=%" PRId64, iterator, ns_from_origin);
        set_self_comp_port_input_msg_iterator_state(iterator,
@@ -1811,8 +1730,25 @@ bt_self_component_port_input_message_iterator_seek_ns_from_origin(
         */
        reset_iterator_expectations(iterator);
 
-       if (iterator->methods.seek_ns_from_origin) {
+       /* Check if the iterator can seek by itself.  If not we'll use autoseek. */
+       if (iterator->methods.can_seek_ns_from_origin) {
+               bt_component_class_message_iterator_can_seek_ns_from_origin_method_status
+                       can_seek_status;
+
+               can_seek_status =
+                       iterator->methods.can_seek_ns_from_origin(
+                               iterator, ns_from_origin, &can_seek_by_itself);
+               if (can_seek_status != BT_FUNC_STATUS_OK) {
+                       status = can_seek_status;
+                       goto end;
+               }
+       } else {
+               can_seek_by_itself = false;
+       }
+
+       if (can_seek_by_itself) {
                /* The iterator knows how to seek to a particular time, let it handle this. */
+               BT_ASSERT(iterator->methods.seek_ns_from_origin);
                BT_LIB_LOGD("Calling user's \"seek nanoseconds from origin\" method: "
                        "%![iter-]+i, ns=%" PRId64, iterator, ns_from_origin);
                status = iterator->methods.seek_ns_from_origin(iterator,
@@ -1833,10 +1769,19 @@ bt_self_component_port_input_message_iterator_seek_ns_from_origin(
                }
        } else {
                /*
-                * The iterator doesn't know how to seek to a particular time.  We will
-                * seek to the beginning and fast forward to the right place.
+                * The iterator doesn't know how to seek by itself to a
+                * particular time.  We will seek to the beginning and fast
+                * forward to the right place.
                 */
-               BT_ASSERT(iterator->methods.can_seek_beginning(iterator));
+               enum bt_component_class_message_iterator_can_seek_beginning_method_status
+                       can_seek_status;
+               bt_bool can_seek_beginning;
+
+               can_seek_status = iterator->methods.can_seek_beginning(iterator,
+                       &can_seek_beginning);
+               BT_ASSERT(can_seek_status == BT_FUNC_STATUS_OK);
+               BT_ASSERT(can_seek_beginning);
+
                BT_ASSERT(iterator->methods.seek_beginning);
                BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i",
                        iterator);
@@ -2028,70 +1973,14 @@ end:
        return status;
 }
 
-static inline
-bt_self_component_port_input_message_iterator *
-borrow_output_port_message_iterator_upstream_iterator(
-               struct bt_port_output_message_iterator *iterator)
-{
-       struct bt_component_class_sink_colander_priv_data *colander_data;
-
-       BT_ASSERT(iterator);
-       colander_data = (void *) iterator->colander->parent.user_data;
-       BT_ASSERT(colander_data);
-       BT_ASSERT(colander_data->msg_iter);
-       return colander_data->msg_iter;
-}
-
-bt_bool bt_port_output_message_iterator_can_seek_ns_from_origin(
-               struct bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin)
+bt_bool bt_self_message_iterator_is_interrupted(
+               const struct bt_self_message_iterator *self_msg_iter)
 {
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator), ns_from_origin);
-}
+       const struct bt_self_component_port_input_message_iterator *iterator =
+               (const void *) self_msg_iter;
 
-bt_bool bt_port_output_message_iterator_can_seek_beginning(
-               struct bt_port_output_message_iterator *iterator)
-{
        BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_can_seek_beginning(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator));
-}
-
-enum bt_message_iterator_seek_ns_from_origin_status
-bt_port_output_message_iterator_seek_ns_from_origin(
-               struct bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_seek_ns_from_origin(
-               borrow_output_port_message_iterator_upstream_iterator(iterator),
-               ns_from_origin);
-}
-
-enum bt_message_iterator_seek_beginning_status
-bt_port_output_message_iterator_seek_beginning(
-               struct bt_port_output_message_iterator *iterator)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_seek_beginning(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator));
-}
-
-void bt_port_output_message_iterator_get_ref(
-               const struct bt_port_output_message_iterator *iterator)
-{
-       bt_object_get_ref(iterator);
-}
-
-void bt_port_output_message_iterator_put_ref(
-               const struct bt_port_output_message_iterator *iterator)
-{
-       bt_object_put_ref(iterator);
+       return (bt_bool) bt_graph_is_interrupted(iterator->graph);
 }
 
 void bt_self_component_port_input_message_iterator_get_ref(
This page took 0.035749 seconds and 4 git commands to generate.