Notification iterator: transform precondition checks to BT_ASSERT_PRE()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 2 Mar 2018 00:08:30 +0000 (19:08 -0500)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 2 May 2019 03:41:50 +0000 (23:41 -0400)
Use BT_ASSERT_PRE() to assert that notification iterator preconditions
are satisfied instead of unconditional run-time checks.

A notification iterator now expects, for a given stream, that a
BT_NOTIFICATION_TYPE_STREAM_BEGIN notification is received as the first
notification, and a BT_NOTIFICATION_TYPE_PACKET_END notification as the
last one. It also expects that, for a given sequence of
BT_NOTIFICATION_TYPE_EVENT notifications which belong to the same
packet, a BT_NOTIFICATION_TYPE_PACKET_BEGIN notification is received
before and a BT_NOTIFICATION_TYPE_PACKET_END notification after.

A notification iterator does not automatically generate
BT_NOTIFICATION_TYPE_STREAM_BEGIN, BT_NOTIFICATION_TYPE_STREAM_END,
BT_NOTIFICATION_TYPE_PACKET_BEGIN, and BT_NOTIFICATION_TYPE_PACKET_END
notifications anymore. In developer mode, the iterator validates that
those notifications were emitted in the correct order and that no
notification is missing for the stream. This is made possible by a
notification sequence number. The first time a notification is received
by an iterator, the iterator sets its sequence number to the expected
one (previous sequence number for this stream plus one). Other iterators
validate that, for a given stream, the received notification's sequence
number is expected.

Because BT_NOTIFICATION_TYPE_STREAM_BEGIN,
BT_NOTIFICATION_TYPE_STREAM_END, BT_NOTIFICATION_TYPE_PACKET_BEGIN, and
BT_NOTIFICATION_TYPE_PACKET_END notifications are expected to be
manually emitted now, the concept of notification subscription is
removed. Each notification iterator user receives all the emitted
notifications, and either forwards the whole notification sequence (for
a given stream) as is or use them to create its own stream and
notifications.

Thanks to the notification sequence number, the stream's current
component port hash table is removed. A component can send notifications
from the same stream to two different ports now, but both streams of
notifications must be complete.

A notification iterator also checks that, when requested to be ended,
its stream is finished (BT_NOTIFICATION_TYPE_STREAM_END received). This
confirms that the iterator's user (consumer) received all the
notifications for a given stream and that nothing is discarded.

`plugins/ctf/common/notif-iter/notif-iter.c` is modified so that it
emits the required BT_NOTIFICATION_TYPE_STREAM_BEGIN notification as its
first one and BT_NOTIFICATION_TYPE_STREAM_END as its last one (when the
medium returns "end of stream"). In order to support multiple stream
files which contain packets of the same logical stream (LTTng's trace
file rotation), `plugins/ctf/fs-src/fs.c` is changed to ignore
"intermediate" BT_NOTIFICATION_TYPE_STREAM_BEGIN and
BT_NOTIFICATION_TYPE_STREAM_END notifications when it resets its CTF
notification iterator (`notif-iter`) between stream files.

Python bindings, some plugins, and some tests are not updated and could
not work as of this patch because further changes in the same patch set
will significantly change them anyway. The changes also do not deal with
BT_NOTIFICATION_TYPE_DISCARDED_EVENTS and
BT_NOTIFICATION_TYPE_DISCARDED_PACKETS notification types as I plan to
remove those types and make this information part of the
BT_NOTIFICATION_TYPE_PACKET_BEGIN type.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
27 files changed:
include/babeltrace/ctf-ir/stream-internal.h
include/babeltrace/graph/component-class-sink-colander-internal.h
include/babeltrace/graph/notification-internal.h
include/babeltrace/graph/notification-iterator-internal.h
include/babeltrace/graph/notification.h
include/babeltrace/graph/output-port-notification-iterator.h
include/babeltrace/graph/private-connection.h
lib/ctf-ir/stream.c
lib/graph/component-class-sink-colander.c
lib/graph/connection.c
lib/graph/iterator.c
lib/graph/notification/inactivity.c
lib/graph/notification/notification.c
plugins/ctf/common/notif-iter/notif-iter.c
plugins/ctf/common/notif-iter/notif-iter.h
plugins/ctf/fs-sink/writer.c
plugins/ctf/fs-src/fs.c
plugins/ctf/fs-src/fs.h
plugins/lttng-utils/plugin.c
plugins/text/pretty/pretty.c
plugins/utils/counter/counter.c
plugins/utils/dummy/dummy.c
plugins/utils/muxer/muxer.c
plugins/utils/trimmer/iterator.c
tests/lib/test_bt_notification_heap.c
tests/lib/test_bt_notification_iterator.c
tests/plugins/test-utils-muxer.c

index e6b8ea0ba2490493a28189ba5782519a0d2a19a8..3214c1653c09073b79019712f6b8193b35a0a124 100644 (file)
@@ -56,26 +56,6 @@ struct bt_stream {
        struct bt_field *packet_header;
        struct bt_field *packet_context;
 
-       /*
-        * When a notification which contains a reference to a stream
-        * object (event notification, for example) is returned by the
-        * "next" method of a sink or filter component's notification
-        * iterator, it must NOT be returned by the "next" method of a
-        * notification iterator which iterates on the notifications of
-        * another output port of the same component.
-        *
-        * To ensure this, the stream object keeps a hash table which
-        * indicates which port, for a given component, is currently
-        * allowed to emit notifications which contain a reference to
-        * this stream.
-        *
-        * This is a `struct bt_component *` to `struct bt_port *` hash
-        * table. Both pointers are weak references because there's no
-        * need to keep one or the other alive as far as this stream is
-        * concerned.
-        */
-       GHashTable *comp_cur_port;
-
        /* Writer-specific members. */
        /* Array of pointers to bt_event for the current packet */
        GPtrArray *events;
@@ -92,15 +72,6 @@ struct bt_stream {
 BT_HIDDEN
 int bt_stream_set_fd(struct bt_stream *stream, int fd);
 
-BT_HIDDEN
-void bt_stream_map_component_to_port(struct bt_stream *stream,
-               struct bt_component *comp,
-               struct bt_port *port);
-
-BT_HIDDEN
-struct bt_port *bt_stream_port_for_component(struct bt_stream *stream,
-               struct bt_component *comp);
-
 BT_HIDDEN
 void bt_stream_add_destroy_listener(struct bt_stream *stream,
                bt_stream_destroy_listener_func func, void *data);
index 36161112b780f38e1d78a03a0b8c204238280264..d58a8ddf8344ce8d231034a97be1931f2269f5e5 100644 (file)
@@ -34,7 +34,6 @@ struct bt_notification;
 
 struct bt_component_class_sink_colander_data {
        struct bt_notification **notification;
-       const enum bt_notification_type *notification_types;
 };
 
 extern struct bt_component_class *bt_component_class_sink_colander_get(void);
index c37d2f10b4c0a65beee806e43644038c8caeef05..d1149055717fc61c451f2dbbf66563f6a96f8720 100644 (file)
@@ -41,6 +41,7 @@ struct bt_notification {
        struct bt_object base;
        enum bt_notification_type type;
        get_stream_func get_stream;
+       uint64_t seq_num;
        bt_bool frozen;
 };
 
@@ -64,12 +65,8 @@ static inline
 const char *bt_notification_type_string(enum bt_notification_type type)
 {
        switch (type) {
-       case BT_NOTIFICATION_TYPE_SENTINEL:
-               return "BT_NOTIFICATION_TYPE_SENTINEL";
        case BT_NOTIFICATION_TYPE_UNKNOWN:
                return "BT_NOTIFICATION_TYPE_UNKNOWN";
-       case BT_NOTIFICATION_TYPE_ALL:
-               return "BT_NOTIFICATION_TYPE_ALL";
        case BT_NOTIFICATION_TYPE_EVENT:
                return "BT_NOTIFICATION_TYPE_EVENT";
        case BT_NOTIFICATION_TYPE_INACTIVITY:
index e0d841fcd0c6c201bb45bda6ae520cd7bf66be97..47b1915948f28e291417f3cebb95ec11f95ed0de 100644 (file)
@@ -95,43 +95,27 @@ struct bt_notification_iterator_private_connection {
        struct bt_component *upstream_component; /* Weak */
        struct bt_port *upstream_port; /* Weak */
        struct bt_connection *connection; /* Weak */
-       GQueue *queue; /* struct bt_notification * (owned by this) */
 
        /*
         * This hash table keeps the state of a stream as viewed by
-        * this notification iterator. This is used to:
+        * this notification iterator. This is used to, in developer
+        * mode:
         *
         * * Automatically enqueue "stream begin", "packet begin",
         *   "packet end", and "stream end" notifications depending
         *   on the stream's state and on the next notification returned
         *   by the upstream component.
         *
-        * * Make sure that, once the notification iterator has seen
-        *   a "stream end" notification for a given stream, that no
-        *   other notifications which refer to this stream can be
-        *   delivered by this iterator.
+        * * Make sure that, once the notification iterator has seen a
+        *   "stream end" notification for a given stream, no other
+        *   notifications which refer to this stream can be delivered
+        *   by this iterator.
         *
         * The key (struct bt_stream *) is not owned by this. The
         * value is an allocated state structure.
         */
        GHashTable *stream_states;
 
-       /*
-        * This is an array of actions which can be rolled back. It's
-        * similar to the memento pattern, but it's not exactly that. It
-        * is allocated once and reset for each notification to process.
-        * More details near the implementation.
-        */
-       GArray *actions;
-
-       /*
-        * This is a mask of notifications to which the user of this
-        * iterator is subscribed
-        * (see enum bt_private_connection_notification_iterator_notif_type
-        * above).
-        */
-       uint32_t subscription_mask;
-
        enum bt_private_connection_notification_iterator_state state;
        void *user_data;
 };
@@ -181,7 +165,6 @@ BT_HIDDEN
 enum bt_connection_status bt_private_connection_notification_iterator_create(
                struct bt_component *upstream_comp,
                struct bt_port *upstream_port,
-               const enum bt_notification_type *notification_types,
                struct bt_connection *connection,
                struct bt_notification_iterator_private_connection **iterator);
 
index b64d40ad29c76a0ac53899c85b88dcfa53178d12..ce4c374f3ad05d2be77f63765aa0cf0b1a95c52a 100644 (file)
@@ -37,9 +37,7 @@ struct bt_notification;
  * Notification types. Unhandled notification types should be ignored.
  */
 enum bt_notification_type {
-       BT_NOTIFICATION_TYPE_SENTINEL =                 -1000,
        BT_NOTIFICATION_TYPE_UNKNOWN =                  -1,
-       BT_NOTIFICATION_TYPE_ALL =                      -2,
        BT_NOTIFICATION_TYPE_EVENT =                    0,
        BT_NOTIFICATION_TYPE_INACTIVITY =               1,
        BT_NOTIFICATION_TYPE_STREAM_BEGIN =             2,
index 0fb4c5bc7111be257fe60cd97e6cccc6797ce113..750fff7d7e35b6c9eae3b597ae69e8523478bb29 100644 (file)
@@ -34,8 +34,7 @@ struct bt_port;
 struct bt_notification_iterator;
 
 extern struct bt_notification_iterator *bt_output_port_notification_iterator_create(
-               struct bt_port *port, const char *colander_component_name,
-               const enum bt_notification_type *notification_types);
+               struct bt_port *port, const char *colander_component_name);
 
 #ifdef __cplusplus
 }
index e16ce16ef1aa30e93627bc89e27428cdfa882c73..e62c1e36da917692bf711c5588fb14c048b051e6 100644 (file)
@@ -42,7 +42,6 @@ extern struct bt_connection *bt_connection_from_private(
 extern enum bt_connection_status
 bt_private_connection_create_notification_iterator(
                struct bt_private_connection *private_connection,
-               const enum bt_notification_type *notification_types,
                struct bt_notification_iterator **iterator);
 
 #ifdef __cplusplus
index 64f82d4a58b70f21bca144985db19d0f4e961982..c5c1f19a0777d48c05a599d89beb89b893bc78b2 100644 (file)
@@ -959,16 +959,6 @@ void set_stream_fd(struct bt_stream *stream, int fd)
        stream->pos.fd = fd;
 }
 
-static
-void component_destroy_listener(struct bt_component *component, void *data)
-{
-       struct bt_stream *stream = data;
-
-       BT_LOGD("Component is being destroyed, stream is notified: "
-               "comp-addr=%p, stream-addr=%p", component, stream);
-       g_hash_table_remove(stream->comp_cur_port, component);
-}
-
 static
 struct bt_stream *bt_stream_create_with_id_no_check(
                struct bt_stream_class *stream_class,
@@ -1148,12 +1138,6 @@ struct bt_stream *bt_stream_create_with_id_no_check(
        } else {
                /* Non-writer stream indicated by a negative FD */
                set_stream_fd(stream, -1);
-               stream->comp_cur_port = g_hash_table_new(g_direct_hash,
-                       g_direct_equal);
-               if (!stream->comp_cur_port) {
-                       BT_LOGE_STR("Failed to allocate a GHashTable.");
-                       goto error;
-               }
        }
 
        /* Add this stream to the trace's streams */
@@ -2009,28 +1993,6 @@ void bt_stream_destroy(struct bt_object *obj)
                g_string_free(stream->name, TRUE);
        }
 
-       if (stream->comp_cur_port) {
-               GHashTableIter ht_iter;
-               gpointer comp_gptr, port_gptr;
-
-               /*
-                * Since we're destroying the stream, remove the destroy
-                * listeners that it registered for each component in
-                * its component-port mapping hash table. Otherwise they
-                * would be called and the stream would be accessed once
-                * it's freed or another stream would be accessed.
-                */
-               g_hash_table_iter_init(&ht_iter, stream->comp_cur_port);
-
-               while (g_hash_table_iter_next(&ht_iter, &comp_gptr, &port_gptr)) {
-                       BT_ASSERT(comp_gptr);
-                       bt_component_remove_destroy_listener((void *) comp_gptr,
-                               component_destroy_listener, stream);
-               }
-
-               g_hash_table_destroy(stream->comp_cur_port);
-       }
-
        if (stream->destroy_listeners) {
                g_array_free(stream->destroy_listeners, TRUE);
        }
@@ -2141,45 +2103,6 @@ end:
        return ret;
 }
 
-BT_HIDDEN
-void bt_stream_map_component_to_port(struct bt_stream *stream,
-               struct bt_component *comp,
-               struct bt_port *port)
-{
-       BT_ASSERT(stream);
-       BT_ASSERT(comp);
-       BT_ASSERT(port);
-       BT_ASSERT(stream->comp_cur_port);
-
-       /*
-        * Do not take a reference to the component here because we
-        * don't want the component to exist as long as this stream
-        * exists. Instead, keep a weak reference, but add a destroy
-        * listener so that we remove this hash table entry when we know
-        * the component is destroyed.
-        */
-       BT_LOGV("Adding component's destroy listener for stream: "
-               "stream-addr=%p, stream-name=\"%s\", comp-addr=%p, "
-               "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
-               stream, bt_stream_get_name(stream),
-               comp, bt_component_get_name(comp), port,
-               bt_port_get_name(port));
-       bt_component_add_destroy_listener(comp, component_destroy_listener,
-               stream);
-       g_hash_table_insert(stream->comp_cur_port, comp, port);
-       BT_LOGV_STR("Mapped component to port for stream.");
-}
-
-BT_HIDDEN
-struct bt_port *bt_stream_port_for_component(struct bt_stream *stream,
-               struct bt_component *comp)
-{
-       BT_ASSERT(stream);
-       BT_ASSERT(comp);
-       BT_ASSERT(stream->comp_cur_port);
-       return g_hash_table_lookup(stream->comp_cur_port, comp);
-}
-
 BT_HIDDEN
 void bt_stream_add_destroy_listener(struct bt_stream *stream,
                bt_stream_destroy_listener_func func, void *data)
index d284ba4be3d91c4f23916b109841957334e32c03..d69989a278fc18cbe9f39169cebceec5f0410893 100644 (file)
@@ -52,7 +52,6 @@ enum bt_component_status colander_init(
        struct colander_data *colander_data = NULL;
        struct bt_component_class_sink_colander_data *user_provided_data =
                init_method_data;
-       const enum bt_notification_type *notif_type;
 
        if (!init_method_data) {
                BT_LOGW_STR("Component initialization method data is NULL.");
@@ -68,30 +67,6 @@ enum bt_component_status colander_init(
        }
 
        colander_data->user_notif = user_provided_data->notification;
-
-       if (user_provided_data->notification_types) {
-               notif_type = user_provided_data->notification_types;
-               unsigned long count;
-
-               while (*notif_type != BT_NOTIFICATION_TYPE_SENTINEL) {
-                       notif_type++;
-               }
-
-               count = notif_type - user_provided_data->notification_types + 1;
-
-               colander_data->notif_types =
-                       g_new0(enum bt_notification_type, count);
-               if (!colander_data->notif_types) {
-                       BT_LOGE_STR("Failed to allocate an array of notification types.");
-                       status = BT_COMPONENT_STATUS_NOMEM;
-                       goto end;
-               }
-
-               memcpy(colander_data->notif_types,
-                       user_provided_data->notification_types,
-                       count * sizeof(enum bt_notification_type));
-       }
-
        status = bt_private_component_sink_add_input_private_port(
                priv_comp, "in", NULL, NULL);
        if (status != BT_COMPONENT_STATUS_OK) {
@@ -138,8 +113,7 @@ void colander_port_connected(struct bt_private_component *priv_comp,
        BT_ASSERT(colander_data);
        BT_PUT(colander_data->notif_iter);
        conn_status = bt_private_connection_create_notification_iterator(
-               priv_conn, colander_data->notif_types,
-               &colander_data->notif_iter);
+               priv_conn, &colander_data->notif_iter);
        if (conn_status) {
                BT_LOGE("Cannot create notification iterator from connection: "
                        "comp-addr=%p, conn-addr=%p", priv_comp, priv_conn);
index 93c101e6b26478ad51fb298049ed5b6e7bc814d5..73b5383dee347e0fe7a8ae1aa436032d9ce6e1e0 100644 (file)
@@ -274,7 +274,6 @@ struct bt_port *bt_connection_get_downstream_port(
 enum bt_connection_status
 bt_private_connection_create_notification_iterator(
                struct bt_private_connection *private_connection,
-               const enum bt_notification_type *notification_types,
                struct bt_notification_iterator **user_iterator)
 {
        enum bt_component_class_type upstream_comp_class_type;
@@ -285,10 +284,6 @@ bt_private_connection_create_notification_iterator(
        struct bt_connection *connection = NULL;
        bt_component_class_notification_iterator_init_method init_method = NULL;
        enum bt_connection_status status;
-       static const enum bt_notification_type all_notif_types[] = {
-               BT_NOTIFICATION_TYPE_ALL,
-               BT_NOTIFICATION_TYPE_SENTINEL,
-       };
 
        if (!private_connection) {
                BT_LOGW_STR("Invalid parameter: private connection is NULL.");
@@ -326,11 +321,6 @@ bt_private_connection_create_notification_iterator(
                goto end;
        }
 
-       if (!notification_types) {
-               BT_LOGD_STR("No notification types: subscribing to all notifications.");
-               notification_types = all_notif_types;
-       }
-
        upstream_port = connection->upstream_port;
        BT_ASSERT(upstream_port);
        upstream_component = bt_port_get_component(upstream_port);
@@ -348,7 +338,7 @@ bt_private_connection_create_notification_iterator(
        BT_ASSERT(upstream_comp_class_type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
                        upstream_comp_class_type == BT_COMPONENT_CLASS_TYPE_FILTER);
        status = bt_private_connection_notification_iterator_create(upstream_component,
-               upstream_port, notification_types, connection, &iterator);
+               upstream_port, connection, &iterator);
        if (status != BT_CONNECTION_STATUS_OK) {
                BT_LOGW("Cannot create notification iterator from connection.");
                goto end;
index 0cd93172d8de9cfd1b2fc64783e30a8ff79a93d7..b98121a1d596a65f06854b10b2318bde390d563d 100644 (file)
@@ -58,6 +58,7 @@
 #include <babeltrace/graph/graph-internal.h>
 #include <babeltrace/types.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/assert-pre-internal.h>
 #include <stdint.h>
 #include <inttypes.h>
 #include <stdlib.h>
@@ -72,61 +73,10 @@ struct stream_state {
        struct bt_packet *cur_packet; /* owned by this */
        struct discarded_elements_state discarded_packets_state;
        struct discarded_elements_state discarded_events_state;
+       uint64_t expected_notif_seq_num;
        bt_bool is_ended;
 };
 
-enum action_type {
-       ACTION_TYPE_PUSH_NOTIF,
-       ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM,
-       ACTION_TYPE_ADD_STREAM_STATE,
-       ACTION_TYPE_SET_STREAM_STATE_IS_ENDED,
-       ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET,
-       ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS,
-       ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS,
-};
-
-struct action {
-       enum action_type type;
-       union {
-               /* ACTION_TYPE_PUSH_NOTIF */
-               struct {
-                       struct bt_notification *notif; /* owned by this */
-               } push_notif;
-
-               /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
-               struct {
-                       struct bt_stream *stream; /* owned by this */
-                       struct bt_component *component; /* owned by this */
-                       struct bt_port *port; /* owned by this */
-               } map_port_to_comp_in_stream;
-
-               /* ACTION_TYPE_ADD_STREAM_STATE */
-               struct {
-                       struct bt_stream *stream; /* owned by this */
-                       struct stream_state *stream_state; /* owned by this */
-               } add_stream_state;
-
-               /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
-               struct {
-                       struct stream_state *stream_state; /* weak */
-               } set_stream_state_is_ended;
-
-               /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
-               struct {
-                       struct stream_state *stream_state; /* weak */
-                       struct bt_packet *packet; /* owned by this */
-               } set_stream_state_cur_packet;
-
-               /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */
-               /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */
-               struct {
-                       struct stream_state *stream_state; /* weak */
-                       struct bt_clock_value *cur_begin; /* owned by this */
-                       uint64_t cur_count;
-               } update_stream_state_discarded_elements;
-       } payload;
-};
-
 static
 void stream_destroy_listener(struct bt_stream *stream, void *data)
 {
@@ -153,178 +103,6 @@ void destroy_stream_state(struct stream_state *stream_state)
        g_free(stream_state);
 }
 
-static
-void destroy_action(struct action *action)
-{
-       BT_ASSERT(action);
-
-       switch (action->type) {
-       case ACTION_TYPE_PUSH_NOTIF:
-               BT_PUT(action->payload.push_notif.notif);
-               break;
-       case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
-               BT_PUT(action->payload.map_port_to_comp_in_stream.stream);
-               BT_PUT(action->payload.map_port_to_comp_in_stream.component);
-               BT_PUT(action->payload.map_port_to_comp_in_stream.port);
-               break;
-       case ACTION_TYPE_ADD_STREAM_STATE:
-               BT_PUT(action->payload.add_stream_state.stream);
-               destroy_stream_state(
-                       action->payload.add_stream_state.stream_state);
-               action->payload.add_stream_state.stream_state = NULL;
-               break;
-       case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
-               BT_PUT(action->payload.set_stream_state_cur_packet.packet);
-               break;
-       case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
-               break;
-       case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS:
-       case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS:
-               BT_PUT(action->payload.update_stream_state_discarded_elements.cur_begin);
-               break;
-       default:
-               BT_LOGF("Unexpected action's type: type=%d", action->type);
-               abort();
-       }
-}
-
-static
-void add_action(struct bt_notification_iterator_private_connection *iterator,
-               struct action *action)
-{
-       g_array_append_val(iterator->actions, *action);
-}
-
-static
-void clear_actions(struct bt_notification_iterator_private_connection *iterator)
-{
-       size_t i;
-
-       for (i = 0; i < iterator->actions->len; i++) {
-               struct action *action = &g_array_index(iterator->actions,
-                       struct action, i);
-
-               destroy_action(action);
-       }
-
-       g_array_set_size(iterator->actions, 0);
-}
-
-static inline
-const char *action_type_string(enum action_type type)
-{
-       switch (type) {
-       case ACTION_TYPE_PUSH_NOTIF:
-               return "ACTION_TYPE_PUSH_NOTIF";
-       case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
-               return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
-       case ACTION_TYPE_ADD_STREAM_STATE:
-               return "ACTION_TYPE_ADD_STREAM_STATE";
-       case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
-               return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
-       case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
-               return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
-       case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS:
-               return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS";
-       case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS:
-               return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-void apply_actions(struct bt_notification_iterator_private_connection *iterator)
-{
-       size_t i;
-
-       BT_LOGV("Applying notification's iterator current actions: "
-               "count=%u", iterator->actions->len);
-
-       for (i = 0; i < iterator->actions->len; i++) {
-               struct action *action = &g_array_index(iterator->actions,
-                       struct action, i);
-
-               BT_LOGV("Applying action: index=%zu, type=%s",
-                       i, action_type_string(action->type));
-
-               switch (action->type) {
-               case ACTION_TYPE_PUSH_NOTIF:
-                       /* Move notification to queue */
-                       g_queue_push_head(iterator->queue,
-                               action->payload.push_notif.notif);
-                       bt_notification_freeze(
-                               action->payload.push_notif.notif);
-                       action->payload.push_notif.notif = NULL;
-                       break;
-               case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
-                       bt_stream_map_component_to_port(
-                               action->payload.map_port_to_comp_in_stream.stream,
-                               action->payload.map_port_to_comp_in_stream.component,
-                               action->payload.map_port_to_comp_in_stream.port);
-                       break;
-               case ACTION_TYPE_ADD_STREAM_STATE:
-                       /* Move stream state to hash table */
-                       g_hash_table_insert(iterator->stream_states,
-                               action->payload.add_stream_state.stream,
-                               action->payload.add_stream_state.stream_state);
-
-                       action->payload.add_stream_state.stream_state = NULL;
-                       break;
-               case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
-                       /*
-                        * We know that this stream is ended. We need to
-                        * remember this as long as the stream exists to
-                        * enforce that the same stream does not end
-                        * twice.
-                        *
-                        * Here we add a destroy listener to the stream
-                        * which we put after (becomes weak as the hash
-                        * table key). If we were the last object to own
-                        * this stream, the destroy listener is called
-                        * when we call bt_put() which removes this
-                        * stream state completely. This is important
-                        * because the memory used by this stream object
-                        * could be reused for another stream, and they
-                        * must have different states.
-                        */
-                       bt_stream_add_destroy_listener(
-                               action->payload.set_stream_state_is_ended.stream_state->stream,
-                               stream_destroy_listener, iterator);
-                       action->payload.set_stream_state_is_ended.stream_state->is_ended = BT_TRUE;
-                       BT_PUT(action->payload.set_stream_state_is_ended.stream_state->stream);
-                       break;
-               case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
-                       /* Move packet to stream state's current packet */
-                       BT_MOVE(action->payload.set_stream_state_cur_packet.stream_state->cur_packet,
-                               action->payload.set_stream_state_cur_packet.packet);
-                       break;
-               case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS:
-               case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS:
-               {
-                       struct discarded_elements_state *state;
-
-                       if (action->type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS) {
-                               state = &action->payload.update_stream_state_discarded_elements.stream_state->discarded_packets_state;
-                       } else {
-                               state = &action->payload.update_stream_state_discarded_elements.stream_state->discarded_events_state;
-                       }
-
-                       BT_MOVE(state->cur_begin,
-                               action->payload.update_stream_state_discarded_elements.cur_begin);
-                       state->cur_count = action->payload.update_stream_state_discarded_elements.cur_count;
-                       break;
-               }
-               default:
-                       BT_LOGF("Unexpected action's type: type=%d",
-                               action->type);
-                       abort();
-               }
-       }
-
-       clear_actions(iterator);
-}
-
 static
 struct stream_state *create_stream_state(struct bt_stream *stream)
 {
@@ -340,17 +118,12 @@ struct stream_state *create_stream_state(struct bt_stream *stream)
         * at 0 at the beginning of the stream. We therefore need to
         * have an internal object initial state of -1ULL to distinguish
         * between initial state and having seen a packet with
-        * seqnum = 0.
+        * the sequence number 0.
         */
        stream_state->discarded_packets_state.cur_count = -1ULL;
 
        /*
-        * We keep a reference to the stream until we know it's ended
-        * because we need to be able to create an automatic "stream
-        * end" notification when the user's "next" method returns
-        * BT_NOTIFICATION_ITERATOR_STATUS_END.
-        *
-        * We put this reference when the stream is marked as ended.
+        * We keep a reference to the stream until we know it's ended.
         */
        stream_state->stream = bt_get(stream);
        BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
@@ -395,18 +168,6 @@ void bt_private_connection_notification_iterator_destroy(struct bt_object *obj)
                iterator);
        bt_private_connection_notification_iterator_finalize(iterator);
 
-       if (iterator->queue) {
-               struct bt_notification *notif;
-
-               BT_LOGD("Putting notifications in queue.");
-
-               while ((notif = g_queue_pop_tail(iterator->queue))) {
-                       bt_put(notif);
-               }
-
-               g_queue_free(iterator->queue);
-       }
-
        if (iterator->stream_states) {
                /*
                 * Remove our destroy listener from each stream which
@@ -431,10 +192,6 @@ void bt_private_connection_notification_iterator_destroy(struct bt_object *obj)
                g_hash_table_destroy(iterator->stream_states);
        }
 
-       if (iterator->actions) {
-               g_array_free(iterator->actions, TRUE);
-       }
-
        if (iterator->connection) {
                /*
                 * Remove ourself from the originating connection so
@@ -534,71 +291,6 @@ void bt_private_connection_notification_iterator_set_connection(
                "iter-addr=%p, conn-addr=%p", iterator, connection);
 }
 
-static
-int create_subscription_mask_from_notification_types(
-               struct bt_notification_iterator_private_connection *iterator,
-               const enum bt_notification_type *notif_types)
-{
-       const enum bt_notification_type *notif_type;
-       int ret = 0;
-
-       BT_ASSERT(notif_types);
-       iterator->subscription_mask = 0;
-
-       for (notif_type = notif_types;
-                       *notif_type != BT_NOTIFICATION_TYPE_SENTINEL;
-                       notif_type++) {
-               switch (*notif_type) {
-               case BT_NOTIFICATION_TYPE_ALL:
-                       iterator->subscription_mask |=
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS |
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
-                       break;
-               case BT_NOTIFICATION_TYPE_EVENT:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
-                       break;
-               case BT_NOTIFICATION_TYPE_INACTIVITY:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
-                       break;
-               case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
-                       break;
-               case BT_NOTIFICATION_TYPE_STREAM_END:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
-                       break;
-               case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
-                       break;
-               case BT_NOTIFICATION_TYPE_PACKET_END:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
-                       break;
-               case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
-                       break;
-               case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
-                       iterator->subscription_mask |= BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
-                       break;
-               default:
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_LOGV("Added notification type to subscription mask: "
-                       "type=%s, mask=%x",
-                       bt_notification_type_string(*notif_type),
-                       iterator->subscription_mask);
-       }
-
-end:
-       return ret;
-}
-
 static
 void init_notification_iterator(struct bt_notification_iterator *iterator,
                enum bt_notification_iterator_type type,
@@ -612,7 +304,6 @@ BT_HIDDEN
 enum bt_connection_status bt_private_connection_notification_iterator_create(
                struct bt_component *upstream_comp,
                struct bt_port *upstream_port,
-               const enum bt_notification_type *notification_types,
                struct bt_connection *connection,
                struct bt_notification_iterator_private_connection **user_iterator)
 {
@@ -622,7 +313,6 @@ enum bt_connection_status bt_private_connection_notification_iterator_create(
 
        BT_ASSERT(upstream_comp);
        BT_ASSERT(upstream_port);
-       BT_ASSERT(notification_types);
        BT_ASSERT(bt_port_is_connected(upstream_port));
        BT_ASSERT(user_iterator);
        BT_LOGD("Creating notification iterator on private connection: "
@@ -646,13 +336,6 @@ enum bt_connection_status bt_private_connection_notification_iterator_create(
                BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION,
                bt_private_connection_notification_iterator_destroy);
 
-       if (create_subscription_mask_from_notification_types(iterator,
-                       notification_types)) {
-               BT_LOGW_STR("Cannot create subscription mask from notification types.");
-               status = BT_CONNECTION_STATUS_INVALID;
-               goto end;
-       }
-
        iterator->stream_states = g_hash_table_new_full(g_direct_hash,
                g_direct_equal, NULL, (GDestroyNotify) destroy_stream_state);
        if (!iterator->stream_states) {
@@ -661,20 +344,6 @@ enum bt_connection_status bt_private_connection_notification_iterator_create(
                goto end;
        }
 
-       iterator->queue = g_queue_new();
-       if (!iterator->queue) {
-               BT_LOGE_STR("Failed to allocate a GQueue.");
-               status = BT_CONNECTION_STATUS_NOMEM;
-               goto end;
-       }
-
-       iterator->actions = g_array_new(FALSE, FALSE, sizeof(struct action));
-       if (!iterator->actions) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               status = BT_CONNECTION_STATUS_NOMEM;
-               goto end;
-       }
-
        iterator->upstream_component = upstream_comp;
        iterator->upstream_port = upstream_port;
        iterator->connection = connection;
@@ -702,7 +371,8 @@ void *bt_private_connection_private_notification_iterator_get_user_data(
        struct bt_notification_iterator_private_connection *iterator =
                bt_private_connection_notification_iterator_borrow_from_private(private_iterator);
 
-       return iterator ? iterator->user_data : NULL;
+       BT_ASSERT_PRE_NON_NULL(private_iterator, "Notification iterator");
+       return iterator->user_data;
 }
 
 enum bt_notification_iterator_status
@@ -710,1390 +380,277 @@ bt_private_connection_private_notification_iterator_set_user_data(
                struct bt_private_connection_private_notification_iterator *private_iterator,
                void *data)
 {
-       enum bt_notification_iterator_status ret =
-                       BT_NOTIFICATION_ITERATOR_STATUS_OK;
        struct bt_notification_iterator_private_connection *iterator =
                bt_private_connection_notification_iterator_borrow_from_private(private_iterator);
 
-       if (!iterator) {
-               BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
-               goto end;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
        iterator->user_data = data;
        BT_LOGV("Set notification iterator's user data: "
                "iter-addr=%p, user-data-addr=%p", iterator, data);
-
-end:
-       return ret;
+       return BT_NOTIFICATION_ITERATOR_STATUS_OK;
 }
 
 struct bt_notification *bt_notification_iterator_get_notification(
                struct bt_notification_iterator *iterator)
 {
-       struct bt_notification *notification = NULL;
-
-       if (!iterator) {
-               BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
-               goto end;
-       }
-
-       notification = bt_get(
+       BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
+       return bt_get(
                bt_notification_iterator_borrow_current_notification(iterator));
-
-end:
-       return notification;
 }
 
-static
-enum bt_private_connection_notification_iterator_notif_type
-bt_notification_iterator_notif_type_from_notif_type(
-               enum bt_notification_type notif_type)
+BT_ASSERT_PRE_FUNC
+static inline
+void bt_notification_borrow_packet_stream(struct bt_notification *notif,
+               struct bt_stream **stream, struct bt_packet **packet)
 {
-       enum bt_private_connection_notification_iterator_notif_type iter_notif_type;
+       BT_ASSERT(notif);
 
-       switch (notif_type) {
+       switch (notif->type) {
        case BT_NOTIFICATION_TYPE_EVENT:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
-               break;
-       case BT_NOTIFICATION_TYPE_INACTIVITY:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
+               *packet = bt_event_borrow_packet(
+                       bt_notification_event_borrow_event(notif));
+               *stream = bt_packet_borrow_stream(*packet);
                break;
        case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
+               *stream = bt_notification_stream_begin_borrow_stream(notif);
                break;
        case BT_NOTIFICATION_TYPE_STREAM_END:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
+               *stream = bt_notification_stream_end_borrow_stream(notif);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
+               *packet = bt_notification_packet_begin_borrow_packet(notif);
+               *stream = bt_packet_borrow_stream(*packet);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_END:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
-               break;
-       case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
-               break;
-       case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
-               iter_notif_type = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
+               *packet = bt_notification_packet_end_borrow_packet(notif);
+               *stream = bt_packet_borrow_stream(*packet);
                break;
        default:
-               abort();
+               break;
        }
-
-       return iter_notif_type;
 }
 
-static
-bt_bool validate_notification(
+BT_ASSERT_PRE_FUNC
+static inline
+bool validate_notification(
                struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream,
-               struct bt_packet *notif_packet)
+               struct bt_notification *notif)
 {
-       bt_bool is_valid = BT_TRUE;
+       bool is_valid = true;
        struct stream_state *stream_state;
-       struct bt_port *stream_comp_cur_port;
+       struct bt_stream *stream = NULL;
+       struct bt_packet *packet = NULL;
+
+       BT_ASSERT(notif);
+       bt_notification_borrow_packet_stream(notif, &stream, &packet);
 
-       BT_ASSERT(notif_stream);
-       stream_comp_cur_port =
-               bt_stream_port_for_component(notif_stream,
-                       iterator->upstream_component);
-       if (!stream_comp_cur_port) {
+       if (!stream) {
+               /* we don't care about notifications not attached to streams */
+               goto end;
+       }
+
+       stream_state = g_hash_table_lookup(iterator->stream_states, stream);
+       if (!stream_state) {
                /*
-                * This is the first time this notification iterator
-                * bumps into this stream. Add an action to map the
-                * iterator's upstream component to the iterator's
-                * upstream port in this stream.
+                * No stream state for this stream: this notification
+                * MUST be a BT_NOTIFICATION_TYPE_STREAM_BEGIN notification
+                * and its sequence number must be 0.
                 */
-               struct action action = {
-                       .type = ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM,
-                       .payload.map_port_to_comp_in_stream = {
-                               .stream = bt_get(notif_stream),
-                               .component = bt_get(iterator->upstream_component),
-                               .port = bt_get(iterator->upstream_port),
-                       },
-               };
-
-               add_action(iterator, &action);
-       } else {
-               if (stream_comp_cur_port != iterator->upstream_port) {
-                       /*
-                        * It looks like two different ports of the same
-                        * component are emitting notifications which
-                        * have references to the same stream. This is
-                        * bad: the API guarantees that it can never
-                        * happen.
-                        */
-                       BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "stream-comp-cur-port-addr=%p, "
-                               "stream-comp-cur-port-name=%p, "
-                               "iter-upstream-port-addr=%p, "
-                               "iter-upstream-port-name=%s",
-                               notif_stream,
-                               bt_stream_get_name(notif_stream),
-                               stream_comp_cur_port,
-                               bt_port_get_name(stream_comp_cur_port),
-                               iterator->upstream_port,
-                               bt_port_get_name(iterator->upstream_port));
-                       is_valid = BT_FALSE;
+               if (notif->type != BT_NOTIFICATION_TYPE_STREAM_BEGIN) {
+                       BT_ASSERT_PRE_MSG("Unexpected notification: missing a "
+                               "BT_NOTIFICATION_TYPE_STREAM_BEGIN "
+                               "notification prior to this notification: "
+                               "%![stream-]+s", stream);
+                       is_valid = false;
                        goto end;
                }
 
-       }
-
-       stream_state = g_hash_table_lookup(iterator->stream_states,
-               notif_stream);
-       if (stream_state) {
-               BT_LOGV("Stream state already exists: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "stream-state-addr=%p",
-                       notif_stream,
-                       bt_stream_get_name(notif_stream), stream_state);
-
-               if (stream_state->is_ended) {
-                       /*
-                        * There's a new notification which has a
-                        * reference to a stream which, from this
-                        * iterator's point of view, is ended ("end of
-                        * stream" notification was returned). This is
-                        * bad: the API guarantees that it can never
-                        * happen.
-                        */
-                       BT_LOGW("Stream is already ended: "
-                               "stream-addr=%p, stream-name=\"%s\"",
-                               notif_stream,
-                               bt_stream_get_name(notif_stream));
-                       is_valid = BT_FALSE;
-                       goto end;
+               if (notif->seq_num == -1ULL) {
+                       notif->seq_num = 0;
                }
 
-               switch (notif->type) {
-               case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-                       /*
-                        * We already have a stream state, which means
-                        * we already returned a "stream begin"
-                        * notification: this is an invalid duplicate.
-                        */
-                       BT_LOGW("Duplicate stream beginning notification: "
-                               "stream-addr=%p, stream-name=\"%s\"",
-                               notif_stream,
-                               bt_stream_get_name(notif_stream));
-                       is_valid = BT_FALSE;
+               if (notif->seq_num != 0) {
+                       BT_ASSERT_PRE_MSG("Unexpected notification sequence "
+                               "number for this notification iterator: "
+                               "this is the first notification for this "
+                               "stream, expecting sequence number 0: "
+                               "seq-num=%" PRIu64 ", %![stream-]+s",
+                               notif->seq_num, stream);
+                       is_valid = false;
                        goto end;
-               case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-                       if (notif_packet == stream_state->cur_packet) {
-                               /* Duplicate "packet begin" notification */
-                               BT_LOGW("Duplicate stream beginning notification: "
-                                       "stream-addr=%p, stream-name=\"%s\", "
-                                       "packet-addr=%p",
-                                       notif_stream,
-                                       bt_stream_get_name(notif_stream),
-                                       notif_packet);
-                               is_valid = BT_FALSE;
-                               goto end;
-                       }
-                       break;
-               default:
-                       break;
                }
-       }
-
-end:
-       return is_valid;
-}
-
-static
-bt_bool is_subscribed_to_notification_type(
-               struct bt_notification_iterator_private_connection *iterator,
-               enum bt_notification_type notif_type)
-{
-       uint32_t iter_notif_type =
-               (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
-                       notif_type);
 
-       return (iter_notif_type & iterator->subscription_mask) ? BT_TRUE : BT_FALSE;
-}
-
-static
-void add_action_push_notif(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif)
-{
-       struct action action = {
-               .type = ACTION_TYPE_PUSH_NOTIF,
-       };
-
-       BT_ASSERT(notif);
+               stream_state = create_stream_state(stream);
+               if (!stream_state) {
+                       abort();
+               }
 
-       if (!is_subscribed_to_notification_type(iterator, notif->type)) {
-               return;
+               g_hash_table_insert(iterator->stream_states, stream,
+                       stream_state);
+               stream_state->expected_notif_seq_num++;
+               goto end;
        }
 
-       action.payload.push_notif.notif = bt_get(notif);
-       add_action(iterator, &action);
-       BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif);
-}
-
-static
-int add_action_push_notif_stream_begin(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_stream *stream)
-{
-       int ret = 0;
-       struct bt_notification *stream_begin_notif = NULL;
-
-       if (!is_subscribed_to_notification_type(iterator,
-                       BT_NOTIFICATION_TYPE_STREAM_BEGIN)) {
-               BT_LOGV("Not adding \"push stream beginning notification\" action: "
-                       "notification iterator is not subscribed: addr=%p",
-                       iterator);
+       if (stream_state->is_ended) {
+               /*
+                * There's a new notification which has a reference to a
+                * stream which, from this iterator's point of view, is
+                * ended ("end of stream" notification was returned).
+                * This is bad: the API guarantees that it can never
+                * happen.
+                */
+               BT_ASSERT_PRE_MSG("Stream is already ended: %![stream-]+s",
+                       stream);
+               is_valid = false;
                goto end;
        }
 
-       BT_ASSERT(stream);
-       stream_begin_notif = bt_notification_stream_begin_create(stream);
-       if (!stream_begin_notif) {
-               BT_LOGE_STR("Cannot create stream beginning notification.");
-               goto error;
+       if (notif->seq_num == -1ULL) {
+               notif->seq_num = stream_state->expected_notif_seq_num;
        }
 
-       add_action_push_notif(iterator, stream_begin_notif);
-       BT_LOGV("Added \"push stream beginning notification\" action: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_stream_get_name(stream));
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       bt_put(stream_begin_notif);
-       return ret;
-}
-
-static
-int add_action_push_notif_stream_end(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_stream *stream)
-{
-       int ret = 0;
-       struct bt_notification *stream_end_notif = NULL;
-
-       if (!is_subscribed_to_notification_type(iterator,
-                       BT_NOTIFICATION_TYPE_STREAM_END)) {
-               BT_LOGV("Not adding \"push stream end notification\" action: "
-                       "notification iterator is not subscribed: addr=%p",
-                       iterator);
+       if (notif->seq_num != -1ULL &&
+                       notif->seq_num != stream_state->expected_notif_seq_num) {
+               BT_ASSERT_PRE_MSG("Unexpected notification sequence number: "
+                       "seq-num=%" PRIu64 ", "
+                       "expected-seq-num=%" PRIu64 ", %![stream-]+s",
+                       notif->seq_num, stream_state->expected_notif_seq_num,
+                       stream);
+               is_valid = false;
                goto end;
        }
 
-       BT_ASSERT(stream);
-       stream_end_notif = bt_notification_stream_end_create(stream);
-       if (!stream_end_notif) {
-               BT_LOGE_STR("Cannot create stream end notification.");
-               goto error;
+       switch (notif->type) {
+       case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
+               BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_STREAM_BEGIN "
+                       "notification at this point: notif-seq-num=%" PRIu64 ", "
+                       "%![stream-]+s", notif->seq_num, stream);
+               is_valid = false;
+               goto end;
+       case BT_NOTIFICATION_TYPE_STREAM_END:
+               if (stream_state->cur_packet) {
+                       BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_STREAM_END "
+                               "notification: missing a "
+                               "BT_NOTIFICATION_TYPE_PACKET_END notification "
+                               "prior to this notification: "
+                               "notif-seq-num=%" PRIu64 ", "
+                               "%![stream-]+s", notif->seq_num, stream);
+                       is_valid = false;
+                       goto end;
+               }
+               stream_state->expected_notif_seq_num++;
+               stream_state->is_ended = true;
+               goto end;
+       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
+               if (stream_state->cur_packet) {
+                       BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_PACKET_BEGIN "
+                               "notification at this point: missing a "
+                               "BT_NOTIFICATION_TYPE_PACKET_END notification "
+                               "prior to this notification: "
+                               "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
+                               "%![packet-]+a", notif->seq_num, stream,
+                               packet);
+                       is_valid = false;
+                       goto end;
+               }
+               stream_state->expected_notif_seq_num++;
+               stream_state->cur_packet = bt_get(packet);
+               goto end;
+       case BT_NOTIFICATION_TYPE_PACKET_END:
+               if (!stream_state->cur_packet) {
+                       BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_PACKET_END "
+                               "notification at this point: missing a "
+                               "BT_NOTIFICATION_TYPE_PACKET_BEGIN notification "
+                               "prior to this notification: "
+                               "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
+                               "%![packet-]+a", notif->seq_num, stream,
+                               packet);
+                       is_valid = false;
+                       goto end;
+               }
+               stream_state->expected_notif_seq_num++;
+               BT_PUT(stream_state->cur_packet);
+               goto end;
+       case BT_NOTIFICATION_TYPE_EVENT:
+               if (packet != stream_state->cur_packet) {
+                       BT_ASSERT_PRE_MSG("Unexpected packet for "
+                               "BT_NOTIFICATION_TYPE_EVENT notification: "
+                               "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
+                               "%![notif-packet-]+a, %![expected-packet-]+a",
+                               notif->seq_num, stream,
+                               stream_state->cur_packet, packet);
+                       is_valid = false;
+                       goto end;
+               }
+               stream_state->expected_notif_seq_num++;
+               goto end;
+       default:
+               break;
        }
 
-       add_action_push_notif(iterator, stream_end_notif);
-       BT_LOGV("Added \"push stream end notification\" action: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_stream_get_name(stream));
-       goto end;
-
-error:
-       ret = -1;
-
 end:
-       bt_put(stream_end_notif);
-       return ret;
+       return is_valid;
 }
 
-static
-int add_action_push_notif_packet_begin(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_packet *packet)
+BT_ASSERT_PRE_FUNC
+static inline bool priv_conn_notif_iter_can_end(
+               struct bt_notification_iterator_private_connection *iterator)
 {
-       int ret = 0;
-       struct bt_notification *packet_begin_notif = NULL;
-
-       if (!is_subscribed_to_notification_type(iterator,
-                       BT_NOTIFICATION_TYPE_PACKET_BEGIN)) {
-               BT_LOGV("Not adding \"push packet beginning notification\" action: "
-                       "notification iterator is not subscribed: addr=%p",
-                       iterator);
-               goto end;
-       }
+       GHashTableIter iter;
+       gpointer stream_key, state_value;
+       bool ret = true;
 
-       BT_ASSERT(packet);
-       packet_begin_notif = bt_notification_packet_begin_create(packet);
-       if (!packet_begin_notif) {
-               BT_LOGE_STR("Cannot create packet beginning notification.");
-               goto error;
-       }
-
-       add_action_push_notif(iterator, packet_begin_notif);
-       BT_LOGV("Added \"push packet beginning notification\" action: "
-               "packet-addr=%p", packet);
-       goto end;
-
-error:
-       ret = -1;
+       /*
+        * Verify that this iterator received a
+        * BT_NOTIFICATION_TYPE_STREAM_END notification for each stream
+        * which has a state.
+        */
 
-end:
-       bt_put(packet_begin_notif);
-       return ret;
-}
+       g_hash_table_iter_init(&iter, iterator->stream_states);
 
-static
-int add_action_push_notif_packet_end(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_packet *packet)
-{
-       int ret = 0;
-       struct bt_notification *packet_end_notif = NULL;
+       while (g_hash_table_iter_next(&iter, &stream_key, &state_value)) {
+               struct stream_state *stream_state = (void *) state_value;
 
-       if (!is_subscribed_to_notification_type(iterator,
-                       BT_NOTIFICATION_TYPE_PACKET_END)) {
-               BT_LOGV("Not adding \"push packet end notification\" action: "
-                       "notification iterator is not subscribed: addr=%p",
-                       iterator);
-               goto end;
-       }
+               BT_ASSERT(stream_state);
+               BT_ASSERT(stream_key);
 
-       BT_ASSERT(packet);
-       packet_end_notif = bt_notification_packet_end_create(packet);
-       if (!packet_end_notif) {
-               BT_LOGE_STR("Cannot create packet end notification.");
-               goto error;
+               if (!stream_state->is_ended) {
+                       BT_ASSERT_PRE_MSG("Ending notification iterator, "
+                               "but stream is not ended: "
+                               "%![stream-]s", stream_key);
+                       ret = false;
+                       goto end;
+               }
        }
 
-       add_action_push_notif(iterator, packet_end_notif);
-       BT_LOGV("Added \"push packet end notification\" action: "
-               "packet-addr=%p", packet);
-       goto end;
-
-error:
-       ret = -1;
-
 end:
-       bt_put(packet_end_notif);
        return ret;
 }
 
 static
-void add_action_set_stream_state_is_ended(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct stream_state *stream_state)
+enum bt_notification_iterator_status
+bt_priv_conn_private_notification_iterator_next(
+               struct bt_notification_iterator_private_connection *iterator)
 {
-       struct action action = {
-               .type = ACTION_TYPE_SET_STREAM_STATE_IS_ENDED,
-               .payload.set_stream_state_is_ended = {
-                       .stream_state = stream_state,
-               },
+       struct bt_private_connection_private_notification_iterator *priv_iterator =
+               bt_private_connection_private_notification_iterator_from_notification_iterator(iterator);
+       bt_component_class_notification_iterator_next_method next_method = NULL;
+       struct bt_notification_iterator_next_method_return next_return = {
+               .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
+               .notification = NULL,
        };
+       enum bt_notification_iterator_status status =
+               BT_NOTIFICATION_ITERATOR_STATUS_OK;
 
-       BT_ASSERT(stream_state);
-       add_action(iterator, &action);
-       BT_LOGV("Added \"set stream state's ended\" action: "
-               "stream-state-addr=%p", stream_state);
-}
-
-static
-void add_action_set_stream_state_cur_packet(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct stream_state *stream_state,
-               struct bt_packet *packet)
-{
-       struct action action = {
-               .type = ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET,
-               .payload.set_stream_state_cur_packet = {
-                       .stream_state = stream_state,
-                       .packet = bt_get(packet),
-               },
-       };
-
-       BT_ASSERT(stream_state);
-       add_action(iterator, &action);
-       BT_LOGV("Added \"set stream state's current packet\" action: "
-               "stream-state-addr=%p, packet-addr=%p",
-               stream_state, packet);
-}
-
-static
-void add_action_update_stream_state_discarded_elements(
-               struct bt_notification_iterator_private_connection *iterator,
-               enum action_type type,
-               struct stream_state *stream_state,
-               struct bt_clock_value *cur_begin,
-               uint64_t cur_count)
-{
-       struct action action = {
-               .type = type,
-               .payload.update_stream_state_discarded_elements = {
-                       .stream_state = stream_state,
-                       .cur_begin = bt_get(cur_begin),
-                       .cur_count = cur_count,
-               },
-       };
-
-       BT_ASSERT(stream_state);
-       BT_ASSERT(type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS ||
-                       type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS);
-       add_action(iterator, &action);
-       if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS) {
-               BT_LOGV("Added \"update stream state's discarded packets\" action: "
-                       "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64,
-                       stream_state, cur_begin, cur_count);
-       } else if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS) {
-               BT_LOGV("Added \"update stream state's discarded events\" action: "
-                       "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64,
-                       stream_state, cur_begin, cur_count);
-       }
-}
-
-static
-int ensure_stream_state_exists(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *stream_begin_notif,
-               struct bt_stream *notif_stream,
-               struct stream_state **_stream_state)
-{
-       int ret = 0;
-       struct stream_state *stream_state = NULL;
-
-       if (!notif_stream) {
-               /*
-                * The notification does not reference any stream: no
-                * need to get or create a stream state.
-                */
-               goto end;
-       }
-
-       stream_state = g_hash_table_lookup(iterator->stream_states,
-               notif_stream);
-       if (!stream_state) {
-               /*
-                * This iterator did not bump into this stream yet:
-                * create a stream state and a "stream begin"
-                * notification.
-                */
-               struct action action = {
-                       .type = ACTION_TYPE_ADD_STREAM_STATE,
-                       .payload.add_stream_state = {
-                               .stream = bt_get(notif_stream),
-                               .stream_state = NULL,
-                       },
-               };
-
-               stream_state = create_stream_state(notif_stream);
-               if (!stream_state) {
-                       BT_LOGE_STR("Cannot create stream state.");
-                       goto error;
-               }
-
-               action.payload.add_stream_state.stream_state = stream_state;
-               add_action(iterator, &action);
-
-               if (stream_begin_notif) {
-                       add_action_push_notif(iterator, stream_begin_notif);
-               } else {
-                       ret = add_action_push_notif_stream_begin(iterator,
-                               notif_stream);
-                       if (ret) {
-                               BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
-                               goto error;
-                       }
-               }
-       }
-       goto end;
-
-error:
-       destroy_stream_state(stream_state);
-       stream_state = NULL;
-       ret = -1;
-
-end:
-       *_stream_state = stream_state;
-       return ret;
-}
-
-static
-struct bt_field *get_struct_field_uint(struct bt_field *struct_field,
-               const char *field_name)
-{
-       struct bt_field *field = NULL;
-       struct bt_field_type *ft = NULL;
-
-       field = bt_field_structure_get_field_by_name(struct_field,
-               field_name);
-       if (!field) {
-               BT_LOGV_STR("`%s` field does not exist.");
-               goto end;
-       }
-
-       if (!bt_field_is_integer(field)) {
-               BT_LOGV("Skipping `%s` field because its type is not an integer field type: "
-                       "field-addr=%p, ft-addr=%p, ft-id=%s", field_name,
-                       field, ft, bt_field_type_id_string(
-                               bt_field_type_get_type_id(ft)));
-               BT_PUT(field);
-               goto end;
-       }
-
-       ft = bt_field_get_type(field);
-       BT_ASSERT(ft);
-
-       if (bt_field_type_integer_is_signed(ft)) {
-               BT_LOGV("Skipping `%s` integer field because its type is signed: "
-                       "field-addr=%p, ft-addr=%p", field_name, field, ft);
-               BT_PUT(field);
-               goto end;
-       }
-
-end:
-       bt_put(ft);
-       return field;
-}
-
-static
-uint64_t get_packet_context_events_discarded(struct bt_packet *packet)
-{
-       struct bt_field *packet_context = NULL;
-       struct bt_field *field = NULL;
-       uint64_t retval = -1ULL;
-       int ret;
-
-       packet_context = bt_packet_get_context(packet);
-       if (!packet_context) {
-               goto end;
-       }
-
-       field = get_struct_field_uint(packet_context, "events_discarded");
-       if (!field) {
-               BT_LOGV("`events_discarded` field does not exist in packet's context field: "
-                       "packet-addr=%p, packet-context-field-addr=%p",
-                       packet, packet_context);
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_is_integer(field));
-       ret = bt_field_unsigned_integer_get_value(field, &retval);
-       if (ret) {
-               BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
-                       "packet-addr=%p, field-addr=%p",
-                       packet, field);
-               retval = -1ULL;
-               goto end;
-       }
-
-end:
-       bt_put(packet_context);
-       bt_put(field);
-       return retval;
-}
-
-static
-uint64_t get_packet_context_packet_seq_num(struct bt_packet *packet)
-{
-       struct bt_field *packet_context = NULL;
-       struct bt_field *field = NULL;
-       uint64_t retval = -1ULL;
-       int ret;
-
-       packet_context = bt_packet_get_context(packet);
-       if (!packet_context) {
-               goto end;
-       }
-
-       field = get_struct_field_uint(packet_context, "packet_seq_num");
-       if (!field) {
-               BT_LOGV("`packet_seq_num` field does not exist in packet's context field: "
-                       "packet-addr=%p, packet-context-field-addr=%p",
-                       packet, packet_context);
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_is_integer(field));
-       ret = bt_field_unsigned_integer_get_value(field, &retval);
-       if (ret) {
-               BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
-                       "packet-addr=%p, field-addr=%p",
-                       packet, field);
-               retval = -1ULL;
-               goto end;
-       }
-
-end:
-       bt_put(packet_context);
-       bt_put(field);
-       return retval;
-}
-
-static
-int handle_discarded_packets(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_packet *packet,
-               struct bt_clock_value *ts_begin,
-               struct bt_clock_value *ts_end,
-               struct stream_state *stream_state)
-{
-       struct bt_notification *notif = NULL;
-       uint64_t diff;
-       uint64_t prev_count, next_count;
-       int ret = 0;
-
-       next_count = get_packet_context_packet_seq_num(packet);
-       if (next_count == -1ULL) {
-               /*
-                * Stream does not have seqnum field, skip discarded
-                * packets feature.
-                */
-               goto end;
-       }
-       prev_count = stream_state->discarded_packets_state.cur_count;
-
-       if (prev_count != -1ULL) {
-               if (next_count < prev_count) {
-                       BT_LOGW("Current value of packet's context field's `packet_seq_num` field is lesser than the previous value for the same stream: "
-                               "not updating the stream state's current value: "
-                               "packet-addr=%p, prev-count=%" PRIu64 ", "
-                               "cur-count=%" PRIu64,
-                               packet, prev_count, next_count);
-                       goto end;
-               }
-               if (next_count == prev_count) {
-                       BT_LOGW("Current value of packet's context field's `packet_seq_num` field is equal to the previous value for the same stream: "
-                               "not updating the stream state's current value: "
-                               "packet-addr=%p, prev-count=%" PRIu64 ", "
-                               "cur-count=%" PRIu64,
-                               packet, prev_count, next_count);
-                       goto end;
-               }
-
-               diff = next_count - prev_count;
-               if (diff > 1) {
-                       /*
-                        * Add a discarded packets notification. The packets
-                        * are considered to be lost between the state's last time
-                        * and the current packet's beginning time.
-                        * The counter is expected to monotonically increase of
-                        * 1 for each packet. Therefore, the number of missing
-                        * packets is 'diff - 1'.
-                        */
-                       notif = bt_notification_discarded_elements_create(
-                               BT_NOTIFICATION_TYPE_DISCARDED_PACKETS,
-                               stream_state->stream,
-                               stream_state->discarded_packets_state.cur_begin,
-                               ts_begin, diff - 1);
-                       if (!notif) {
-                               BT_LOGE_STR("Cannot create discarded packets notification.");
-                               ret = -1;
-                               goto end;
-                       }
-
-                       add_action_push_notif(iterator, notif);
-               }
-       }
-
-       add_action_update_stream_state_discarded_elements(iterator,
-               ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS,
-               stream_state, ts_end, next_count);
-
-end:
-       bt_put(notif);
-       return ret;
-}
-
-static
-int handle_discarded_events(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_packet *packet,
-               struct bt_clock_value *ts_begin,
-               struct bt_clock_value *ts_end,
-               struct stream_state *stream_state)
-{
-       struct bt_notification *notif = NULL;
-       uint64_t diff;
-       uint64_t next_count;
-       int ret = 0;
-
-       next_count = get_packet_context_events_discarded(packet);
-       if (next_count == -1ULL) {
-               next_count = stream_state->discarded_events_state.cur_count;
-               goto update_state;
-       }
-
-       if (next_count < stream_state->discarded_events_state.cur_count) {
-               BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: "
-                       "not updating the stream state's current value: "
-                       "packet-addr=%p, prev-count=%" PRIu64 ", "
-                       "cur-count=%" PRIu64,
-                       packet, stream_state->discarded_events_state.cur_count,
-                       next_count);
-               goto end;
-       }
-
-       diff = next_count - stream_state->discarded_events_state.cur_count;
-       if (diff > 0) {
-               /*
-                * Add a discarded events notification. The events are
-                * considered to be lost betweem the state's last time
-                * and the current packet's end time.
-                */
-               notif = bt_notification_discarded_elements_create(
-                       BT_NOTIFICATION_TYPE_DISCARDED_EVENTS,
-                       stream_state->stream,
-                       stream_state->discarded_events_state.cur_begin,
-                       ts_end, diff);
-               if (!notif) {
-                       BT_LOGE_STR("Cannot create discarded events notification.");
-                       ret = -1;
-                       goto end;
-               }
-
-               add_action_push_notif(iterator, notif);
-       }
-
-update_state:
-       add_action_update_stream_state_discarded_elements(iterator,
-               ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS,
-               stream_state, ts_end, next_count);
-
-end:
-       bt_put(notif);
-       return ret;
-}
-
-static
-int get_field_clock_value(struct bt_field *root_field,
-               const char *field_name,
-               struct bt_clock_value **user_clock_val)
-{
-       struct bt_field *field;
-       struct bt_field_type *ft = NULL;
-       struct bt_clock_class *clock_class = NULL;
-       struct bt_clock_value *clock_value = NULL;
-       uint64_t val;
-       int ret = 0;
-
-       field = get_struct_field_uint(root_field, field_name);
-       if (!field) {
-               /* Not an error: skip this */
-               goto end;
-       }
-
-       ft = bt_field_get_type(field);
-       BT_ASSERT(ft);
-       clock_class = bt_field_type_integer_get_mapped_clock_class(ft);
-       if (!clock_class) {
-               BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
-                       "ft-addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_field_unsigned_integer_get_value(field, &val);
-       if (ret) {
-               BT_LOGW("Cannot get integer field's raw value: "
-                       "field-addr=%p", field);
-               ret = -1;
-               goto end;
-       }
-
-       clock_value = bt_clock_value_create(clock_class, val);
-       if (!clock_value) {
-               BT_LOGE_STR("Cannot create clock value from clock class.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Move clock value to user */
-       *user_clock_val = clock_value;
-       clock_value = NULL;
-
-end:
-       bt_put(field);
-       bt_put(ft);
-       bt_put(clock_class);
-       bt_put(clock_value);
-       return ret;
-}
-
-static
-int get_ts_begin_ts_end_from_packet(struct bt_packet *packet,
-               struct bt_clock_value **user_ts_begin,
-               struct bt_clock_value **user_ts_end)
-{
-       struct bt_field *packet_context = NULL;
-       struct bt_clock_value *ts_begin = NULL;
-       struct bt_clock_value *ts_end = NULL;
-       int ret = 0;
-
-       packet_context = bt_packet_get_context(packet);
-       if (!packet_context) {
-               goto end;
-       }
-
-       ret = get_field_clock_value(packet_context, "timestamp_begin",
-               &ts_begin);
-       if (ret) {
-               BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
-                       "packet-addr=%p, packet-context-field-addr=%p",
-                       packet, packet_context);
-               goto end;
-       }
-
-       ret = get_field_clock_value(packet_context, "timestamp_end",
-               &ts_end);
-       if (ret) {
-               BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
-                       "packet-addr=%p, packet-context-field-addr=%p",
-                       packet, packet_context);
-               goto end;
-       }
-
-       /* Move clock values to user */
-       *user_ts_begin = ts_begin;
-       ts_begin = NULL;
-       *user_ts_end = ts_end;
-       ts_end = NULL;
-
-end:
-       bt_put(packet_context);
-       bt_put(ts_begin);
-       bt_put(ts_end);
-       return ret;
-}
-
-static
-int handle_discarded_elements(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_packet *packet, struct stream_state *stream_state)
-{
-       struct bt_clock_value *ts_begin = NULL;
-       struct bt_clock_value *ts_end = NULL;
-       int ret;
-
-       ret = get_ts_begin_ts_end_from_packet(packet, &ts_begin, &ts_end);
-       if (ret) {
-               BT_LOGW("Cannot get packet's beginning or end clock values: "
-                       "packet-addr=%p, ret=%d", packet, ret);
-               ret = -1;
-               goto end;
-       }
-
-       ret = handle_discarded_packets(iterator, packet, ts_begin, ts_end,
-               stream_state);
-       if (ret) {
-               BT_LOGW("Cannot handle discarded packets for packet: "
-                       "packet-addr=%p, ret=%d", packet, ret);
-               ret = -1;
-               goto end;
-       }
-
-       ret = handle_discarded_events(iterator, packet, ts_begin, ts_end,
-               stream_state);
-       if (ret) {
-               BT_LOGW("Cannot handle discarded events for packet: "
-                       "packet-addr=%p, ret=%d", packet, ret);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       bt_put(ts_begin);
-       bt_put(ts_end);
-       return ret;
-}
-
-static
-int handle_packet_switch(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *packet_begin_notif,
-               struct bt_packet *new_packet,
-               struct stream_state *stream_state)
-{
-       int ret = 0;
-
-       if (stream_state->cur_packet == new_packet) {
-               goto end;
-       }
-
-       BT_LOGV("Handling packet switch: "
-               "cur-packet-addr=%p, new-packet-addr=%p",
-               stream_state->cur_packet, new_packet);
-
-       if (stream_state->cur_packet) {
-               /* End of the current packet */
-               ret = add_action_push_notif_packet_end(iterator,
-                       stream_state->cur_packet);
-               if (ret) {
-                       BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
-                       goto error;
-               }
-       }
-
-       /*
-        * Check the new packet's context fields for discarded packets
-        * and events to emit those automatic notifications.
-        */
-       ret = handle_discarded_elements(iterator, new_packet, stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot handle discarded elements for new packet.");
-               goto error;
-       }
-
-       /* Beginning of the new packet */
-       if (packet_begin_notif) {
-               add_action_push_notif(iterator, packet_begin_notif);
-       } else if (new_packet) {
-               ret = add_action_push_notif_packet_begin(iterator,
-                       new_packet);
-               if (ret) {
-                       BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
-                       goto error;
-               }
-       }
-
-       add_action_set_stream_state_cur_packet(iterator, stream_state,
-               new_packet);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_stream_begin(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_STREAM_BEGIN);
-       BT_ASSERT(notif_stream);
-       ret = ensure_stream_state_exists(iterator, notif, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_stream_end(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_STREAM_END);
-       BT_ASSERT(notif_stream);
-       ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot handle packet switch.");
-               goto error;
-       }
-
-       add_action_push_notif(iterator, notif);
-       add_action_set_stream_state_is_ended(iterator, stream_state);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_discarded_elements(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_DISCARDED_EVENTS ||
-                       notif->type == BT_NOTIFICATION_TYPE_DISCARDED_PACKETS);
-       BT_ASSERT(notif_stream);
-       ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       add_action_push_notif(iterator, notif);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_packet_begin(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream,
-               struct bt_packet *notif_packet)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_PACKET_BEGIN);
-       BT_ASSERT(notif_packet);
-       ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       ret = handle_packet_switch(iterator, notif, notif_packet, stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot handle packet switch.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_packet_end(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream,
-               struct bt_packet *notif_packet)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_PACKET_END);
-       BT_ASSERT(notif_packet);
-       ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot handle packet switch.");
-               goto error;
-       }
-
-       /* End of the current packet */
-       add_action_push_notif(iterator, notif);
-       add_action_set_stream_state_cur_packet(iterator, stream_state, NULL);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_notif_event(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif,
-               struct bt_stream *notif_stream,
-               struct bt_packet *notif_packet)
-{
-       int ret = 0;
-       struct stream_state *stream_state;
-
-       BT_ASSERT(notif->type == BT_NOTIFICATION_TYPE_EVENT);
-       BT_ASSERT(notif_packet);
-       ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
-               &stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot ensure that stream state exists.");
-               goto error;
-       }
-
-       ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
-       if (ret) {
-               BT_LOGE_STR("Cannot handle packet switch.");
-               goto error;
-       }
-
-       add_action_push_notif(iterator, notif);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int enqueue_notification_and_automatic(
-               struct bt_notification_iterator_private_connection *iterator,
-               struct bt_notification *notif)
-{
-       int ret = 0;
-       struct bt_event *notif_event = NULL;
-       struct bt_stream *notif_stream = NULL;
-       struct bt_packet *notif_packet = NULL;
-
-       BT_ASSERT(notif);
-
-       BT_LOGV("Enqueuing user notification and automatic notifications: "
-               "iter-addr=%p, notif-addr=%p", iterator, notif);
-
-       // TODO: Skip most of this if the iterator is only subscribed
-       //       to event/inactivity notifications.
-
-       /* Get the stream and packet referred by the notification */
-       switch (notif->type) {
-       case BT_NOTIFICATION_TYPE_EVENT:
-               notif_event = bt_notification_event_borrow_event(notif);
-               BT_ASSERT(notif_event);
-               notif_packet = bt_event_borrow_packet(notif_event);
-               BT_ASSERT(notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-               notif_stream =
-                       bt_notification_stream_begin_borrow_stream(notif);
-               BT_ASSERT(notif_stream);
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_END:
-               notif_stream = bt_notification_stream_end_borrow_stream(notif);
-               BT_ASSERT(notif_stream);
-               break;
-       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-               notif_packet =
-                       bt_notification_packet_begin_borrow_packet(notif);
-               BT_ASSERT(notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_PACKET_END:
-               notif_packet = bt_notification_packet_end_borrow_packet(notif);
-               BT_ASSERT(notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_INACTIVITY:
-               /* Always valid */
-               goto handle_notif;
-       default:
-               /*
-                * Invalid type of notification. Only the notification
-                * types above are allowed to be returned by a user
-                * component.
-                */
-               BT_LOGF("Unexpected notification type at this point: "
-                       "notif-addr=%p, notif-type=%s", notif,
-                       bt_notification_type_string(notif->type));
-               abort();
-       }
-
-       if (notif_packet) {
-               notif_stream = bt_packet_borrow_stream(notif_packet);
-               BT_ASSERT(notif_stream);
-       }
-
-       if (!notif_stream) {
-               /*
-                * The notification has no reference to a stream: it
-                * cannot cause the creation of automatic notifications.
-                */
-               BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
-               goto end;
-       }
-
-       if (!validate_notification(iterator, notif, notif_stream,
-                       notif_packet)) {
-               BT_LOGW_STR("Invalid notification.");
-               goto error;
-       }
-
-handle_notif:
-       switch (notif->type) {
-       case BT_NOTIFICATION_TYPE_EVENT:
-               ret = handle_notif_event(iterator, notif, notif_stream,
-                       notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-               ret = handle_notif_stream_begin(iterator, notif, notif_stream);
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_END:
-               ret = handle_notif_stream_end(iterator, notif, notif_stream);
-               break;
-       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-               ret = handle_notif_packet_begin(iterator, notif, notif_stream,
-                       notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_PACKET_END:
-               ret = handle_notif_packet_end(iterator, notif, notif_stream,
-                       notif_packet);
-               break;
-       case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
-       case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
-               ret = handle_notif_discarded_elements(iterator, notif,
-                       notif_stream);
-               break;
-       case BT_NOTIFICATION_TYPE_INACTIVITY:
-               add_action_push_notif(iterator, notif);
-               break;
-       default:
-               break;
-       }
-
-       if (ret) {
-               BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
-               goto error;
-       }
-
-       apply_actions(iterator);
-       BT_LOGV("Enqueued user notification and automatic notifications: "
-               "iter-addr=%p, notif-addr=%p", iterator, notif);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int handle_end(struct bt_notification_iterator_private_connection *iterator)
-{
-       GHashTableIter stream_state_iter;
-       gpointer stream_gptr, stream_state_gptr;
-       int ret = 0;
-
-       BT_LOGV("Handling end of iteration: addr=%p", iterator);
-
-       /*
-        * Emit a "stream end" notification for each non-ended stream
-        * known by this iterator and mark them as ended.
-        */
-       g_hash_table_iter_init(&stream_state_iter, iterator->stream_states);
-
-       while (g_hash_table_iter_next(&stream_state_iter, &stream_gptr,
-                       &stream_state_gptr)) {
-               struct stream_state *stream_state = stream_state_gptr;
-
-               BT_ASSERT(stream_state_gptr);
-
-               if (stream_state->is_ended) {
-                       continue;
-               }
-
-               ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
-               if (ret) {
-                       BT_LOGE_STR("Cannot handle packet switch.");
-                       goto error;
-               }
-
-               ret = add_action_push_notif_stream_end(iterator, stream_gptr);
-               if (ret) {
-                       BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
-                       goto error;
-               }
-
-               add_action_set_stream_state_is_ended(iterator, stream_state);
-       }
-
-       apply_actions(iterator);
-       BT_LOGV("Handled end of iteration: addr=%p", iterator);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-enum bt_notification_iterator_status ensure_queue_has_notifications(
-               struct bt_notification_iterator_private_connection *iterator)
-{
-       struct bt_private_connection_private_notification_iterator *priv_iterator =
-               bt_private_connection_private_notification_iterator_from_notification_iterator(iterator);
-       bt_component_class_notification_iterator_next_method next_method = NULL;
-       struct bt_notification_iterator_next_method_return next_return = {
-               .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
-               .notification = NULL,
-       };
-       enum bt_notification_iterator_status status =
-               BT_NOTIFICATION_ITERATOR_STATUS_OK;
-       int ret;
-
-       BT_ASSERT(iterator);
-       BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
-               "iter-addr=%p, queue-size=%u, iter-state=%s",
-               iterator, iterator->queue->length,
-               bt_private_connection_notification_iterator_state_string(iterator->state));
-
-       if (iterator->queue->length > 0) {
-               /*
-                * We already have enough. Even if this notification
-                * iterator is finalized, its user can still flush its
-                * current queue's content by calling its "next" method
-                * since this content is local and has no impact on what
-                * used to be the iterator's upstream component.
-                */
-               BT_LOGD_STR("Queue already has at least one notification.");
-               goto end;
-       }
-
-       switch (iterator->state) {
-       case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
-       case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED:
-               BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
-               status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
-               goto end;
-       case BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED:
-               BT_LOGD_STR("Notification iterator is ended.");
-               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-               goto end;
-       default:
-               break;
-       }
-
-       BT_ASSERT(iterator->upstream_component);
-       BT_ASSERT(iterator->upstream_component->class);
+       BT_ASSERT(iterator);
+       BT_LIB_LOGD("Getting next notification iterator's notification: %!+i",
+               iterator);
+       BT_ASSERT_PRE(iterator->state ==
+               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ACTIVE,
+               "Notification iterator's \"next\" called, but "
+               "iterator is in the wrong state: %!+i", iterator);
+       BT_ASSERT(iterator->upstream_component);
+       BT_ASSERT(iterator->upstream_component->class);
 
        /* Pick the appropriate "next" method */
        switch (iterator->upstream_component->class->type) {
@@ -2126,109 +683,71 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
         * and status.
         */
        BT_ASSERT(next_method);
+       BT_LOGD_STR("Calling user's \"next\" method.");
+       next_return = next_method(priv_iterator);
+       BT_LOGD("User method returned: status=%s",
+               bt_notification_iterator_status_string(next_return.status));
+       if (next_return.status < 0) {
+               BT_LOGW_STR("User method failed.");
+               status = next_return.status;
+               goto end;
+       }
 
-       while (iterator->queue->length == 0) {
-               BT_LOGD_STR("Calling user's \"next\" method.");
-               next_return = next_method(priv_iterator);
-               BT_LOGD("User method returned: status=%s",
-                       bt_notification_iterator_status_string(next_return.status));
-               if (next_return.status < 0) {
-                       BT_LOGW_STR("User method failed.");
-                       status = next_return.status;
-                       goto end;
+       if (iterator->state == BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
+                       iterator->state == BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED) {
+               /*
+                * The user's "next" method, somehow, cancelled its own
+                * notification iterator. This can happen, for example,
+                * when the user's method removes the port on which
+                * there's the connection from which the iterator was
+                * created. In this case, said connection is ended, and
+                * all its notification iterators are finalized.
+                *
+                * Only bt_put() the returned notification if
+                * the status is
+                * BT_NOTIFICATION_ITERATOR_STATUS_OK because
+                * otherwise this field could be garbage.
+                */
+               if (next_return.status ==
+                               BT_NOTIFICATION_ITERATOR_STATUS_OK) {
+                       bt_put(next_return.notification);
                }
 
-               if (iterator->state == BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
-                               iterator->state == BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED) {
-                       /*
-                        * The user's "next" method, somehow, cancelled
-                        * its own notification iterator. This can
-                        * happen, for example, when the user's method
-                        * removes the port on which there's the
-                        * connection from which the iterator was
-                        * created. In this case, said connection is
-                        * ended, and all its notification iterators are
-                        * finalized.
-                        *
-                        * Only bt_put() the returned notification if
-                        * the status is
-                        * BT_NOTIFICATION_ITERATOR_STATUS_OK because
-                        * otherwise this field could be garbage.
-                        */
-                       if (next_return.status ==
-                                       BT_NOTIFICATION_ITERATOR_STATUS_OK) {
-                               bt_put(next_return.notification);
-                       }
-
-                       status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
-                       goto end;
-               }
+               status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
+               goto end;
+       }
 
-               switch (next_return.status) {
-               case BT_NOTIFICATION_ITERATOR_STATUS_END:
-                       ret = handle_end(iterator);
-                       if (ret) {
-                               BT_LOGW_STR("Cannot handle end of iteration.");
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       BT_ASSERT(iterator->state ==
-                               BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ACTIVE);
-                       iterator->state = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED;
-
-                       if (iterator->queue->length == 0) {
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-                       }
-
-                       BT_LOGD("Set new status: status=%s",
-                               bt_notification_iterator_status_string(status));
-                       goto end;
-               case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
-                       status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
-                       goto end;
-               case BT_NOTIFICATION_ITERATOR_STATUS_OK:
-                       if (!next_return.notification) {
-                               BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       /*
-                        * Ignore some notifications which are always
-                        * automatically generated by the notification
-                        * iterator to make sure they have valid values.
-                        */
-                       switch (next_return.notification->type) {
-                       case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
-                       case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
-                               BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: "
-                                       "notif-type=%s",
-                                       bt_notification_type_string(next_return.notification->type));
-                               BT_PUT(next_return.notification);
-                               continue;
-                       default:
-                               break;
-                       }
-
-                       /*
-                        * We know the notification is valid. Before we
-                        * push it to the head of the queue, push the
-                        * appropriate automatic notifications if any.
-                        */
-                       ret = enqueue_notification_and_automatic(iterator,
-                               next_return.notification);
-                       BT_PUT(next_return.notification);
-                       if (ret) {
-                               BT_LOGW("Cannot enqueue notification and automatic notifications.");
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-                       break;
-               default:
-                       /* Unknown non-error status */
-                       abort();
-               }
+       switch (next_return.status) {
+       case BT_NOTIFICATION_ITERATOR_STATUS_END:
+               BT_ASSERT_PRE(priv_conn_notif_iter_can_end(iterator),
+                       "Notification iterator cannot end at this point: "
+                       "%!+i", iterator);
+               BT_ASSERT(iterator->state ==
+                       BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ACTIVE);
+               iterator->state = BT_PRIVATE_CONNECTION_NOTIFICATION_ITERATOR_STATE_ENDED;
+               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
+               BT_LOGD("Set new status: status=%s",
+                       bt_notification_iterator_status_string(status));
+               goto end;
+       case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
+               status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
+               goto end;
+       case BT_NOTIFICATION_ITERATOR_STATUS_OK:
+               BT_ASSERT_PRE(next_return.notification,
+                       "User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL: "
+                       "%!+i", iterator);
+               BT_ASSERT_PRE(validate_notification(iterator,
+                       next_return.notification),
+                       "Notification is invalid at this point: "
+                       "%![notif-iter-]+i, %![notif-]+n",
+                       iterator, next_return.notification);
+               bt_notification_iterator_replace_current_notification(
+                       (void *) iterator, next_return.notification);
+               bt_put(next_return.notification);
+               break;
+       default:
+               /* Unknown non-error status */
+               abort();
        }
 
 end:
@@ -2240,39 +759,23 @@ bt_notification_iterator_next(struct bt_notification_iterator *iterator)
 {
        enum bt_notification_iterator_status status;
 
-       if (!iterator) {
-               BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
-               status = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
-               goto end;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
        BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator);
+       BT_ASSERT(iterator->type == BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION ||
+               iterator->type == BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT);
 
        switch (iterator->type) {
        case BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION:
        {
                struct bt_notification_iterator_private_connection *priv_conn_iter =
                        (void *) iterator;
-               struct bt_notification *notif;
 
                /*
                 * Make sure that the iterator's queue contains at least
                 * one notification.
                 */
-               status = ensure_queue_has_notifications(priv_conn_iter);
-               if (status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               /*
-                * Move the notification at the tail of the queue to the
-                * iterator's current notification.
-                */
-               BT_ASSERT(priv_conn_iter->queue->length > 0);
-               notif = g_queue_pop_tail(priv_conn_iter->queue);
-               bt_notification_iterator_replace_current_notification(
-                       iterator, notif);
-               bt_put(notif);
+               status = bt_priv_conn_private_notification_iterator_next(
+                       priv_conn_iter);
                break;
        }
        case BT_NOTIFICATION_ITERATOR_TYPE_OUTPUT_PORT:
@@ -2298,8 +801,7 @@ bt_notification_iterator_next(struct bt_notification_iterator *iterator)
                bt_notification_iterator_replace_current_notification(
                        iterator, NULL);
                graph_status = bt_graph_consume_sink_no_check(
-                       out_port_iter->graph,
-                       out_port_iter->colander);
+                       out_port_iter->graph, out_port_iter->colander);
                switch (graph_status) {
                case BT_GRAPH_STATUS_CANCELED:
                        status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
@@ -2332,36 +834,24 @@ bt_notification_iterator_next(struct bt_notification_iterator *iterator)
                break;
        }
        default:
-               BT_LOGF("Unknown notification iterator type: addr=%p, type=%d",
-                       iterator, iterator->type);
                abort();
        }
 
-end:
        return status;
 }
 
 struct bt_component *bt_private_connection_notification_iterator_get_component(
                struct bt_notification_iterator *iterator)
 {
-       struct bt_component *comp = NULL;
        struct bt_notification_iterator_private_connection *iter_priv_conn;
 
-       if (!iterator) {
-               BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
-               goto end;
-       }
-
-       if (iterator->type != BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION) {
-               BT_LOGW_STR("Invalid parameter: notification iterator was not created from a private connection.");
-               goto end;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
+       BT_ASSERT_PRE(iterator->type ==
+               BT_NOTIFICATION_ITERATOR_TYPE_PRIVATE_CONNECTION,
+               "Notification iterator was not created from a private connection: "
+               "%!+i", iterator);
        iter_priv_conn = (void *) iterator;
-       comp = bt_get(iter_priv_conn->upstream_component);
-
-end:
-       return comp;
+       return bt_get(iter_priv_conn->upstream_component);
 }
 
 struct bt_private_component *
@@ -2392,8 +882,7 @@ void bt_output_port_notification_iterator_destroy(struct bt_object *obj)
 
 struct bt_notification_iterator *bt_output_port_notification_iterator_create(
                struct bt_port *output_port,
-               const char *colander_component_name,
-               const enum bt_notification_type *notification_types)
+               const char *colander_component_name)
 {
        struct bt_notification_iterator *iterator_base = NULL;
        struct bt_notification_iterator_output_port *iterator = NULL;
@@ -2406,24 +895,12 @@ struct bt_notification_iterator *bt_output_port_notification_iterator_create(
        struct bt_port *colander_in_port = NULL;
        struct bt_component_class_sink_colander_data colander_data;
 
-       if (!output_port) {
-               BT_LOGW_STR("Invalid parameter: port is NULL.");
-               goto error;
-       }
-
-       if (bt_port_get_type(output_port) != BT_PORT_TYPE_OUTPUT) {
-               BT_LOGW_STR("Invalid parameter: port is not an output port.");
-               goto error;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(output_port, "Output port");
+       BT_ASSERT_PRE(bt_port_get_type(output_port) == BT_PORT_TYPE_OUTPUT,
+               "Port is not an output port: %!+p", output_port);
        output_port_comp = bt_port_get_component(output_port);
-       if (!output_port_comp) {
-               BT_LOGW("Cannot get output port's component: "
-                       "port-addr=%p, port-name=\"%s\"",
-                       output_port, bt_port_get_name(output_port));
-               goto error;
-       }
-
+       BT_ASSERT_PRE(output_port_comp,
+               "Output port has no component: %!+p", output_port);
        graph = bt_component_get_graph(output_port_comp);
        BT_ASSERT(graph);
 
@@ -2454,7 +931,6 @@ struct bt_notification_iterator *bt_output_port_notification_iterator_create(
        colander_comp_name =
                colander_component_name ? colander_component_name : "colander";
        colander_data.notification = &iterator_base->current_notification;
-       colander_data.notification_types = notification_types;
        graph_status = bt_graph_add_component_with_init_method_data(
                iterator->graph, colander_comp_cls, colander_comp_name,
                NULL, &colander_data, &iterator->colander);
index 181625db16c880509a324e2315f30c09c6a86e86..0b5ec96e417a2b98c59f887d73b659f7caa2e59f 100644 (file)
@@ -154,7 +154,7 @@ int bt_notification_inactivity_set_clock_value(
 
        BT_ASSERT_PRE_NON_NULL(notification, "Notification");
        BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-       BT_ASSERT_PRE_HOT(notification, "notification",
+       BT_ASSERT_PRE_HOT(notification, "Notification",
                ": +%!+n", notification);
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notification,
                BT_NOTIFICATION_TYPE_INACTIVITY);
index 8d045fa5feceb3f0012f689ee53e8f2c37816628..57da6c333c3ae95c80d24babd2eec2bcff210ccf 100644 (file)
 #include <babeltrace/assert-internal.h>
 #include <babeltrace/assert-pre-internal.h>
 
+BT_ASSERT_PRE_FUNC
+static inline void _init_seq_num(struct bt_notification *notification)
+{
+       notification->seq_num = -1ULL;
+}
+
+#ifdef BT_DEV_MODE
+# define init_seq_num  _init_seq_num
+#else
+# define init_seq_num(_notif)
+#endif /* BT_DEV_MODE */
+
 BT_HIDDEN
 void bt_notification_init(struct bt_notification *notification,
                enum bt_notification_type type,
                bt_object_release_func release)
 {
-       BT_ASSERT(type > BT_NOTIFICATION_TYPE_ALL &&
-                       type < BT_NOTIFICATION_TYPE_NR);
+       BT_ASSERT(type >= 0 && type < BT_NOTIFICATION_TYPE_NR);
        notification->type = type;
+       init_seq_num(notification);
        bt_object_init(&notification->base, release);
 }
 
index 1f3587d75ae67c79a964145379bf5a8a61ca1085..e596b532666e2c0ddd696a8da45256910b037ad6 100644 (file)
@@ -78,6 +78,7 @@ enum state {
        STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN,
        STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
        STATE_AFTER_STREAM_PACKET_CONTEXT,
+       STATE_EMIT_NOTIF_NEW_STREAM,
        STATE_EMIT_NOTIF_NEW_PACKET,
        STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN,
        STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
@@ -90,6 +91,7 @@ enum state {
        STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
        STATE_EMIT_NOTIF_EVENT,
        STATE_EMIT_NOTIF_END_OF_PACKET,
+       STATE_DONE,
        STATE_SKIP_PACKET_PADDING,
 };
 
@@ -214,6 +216,9 @@ struct bt_notif_iter {
                void *data;
        } medium;
 
+       /* Stream beginning was emitted */
+       bool stream_begin_emitted;
+
        /* Current packet size (bits) (-1 if unknown) */
        int64_t cur_packet_size;
 
@@ -265,6 +270,8 @@ const char *state_string(enum state state)
                return "STATE_AFTER_STREAM_PACKET_CONTEXT";
        case STATE_EMIT_NOTIF_NEW_PACKET:
                return "STATE_EMIT_NOTIF_NEW_PACKET";
+       case STATE_EMIT_NOTIF_NEW_STREAM:
+               return "STATE_EMIT_NOTIF_NEW_STREAM";
        case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
                return "STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN";
        case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
@@ -287,6 +294,8 @@ const char *state_string(enum state state)
                return "STATE_EMIT_NOTIF_EVENT";
        case STATE_EMIT_NOTIF_END_OF_PACKET:
                return "STATE_EMIT_NOTIF_END_OF_PACKET";
+       case STATE_DONE:
+               return "STATE_DONE";
        case STATE_SKIP_PACKET_PADDING:
                return "STATE_SKIP_PACKET_PADDING";
        default:
@@ -1170,7 +1179,11 @@ enum bt_notif_iter_status after_packet_context_state(
 
        status = set_current_packet_content_sizes(notit);
        if (status == BT_NOTIF_ITER_STATUS_OK) {
-               notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
+               if (notit->stream_begin_emitted) {
+                       notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
+               } else {
+                       notit->state = STATE_EMIT_NOTIF_NEW_STREAM;
+               }
        }
 
        return status;
@@ -1647,6 +1660,9 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit)
        case STATE_AFTER_STREAM_PACKET_CONTEXT:
                status = after_packet_context_state(notit);
                break;
+       case STATE_EMIT_NOTIF_NEW_STREAM:
+               notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
+               break;
        case STATE_EMIT_NOTIF_NEW_PACKET:
                notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
                break;
@@ -1702,7 +1718,7 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit)
 /**
  * Resets the internal state of a CTF notification iterator.
  */
-static
+BT_HIDDEN
 void bt_notif_iter_reset(struct bt_notif_iter *notit)
 {
        BT_ASSERT(notit);
@@ -1722,6 +1738,7 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit)
        notit->cur_content_size = -1;
        notit->cur_packet_size = -1;
        notit->cur_packet_offset = -1;
+       notit->stream_begin_emitted = false;
 }
 
 static
@@ -1795,9 +1812,14 @@ struct bt_field *get_next_field(struct bt_notif_iter *notit)
 
        switch (bt_field_type_get_type_id(base_type)) {
        case BT_FIELD_TYPE_ID_STRUCT:
+       {
                next_field = bt_field_structure_get_field_by_index(
                        base_field, index);
+               const char *name;
+               bt_field_type_structure_get_field_by_index(base_type,
+                       &name, NULL, index);
                break;
+       }
        case BT_FIELD_TYPE_ID_ARRAY:
                next_field = bt_field_array_get_field(base_field, index);
                break;
@@ -2774,13 +2796,6 @@ void create_packet(struct bt_notif_iter *notit)
 
        BT_LOGV("Creating packet for packet notification: "
                "notit-addr=%p", notit);
-
-       /* Ask the user for the stream */
-       ret = set_stream(notit);
-       if (ret) {
-               goto error;
-       }
-
        BT_LOGV("Creating packet from stream: "
                "notit-addr=%p, stream-addr=%p, "
                "stream-class-addr=%p, "
@@ -2791,6 +2806,7 @@ void create_packet(struct bt_notif_iter *notit)
                bt_stream_class_get_id(notit->meta.stream_class));
 
        /* Create packet */
+       BT_ASSERT(notit->stream);
        packet = bt_packet_create(notit->stream);
        if (!packet) {
                BT_LOGE("Cannot create packet from stream: "
@@ -2852,6 +2868,54 @@ end:
        BT_MOVE(notit->packet, packet);
 }
 
+static
+void notify_new_stream(struct bt_notif_iter *notit,
+               struct bt_notification **notification)
+{
+       struct bt_notification *ret = NULL;
+       int iret;
+
+       /* Ask the user for the stream */
+       iret = set_stream(notit);
+       if (iret) {
+               goto end;
+       }
+
+       BT_ASSERT(notit->stream);
+       ret = bt_notification_stream_begin_create(notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream beginning notification: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+end:
+       *notification = ret;
+}
+
+static
+void notify_end_of_stream(struct bt_notif_iter *notit,
+               struct bt_notification **notification)
+{
+       struct bt_notification *ret;
+
+       if (!notit->stream) {
+               BT_LOGE("Cannot create stream for stream notification: "
+                       "notit-addr=%p", notit);
+               return;
+       }
+
+       ret = bt_notification_stream_end_create(notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream beginning notification: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+       *notification = ret;
+}
+
 static
 void notify_new_packet(struct bt_notif_iter *notit,
                struct bt_notification **notification)
@@ -3118,6 +3182,11 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
        BT_ASSERT(notit);
        BT_ASSERT(notification);
 
+       if (notit->state == STATE_DONE) {
+               status = BT_NOTIF_ITER_STATUS_EOF;
+               goto end;
+       }
+
        BT_LOGV("Getting next notification: notit-addr=%p, cc-prio-map-addr=%p",
                notit, cc_prio_map);
 
@@ -3129,7 +3198,25 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                }
                if (status != BT_NOTIF_ITER_STATUS_OK) {
                        if (status == BT_NOTIF_ITER_STATUS_EOF) {
+                               enum state next_state = notit->state;
+
                                BT_LOGV_STR("Medium returned BT_NOTIF_ITER_STATUS_EOF.");
+
+                               if (notit->packet) {
+                                       notify_end_of_packet(notit, notification);
+                               } else {
+                                       notify_end_of_stream(notit, notification);
+                                       next_state = STATE_DONE;
+                               }
+
+                               if (!*notification) {
+                                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                                       goto end;
+                               }
+
+                               status = BT_NOTIF_ITER_STATUS_OK;
+                               notit->state = next_state;
+                               goto end;
                        } else {
                                BT_LOGW("Cannot handle state: "
                                        "notit-addr=%p, state=%s",
@@ -3139,6 +3226,14 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                }
 
                switch (notit->state) {
+               case STATE_EMIT_NOTIF_NEW_STREAM:
+                       /* notify_new_stream() logs errors */
+                       notify_new_stream(notit, notification);
+                       if (!*notification) {
+                               status = BT_NOTIF_ITER_STATUS_ERROR;
+                       }
+                       notit->stream_begin_emitted = true;
+                       goto end;
                case STATE_EMIT_NOTIF_NEW_PACKET:
                        /* notify_new_packet() logs errors */
                        notify_new_packet(notit, notification);
@@ -3230,6 +3325,7 @@ enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields(
                         */
                        goto set_fields;
                case STATE_INIT:
+               case STATE_EMIT_NOTIF_NEW_STREAM:
                case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
                case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
                case STATE_AFTER_TRACE_PACKET_HEADER:
index ff70730900bf66c78f374a4aaa48a8fed75962dc..640bcf94855bab67c9fccd2f1084261433c3f618 100644 (file)
@@ -355,6 +355,15 @@ BT_HIDDEN
 off_t bt_notif_iter_get_current_packet_size(
                struct bt_notif_iter *notit);
 
+/*
+ * Resets the iterator so that the next requested medium bytes are
+ * assumed to be the first bytes of a new stream. The first notification
+ * which this iterator emits after calling bt_notif_iter_reset() is a
+ * BT_NOTIFICATION_TYPE_STREAM_BEGIN one.
+ */
+BT_HIDDEN
+void bt_notif_iter_reset(struct bt_notif_iter *notit);
+
 static inline
 const char *bt_notif_iter_medium_status_string(
                enum bt_notif_iter_medium_status status)
index 1ef26ddc4b3f887a0eb5d573dfa1beb4bc8fc6e8..ccfa6f26fc03bd0552b067956212d5cf9567f1c9 100644 (file)
@@ -191,7 +191,7 @@ enum bt_component_status handle_notification(
                break;
        }
        default:
-               puts("Unhandled notification type");
+               break;
        }
 end:
        return ret;
@@ -206,14 +206,6 @@ void writer_component_port_connected(
        struct bt_private_connection *connection;
        struct writer_component *writer;
        enum bt_connection_status conn_status;
-       static const enum bt_notification_type notif_types[] = {
-               BT_NOTIFICATION_TYPE_EVENT,
-               BT_NOTIFICATION_TYPE_PACKET_BEGIN,
-               BT_NOTIFICATION_TYPE_PACKET_END,
-               BT_NOTIFICATION_TYPE_STREAM_BEGIN,
-               BT_NOTIFICATION_TYPE_STREAM_END,
-               BT_NOTIFICATION_TYPE_SENTINEL,
-       };
 
        writer = bt_private_component_get_user_data(component);
        BT_ASSERT(writer);
@@ -221,7 +213,7 @@ void writer_component_port_connected(
        connection = bt_private_port_get_private_connection(self_port);
        BT_ASSERT(connection);
        conn_status = bt_private_connection_create_notification_iterator(
-               connection, notif_types, &writer->input_iterator);
+               connection, &writer->input_iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                writer->error = true;
        }
index 74e9b52aaf9fe04d7418bb6e40e0f3358642fd40..8395c81b0225eca494fac4a5e9d5f2e3e3757c95 100644 (file)
@@ -96,19 +96,52 @@ struct bt_notification_iterator_next_method_return ctf_fs_iterator_next(
 
        BT_ASSERT(notif_iter_data->ds_file);
        next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
-       if (next_ret.status == BT_NOTIFICATION_ITERATOR_STATUS_END) {
-               BT_ASSERT(!next_ret.notification);
+
+       if (next_ret.status == BT_NOTIFICATION_ITERATOR_STATUS_OK &&
+                       bt_notification_get_type(next_ret.notification) ==
+                       BT_NOTIFICATION_TYPE_STREAM_BEGIN) {
+               if (notif_iter_data->skip_stream_begin_notifs) {
+                       /*
+                        * We already emitted a
+                        * BT_NOTIFICATION_TYPE_STREAM_BEGIN
+                        * notification: skip this one, get a new one.
+                        */
+                       BT_PUT(next_ret.notification);
+                       next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
+                       BT_ASSERT(next_ret.status != BT_NOTIFICATION_ITERATOR_STATUS_END);
+                       goto end;
+               } else {
+                       /*
+                        * First BT_NOTIFICATION_TYPE_STREAM_BEGIN
+                        * notification: skip all following.
+                        */
+                       notif_iter_data->skip_stream_begin_notifs = true;
+                       goto end;
+               }
+       }
+
+       if (next_ret.status == BT_NOTIFICATION_ITERATOR_STATUS_OK &&
+                       bt_notification_get_type(next_ret.notification) ==
+                       BT_NOTIFICATION_TYPE_STREAM_END) {
                notif_iter_data->ds_file_info_index++;
 
                if (notif_iter_data->ds_file_info_index ==
                                notif_iter_data->ds_file_group->ds_file_infos->len) {
                        /*
                         * No more stream files to read: we reached the
-                        * real end.
+                        * real end. Emit this
+                        * BT_NOTIFICATION_TYPE_STREAM_END notification.
+                        * The next time ctf_fs_iterator_next() is
+                        * called for this notification iterator,
+                        * ctf_fs_ds_file_next() will return
+                        * BT_NOTIFICATION_ITERATOR_STATUS_END().
                         */
                        goto end;
                }
 
+               BT_PUT(next_ret.notification);
+               bt_notif_iter_reset(notif_iter_data->notif_iter);
+
                /*
                 * Open and start reading the next stream file within
                 * our stream file group.
@@ -122,14 +155,30 @@ struct bt_notification_iterator_next_method_return ctf_fs_iterator_next(
                next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
 
                /*
-                * We should not get BT_NOTIFICATION_ITERATOR_STATUS_END
-                * with a brand new stream file because empty stream
-                * files are not even part of stream file groups, which
-                * means we're sure to get at least one pair of "packet
-                * begin" and "packet end" notifications in the case of
-                * a single, empty packet.
+                * If we get a notification, we expect to get a
+                * BT_NOTIFICATION_TYPE_STREAM_BEGIN notification
+                * because the iterator's state machine emits one before
+                * even requesting the first block of data from the
+                * medium. Skip this notification because we're not
+                * really starting a new stream here, and try getting a
+                * new notification (which, if it works, is a
+                * BT_NOTIFICATION_TYPE_PACKET_BEGIN one). We're sure to
+                * get at least one pair of
+                * BT_NOTIFICATION_TYPE_PACKET_BEGIN and
+                * BT_NOTIFICATION_TYPE_PACKET_END notifications in the
+                * case of a single, empty packet. We know there's at
+                * least one packet because the stream file group does
+                * not contain empty stream files.
                 */
-               BT_ASSERT(next_ret.status != BT_NOTIFICATION_ITERATOR_STATUS_END);
+               BT_ASSERT(notif_iter_data->skip_stream_begin_notifs);
+
+               if (next_ret.status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
+                       BT_ASSERT(bt_notification_get_type(next_ret.notification) ==
+                               BT_NOTIFICATION_TYPE_STREAM_BEGIN);
+                       BT_PUT(next_ret.notification);
+                       next_ret = ctf_fs_ds_file_next(notif_iter_data->ds_file);
+                       BT_ASSERT(next_ret.status != BT_NOTIFICATION_ITERATOR_STATUS_END);
+               }
        }
 
 end:
index bbac1bb4d96daf7ee4fcbf286b702ed118c26141..d8fc7f43ee626fc0504e6df8b371ec78733a8c44 100644 (file)
@@ -131,6 +131,9 @@ struct ctf_fs_notif_iter_data {
 
        /* Owned by this */
        struct bt_notif_iter *notif_iter;
+
+       /* True to skip BT_NOTIFICATION_TYPE_STREAM_BEGIN notifications */
+       bool skip_stream_begin_notifs;
 };
 
 BT_HIDDEN
index 6a4841e342e0929020b944625adac9693444728a..0646f49ab248fe232eef889f6583cf50a143defd 100644 (file)
@@ -300,7 +300,7 @@ enum bt_notification_iterator_status debug_info_iterator_init(
        }
 
        conn_status = bt_private_connection_create_notification_iterator(
-                       connection, NULL, &it_data->input_iterator);
+                       connection, &it_data->input_iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
                goto end;
index 77d982ef153a0787d901bc65929aba1f915f9a73..8b5ecd2c63a14bbd1681da21bde951c338b763f1 100644 (file)
@@ -140,17 +140,12 @@ enum bt_component_status handle_notification(struct pretty_component *pretty,
        case BT_NOTIFICATION_TYPE_INACTIVITY:
                fprintf(stderr, "Inactivity notification\n");
                break;
-       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-       case BT_NOTIFICATION_TYPE_PACKET_END:
-       case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-       case BT_NOTIFICATION_TYPE_STREAM_END:
-               break;
        case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
        case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
                ret = pretty_print_discarded_elements(pretty, notification);
                break;
        default:
-               fprintf(stderr, "Unhandled notification type\n");
+               break;
        }
 
        return ret;
@@ -165,12 +160,6 @@ void pretty_port_connected(
        enum bt_connection_status conn_status;
        struct bt_private_connection *connection;
        struct pretty_component *pretty;
-       static const enum bt_notification_type notif_types[] = {
-               BT_NOTIFICATION_TYPE_EVENT,
-               BT_NOTIFICATION_TYPE_DISCARDED_PACKETS,
-               BT_NOTIFICATION_TYPE_DISCARDED_EVENTS,
-               BT_NOTIFICATION_TYPE_SENTINEL,
-       };
 
        pretty = bt_private_component_get_user_data(component);
        BT_ASSERT(pretty);
@@ -178,7 +167,7 @@ void pretty_port_connected(
        connection = bt_private_port_get_private_connection(self_port);
        BT_ASSERT(connection);
        conn_status = bt_private_connection_create_notification_iterator(
-               connection, notif_types, &pretty->input_iterator);
+               connection, &pretty->input_iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                pretty->error = true;
        }
index 406a76ee6326ba991626a6e40a92945ec2e8a4b8..f3e61e6dc3f40a9c4452f9267660fa96b1b93beb 100644 (file)
@@ -199,7 +199,7 @@ void counter_port_connected(
        connection = bt_private_port_get_private_connection(self_port);
        BT_ASSERT(connection);
        conn_status = bt_private_connection_create_notification_iterator(
-               connection, NULL, &iterator);
+               connection, &iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                counter->error = true;
                goto end;
index ad48e6985dd1c19968a7845b0c1f2d99b50d1b58..0535b95806cf4762b6159f00deaaeb76631c08a9 100644 (file)
@@ -88,7 +88,7 @@ void dummy_port_connected(
        connection = bt_private_port_get_private_connection(self_port);
        BT_ASSERT(connection);
        conn_status = bt_private_connection_create_notification_iterator(
-               connection, NULL, &iterator);
+               connection, &iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                dummy->error = true;
                goto end;
index a13de5303c3bc076b39ec4bfc73ef3454e5b8292..aae41f613925ad66164d4464f841e40567d5bffc 100644 (file)
@@ -423,7 +423,7 @@ struct bt_notification_iterator *create_notif_iter_on_input_port(
        //       returned notification by the muxer notification
        //       iterator which creates it.
        conn_status = bt_private_connection_create_notification_iterator(
-               priv_conn, NULL, &notif_iter);
+               priv_conn, &notif_iter);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                BT_LOGE("Cannot create upstream notification iterator on input port's connection: "
                        "port-addr=%p, port-name=\"%s\", conn-addr=%p, "
index 8a081bce096d793ddacd5808e1e44d5f7ff1f4df..a70fd8a16cfd5a7f46f7475956cd339f8d45a280 100644 (file)
@@ -77,13 +77,6 @@ enum bt_notification_iterator_status trimmer_iterator_init(
        struct bt_private_component *component =
                bt_private_connection_private_notification_iterator_get_private_component(iterator);
        struct trimmer_iterator *it_data = g_new0(struct trimmer_iterator, 1);
-       static const enum bt_notification_type notif_types[] = {
-               BT_NOTIFICATION_TYPE_EVENT,
-               BT_NOTIFICATION_TYPE_STREAM_END,
-               BT_NOTIFICATION_TYPE_PACKET_BEGIN,
-               BT_NOTIFICATION_TYPE_PACKET_END,
-               BT_NOTIFICATION_TYPE_SENTINEL,
-       };
 
        if (!it_data) {
                ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
@@ -98,7 +91,7 @@ enum bt_notification_iterator_status trimmer_iterator_init(
        BT_ASSERT(connection);
 
        conn_status = bt_private_connection_create_notification_iterator(connection,
-                       notif_types, &it_data->input_iterator);
+                       &it_data->input_iterator);
        if (conn_status != BT_CONNECTION_STATUS_OK) {
                ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
                goto end;
@@ -550,7 +543,6 @@ enum bt_notification_iterator_status evaluate_notification(
                                trim_it);
                break;
        default:
-               puts("Unhandled notification type");
                break;
        }
        BT_PUT(*notification);
index d4767b1b93f5e7b0401777079756373480e615c0..531ddf680464a4aa3ab6b4173ff52956bd275bdd 100644 (file)
@@ -45,8 +45,7 @@ void bt_notification_init(struct bt_notification *notification,
                enum bt_notification_type type,
                bt_object_release_func release)
 {
-       assert(type > BT_NOTIFICATION_TYPE_ALL &&
-                       type < BT_NOTIFICATION_TYPE_NR);
+       assert(type > 0 && type < BT_NOTIFICATION_TYPE_NR);
        notification->type = type;
        bt_object_init(&notification->base, release);
 }
index 90f4dff35f5bc3aefc2e765629e2c16ca9ff4558..cb91ac51b0d74991d9cc2ceec2de72c83ae17e3c 100644 (file)
 
 #include "tap/tap.h"
 
-#define NR_TESTS       31
+#define NR_TESTS       6
 
 enum test {
        TEST_NO_AUTO_NOTIFS,
-       TEST_AUTO_STREAM_BEGIN_FROM_PACKET_BEGIN,
-       TEST_AUTO_STREAM_BEGIN_FROM_STREAM_END,
-       TEST_AUTO_STREAM_END_FROM_END,
-       TEST_AUTO_PACKET_BEGIN_FROM_PACKET_END,
-       TEST_AUTO_PACKET_BEGIN_FROM_EVENT,
-       TEST_AUTO_PACKET_END_FROM_PACKET_BEGIN,
-       TEST_AUTO_PACKET_END_PACKET_BEGIN_FROM_EVENT,
-       TEST_AUTO_PACKET_END_FROM_STREAM_END,
-       TEST_AUTO_PACKET_END_STREAM_END_FROM_END,
-       TEST_MULTIPLE_AUTO_STREAM_END_FROM_END,
-       TEST_MULTIPLE_AUTO_PACKET_END_STREAM_END_FROM_END,
        TEST_OUTPUT_PORT_NOTIFICATION_ITERATOR,
 };
 
@@ -162,111 +151,6 @@ static int64_t seq_no_auto_notifs[] = {
        SEQ_END,
 };
 
-/* Automatic "stream begin" from "packet begin" */
-static int64_t seq_auto_stream_begin_from_packet_begin[] = {
-       /* Automatic "stream begin" here */
-       SEQ_STREAM1_PACKET1_BEGIN,
-       SEQ_STREAM1_PACKET1_END,
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "stream begin" from "stream end" */
-static int64_t seq_auto_stream_begin_from_stream_end[] = {
-       /* Automatic "stream begin" here */
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "stream end" from END */
-static int64_t seq_auto_stream_end_from_end[] = {
-       SEQ_STREAM1_BEGIN,
-       /* Automatic "packet end" here */
-       SEQ_END,
-};
-
-/* Automatic "packet begin" from "packet end" */
-static int64_t seq_auto_packet_begin_from_packet_end[] = {
-       SEQ_STREAM1_BEGIN,
-       /* Automatic "packet begin" here */
-       SEQ_STREAM1_PACKET1_END,
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "packet begin" from event */
-static int64_t seq_auto_packet_begin_from_event[] = {
-       SEQ_STREAM1_BEGIN,
-       /* Automatic "packet begin" here */
-       SEQ_EVENT_STREAM1_PACKET1,
-       SEQ_STREAM1_PACKET1_END,
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "packet end" from "packet begin" */
-static int64_t seq_auto_packet_end_from_packet_begin[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM1_PACKET1_BEGIN,
-       /* Automatic "packet end" here */
-       SEQ_STREAM1_PACKET2_BEGIN,
-       SEQ_STREAM1_PACKET2_END,
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "packet end" and "packet begin" from event */
-static int64_t seq_auto_packet_end_packet_begin_from_event[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM1_PACKET1_BEGIN,
-       /* Automatic "packet end" here */
-       /* Automatic "packet begin" here */
-       SEQ_EVENT_STREAM1_PACKET2,
-       SEQ_STREAM1_PACKET2_END,
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "packet end" from "stream end" */
-static int64_t seq_auto_packet_end_from_stream_end[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM1_PACKET1_BEGIN,
-       /* Automatic "packet end" here */
-       SEQ_STREAM1_END,
-       SEQ_END,
-};
-
-/* Automatic "packet end" and "stream end" from END */
-static int64_t seq_auto_packet_end_stream_end_from_end[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM1_PACKET1_BEGIN,
-       /* Automatic "packet end" here */
-       /* Automatic "stream end" here */
-       SEQ_END,
-};
-
-/* Multiple automatic "stream end" from END */
-static int64_t seq_multiple_auto_stream_end_from_end[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM2_BEGIN,
-       /* Automatic "stream end" here */
-       /* Automatic "stream end" here */
-       SEQ_END,
-};
-
-/* Multiple automatic "packet end" and "stream end" from END */
-static int64_t seq_multiple_auto_packet_end_stream_end_from_end[] = {
-       SEQ_STREAM1_BEGIN,
-       SEQ_STREAM2_BEGIN,
-       SEQ_STREAM1_PACKET1_BEGIN,
-       SEQ_STREAM2_PACKET1_BEGIN,
-       /* Automatic "packet end" here */
-       /* Automatic "stream end" here */
-       /* Automatic "packet end" here */
-       /* Automatic "stream end" here */
-       SEQ_END,
-};
-
 static
 void clear_test_events(void)
 {
@@ -510,39 +394,6 @@ enum bt_notification_iterator_status src_iter_init(
        case TEST_OUTPUT_PORT_NOTIFICATION_ITERATOR:
                user_data->seq = seq_no_auto_notifs;
                break;
-       case TEST_AUTO_STREAM_BEGIN_FROM_PACKET_BEGIN:
-               user_data->seq = seq_auto_stream_begin_from_packet_begin;
-               break;
-       case TEST_AUTO_STREAM_BEGIN_FROM_STREAM_END:
-               user_data->seq = seq_auto_stream_begin_from_stream_end;
-               break;
-       case TEST_AUTO_STREAM_END_FROM_END:
-               user_data->seq = seq_auto_stream_end_from_end;
-               break;
-       case TEST_AUTO_PACKET_BEGIN_FROM_PACKET_END:
-               user_data->seq = seq_auto_packet_begin_from_packet_end;
-               break;
-       case TEST_AUTO_PACKET_BEGIN_FROM_EVENT:
-               user_data->seq = seq_auto_packet_begin_from_event;
-               break;
-       case TEST_AUTO_PACKET_END_FROM_PACKET_BEGIN:
-               user_data->seq = seq_auto_packet_end_from_packet_begin;
-               break;
-       case TEST_AUTO_PACKET_END_PACKET_BEGIN_FROM_EVENT:
-               user_data->seq = seq_auto_packet_end_packet_begin_from_event;
-               break;
-       case TEST_AUTO_PACKET_END_FROM_STREAM_END:
-               user_data->seq = seq_auto_packet_end_from_stream_end;
-               break;
-       case TEST_AUTO_PACKET_END_STREAM_END_FROM_END:
-               user_data->seq = seq_auto_packet_end_stream_end_from_end;
-               break;
-       case TEST_MULTIPLE_AUTO_STREAM_END_FROM_END:
-               user_data->seq = seq_multiple_auto_stream_end_from_end;
-               break;
-       case TEST_MULTIPLE_AUTO_PACKET_END_STREAM_END_FROM_END:
-               user_data->seq = seq_multiple_auto_packet_end_stream_end_from_end;
-               break;
        default:
                abort();
        }
@@ -853,7 +704,7 @@ void sink_port_connected(struct bt_private_component *private_component,
        assert(user_data);
        assert(priv_conn);
        conn_status = bt_private_connection_create_notification_iterator(
-               priv_conn, NULL, &user_data->notif_iter);
+               priv_conn, &user_data->notif_iter);
        assert(conn_status == 0);
        bt_put(priv_conn);
 }
@@ -1014,327 +865,6 @@ void test_no_auto_notifs(void)
                expected_test_events);
 }
 
-static
-void test_auto_stream_begin_from_packet_begin(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_STREAM_BEGIN_FROM_PACKET_BEGIN,
-               "automatic \"stream begin\" notif. caused by \"packet begin\" notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_stream_begin_from_stream_end(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_STREAM_BEGIN_FROM_STREAM_END,
-               "automatic \"stream begin\" notif. caused by \"stream end\" notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_stream_end_from_end(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_STREAM_END_FROM_END,
-               "automatic \"stream end\" notif. caused by BT_NOTIFICATION_ITERATOR_STATUS_END",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_begin_from_packet_end(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_BEGIN_FROM_PACKET_END,
-               "automatic \"packet begin\" notif. caused by \"packet end\" notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_begin_from_event(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_BEGIN_FROM_EVENT,
-               "automatic \"packet begin\" notif. caused by event notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_end_from_packet_begin(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_END_FROM_PACKET_BEGIN,
-               "automatic \"packet end\" notif. caused by \"packet begin\" notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_end_packet_begin_from_event(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_END_PACKET_BEGIN_FROM_EVENT,
-               "automatic \"packet end\" and \"packet begin\" notifs. caused by event notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_end_from_stream_end(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_END_FROM_STREAM_END,
-               "automatic \"packet end\" notif. caused by \"stream end\" notif.",
-               expected_test_events);
-}
-
-static
-void test_auto_packet_end_stream_end_from_end(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, .stream = src_stream1, .packet = NULL, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_AUTO_PACKET_END_STREAM_END_FROM_END,
-               "automatic \"packet end\" and \"stream end\" notifs. caused by BT_NOTIFICATION_ITERATOR_STATUS_END",
-               expected_test_events);
-}
-
-static
-void test_multiple_auto_stream_end_from_end(void)
-{
-       bool expected = true;
-       struct test_event expected_event;
-       struct test_event expected_event2;
-       struct test_event *event;
-       struct test_event *event2;
-
-       do_std_test(TEST_MULTIPLE_AUTO_STREAM_END_FROM_END,
-               "multiple automatic \"stream end\" notifs. caused by BT_NOTIFICATION_ITERATOR_STATUS_END",
-               NULL);
-
-       if (test_events->len != 5) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
-       expected_event.stream = src_stream1;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 0);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
-       expected_event.stream = src_stream2;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 1);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_END;
-       expected_event.stream = src_stream1;
-       expected_event.packet = NULL;
-       expected_event2.type = TEST_EV_TYPE_NOTIF_STREAM_END;
-       expected_event2.stream = src_stream2;
-       expected_event2.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 2);
-       event2 = &g_array_index(test_events, struct test_event, 3);
-       if (!(compare_single_test_events(event, &expected_event) &&
-                       compare_single_test_events(event2, &expected_event2)) &&
-                       !(compare_single_test_events(event2, &expected_event) &&
-                       compare_single_test_events(event, &expected_event2))) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_END;
-       expected_event.stream = NULL;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 4);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-end:
-       ok(expected,
-               "the produced sequence of test events is the expected one");
-}
-
-static
-void test_multiple_auto_packet_end_stream_end_from_end(void)
-{
-       bool expected = true;
-       struct test_event expected_event;
-       struct test_event expected_event2;
-       struct test_event *event;
-       struct test_event *event2;
-
-       do_std_test(TEST_MULTIPLE_AUTO_PACKET_END_STREAM_END_FROM_END,
-               "multiple automatic \"packet end\" and \"stream end\" notifs. caused by BT_NOTIFICATION_ITERATOR_STATUS_END",
-               NULL);
-
-       if (test_events->len != 9) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
-       expected_event.stream = src_stream1;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 0);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
-       expected_event.stream = src_stream2;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 1);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN;
-       expected_event.stream = src_stream1;
-       expected_event.packet = src_stream1_packet1;
-       event = &g_array_index(test_events, struct test_event, 2);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN;
-       expected_event.stream = src_stream2;
-       expected_event.packet = src_stream2_packet1;
-       event = &g_array_index(test_events, struct test_event, 3);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_PACKET_END;
-       expected_event.stream = src_stream1;
-       expected_event.packet = src_stream1_packet1;
-       expected_event2.type = TEST_EV_TYPE_NOTIF_PACKET_END;
-       expected_event2.stream = src_stream2;
-       expected_event2.packet = src_stream2_packet1;
-       event = &g_array_index(test_events, struct test_event, 4);
-       event2 = &g_array_index(test_events, struct test_event, 6);
-       if (!(compare_single_test_events(event, &expected_event) &&
-                       compare_single_test_events(event2, &expected_event2)) &&
-                       !(compare_single_test_events(event2, &expected_event) &&
-                       compare_single_test_events(event, &expected_event2))) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_NOTIF_STREAM_END;
-       expected_event.stream = src_stream1;
-       expected_event.packet = NULL;
-       expected_event2.type = TEST_EV_TYPE_NOTIF_STREAM_END;
-       expected_event2.stream = src_stream2;
-       expected_event2.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 5);
-       event2 = &g_array_index(test_events, struct test_event, 7);
-       if (!(compare_single_test_events(event, &expected_event) &&
-                       compare_single_test_events(event2, &expected_event2)) &&
-                       !(compare_single_test_events(event2, &expected_event) &&
-                       compare_single_test_events(event, &expected_event2))) {
-               expected = false;
-               goto end;
-       }
-
-       expected_event.type = TEST_EV_TYPE_END;
-       expected_event.stream = NULL;
-       expected_event.packet = NULL;
-       event = &g_array_index(test_events, struct test_event, 8);
-       if (!compare_single_test_events(event, &expected_event)) {
-               expected = false;
-               goto end;
-       }
-
-end:
-       ok(expected,
-               "the produced sequence of test events is the expected one");
-}
-
 static
 void test_output_port_notification_iterator(void)
 {
@@ -1375,62 +905,7 @@ void test_output_port_notification_iterator(void)
        /* Create notification iterator on source's output port */
        upstream_port = bt_component_source_get_output_port_by_name(src_comp, "out");
        notif_iter = bt_output_port_notification_iterator_create(upstream_port,
-               NULL, NULL);
-       ok(notif_iter, "bt_output_port_notification_iterator_create() succeeds");
-       bt_put(upstream_port);
-
-       /* Consume the notification iterator */
-       while (iter_status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
-               iter_status = common_consume(notif_iter);
-       }
-
-       ok(iter_status == BT_NOTIFICATION_ITERATOR_STATUS_END,
-               "output port notification iterator finishes without any error");
-
-       /* Compare the resulting test events */
-       ok(compare_test_events(expected_test_events),
-               "the produced sequence of test events is the expected one");
-
-       bt_put(src_comp);
-       bt_put(graph);
-       bt_put(notif_iter);
-}
-
-static
-void test_output_port_notification_iterator_subscribe_events(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream2, .packet = src_stream2_packet2, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .stream = src_stream1, .packet = src_stream1_packet2, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-       const enum bt_notification_type notification_types[] = {
-               BT_NOTIFICATION_TYPE_EVENT,
-               BT_NOTIFICATION_TYPE_SENTINEL,
-       };
-       struct bt_component *src_comp;
-       struct bt_notification_iterator *notif_iter;
-       enum bt_notification_iterator_status iter_status =
-               BT_NOTIFICATION_ITERATOR_STATUS_OK;
-       struct bt_port *upstream_port;
-       struct bt_graph *graph;
-
-       clear_test_events();
-       current_test = TEST_OUTPUT_PORT_NOTIFICATION_ITERATOR;
-       diag("test: output port notification iterator with event subscription");
-       graph = bt_graph_create();
-       assert(graph);
-       create_source_sink(graph, &src_comp, NULL);
-
-       /* Create notification iterator on source's output port */
-       upstream_port = bt_component_source_get_output_port_by_name(src_comp, "out");
-       notif_iter = bt_output_port_notification_iterator_create(upstream_port,
-               NULL, notification_types);
+               NULL);
        ok(notif_iter, "bt_output_port_notification_iterator_create() succeeds");
        bt_put(upstream_port);
 
@@ -1469,7 +944,7 @@ void test_output_port_notification_iterator_cannot_consume(void)
        /* Create notification iterator on source's output port */
        upstream_port = bt_component_source_get_output_port_by_name(src_comp, "out");
        notif_iter = bt_output_port_notification_iterator_create(upstream_port,
-               NULL, NULL);
+               NULL);
        assert(notif_iter);
        bt_put(upstream_port);
 
@@ -1496,19 +971,7 @@ int main(int argc, char **argv)
        plan_tests(NR_TESTS);
        init_static_data();
        test_no_auto_notifs();
-       test_auto_stream_begin_from_packet_begin();
-       test_auto_stream_begin_from_stream_end();
-       test_auto_stream_end_from_end();
-       test_auto_packet_begin_from_packet_end();
-       test_auto_packet_begin_from_event();
-       test_auto_packet_end_from_packet_begin();
-       test_auto_packet_end_packet_begin_from_event();
-       test_auto_packet_end_from_stream_end();
-       test_auto_packet_end_stream_end_from_end();
-       test_multiple_auto_stream_end_from_end();
-       test_multiple_auto_packet_end_stream_end_from_end();
        test_output_port_notification_iterator();
-       test_output_port_notification_iterator_subscribe_events();
        test_output_port_notification_iterator_cannot_consume();
        fini_static_data();
        return exit_status();
index 292ee0fec6f4bc8432b985c4017438114ecc00d2..f652fa99d6ab79234579fa6b6de8f9d1f29011a9 100644 (file)
@@ -87,6 +87,8 @@ enum {
        SEQ_AGAIN = -2,
        SEQ_PACKET_BEGIN = -3,
        SEQ_PACKET_END = -4,
+       SEQ_STREAM_BEGIN = -5,
+       SEQ_STREAM_END = -6,
 };
 
 struct src_iter_user_data {
@@ -101,52 +103,62 @@ struct sink_user_data {
 };
 
 static int64_t seq1[] = {
-       24, 53, 97, 105, 119, 210, 222, 240, 292, 317, 353, 407, 433,
-       473, 487, 504, 572, 615, 708, 766, 850, 852, 931, 951, 956, 996,
-       SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 24, 53, 97, 105, 119, 210,
+       222, 240, 292, 317, 353, 407, 433, 473, 487, 504, 572, 615, 708,
+       766, 850, 852, 931, 951, 956, 996, SEQ_PACKET_END,
+       SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq2[] = {
-       51, 59, 68, 77, 91, 121, 139, 170, 179, 266, 352, 454, 478, 631,
-       644, 668, 714, 744, 750, 778, 790, 836, SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 51, 59, 68, 77, 91, 121,
+       139, 170, 179, 266, 352, 454, 478, 631, 644, 668, 714, 744, 750,
+       778, 790, 836, SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq3[] = {
-       8, 71, 209, 254, 298, 320, 350, 393, 419, 624, 651, 678, 717,
-       731, 733, 788, 819, 820, 857, 892, 903, 944, 998, SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 8, 71, 209, 254, 298, 320,
+       350, 393, 419, 624, 651, 678, 717, 731, 733, 788, 819, 820, 857,
+       892, 903, 944, 998, SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq4[] = {
-       41, 56, 120, 138, 154, 228, 471, 479, 481, 525, 591, 605, 612,
-       618, 632, 670, 696, 825, 863, 867, 871, 884, 953, 985, 999,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 41, 56, 120, 138, 154, 228,
+       471, 479, 481, 525, 591, 605, 612, 618, 632, 670, 696, 825, 863,
+       867, 871, 884, 953, 985, 999, SEQ_PACKET_END, SEQ_STREAM_END,
        SEQ_END,
 };
 
 static int64_t seq1_with_again[] = {
-       24, 53, 97, 105, 119, 210, SEQ_AGAIN, 222, 240, 292, 317, 353,
-       407, 433, 473, 487, 504, 572, 615, 708, 766, 850, 852, 931, 951,
-       956, 996, SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 24, 53, 97, 105, 119, 210,
+       SEQ_AGAIN, 222, 240, 292, 317, 353, 407, 433, 473, 487, 504,
+       572, 615, 708, 766, 850, 852, 931, 951, 956, 996,
+       SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq2_with_again[] = {
-       51, 59, 68, 77, 91, 121, 139, 170, 179, 266, 352, 454, 478, 631,
-       644, 668, 714, 744, 750, 778, 790, 836, SEQ_AGAIN, SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 51, 59, 68, 77, 91, 121,
+       139, 170, 179, 266, 352, 454, 478, 631, 644, 668, 714, 744, 750,
+       778, 790, 836, SEQ_AGAIN, SEQ_PACKET_END, SEQ_STREAM_END,
+       SEQ_END,
 };
 
 static int64_t seq3_with_again[] = {
-       8, 71, 209, 254, 298, 320, 350, 393, 419, 624, 651, SEQ_AGAIN,
-       678, 717, 731, 733, 788, 819, 820, 857, 892, 903, 944, 998,
-       SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 8, 71, 209, 254, 298, 320,
+       350, 393, 419, 624, 651, SEQ_AGAIN, 678, 717, 731, 733, 788,
+       819, 820, 857, 892, 903, 944, 998, SEQ_PACKET_END,
+       SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq4_with_again[] = {
-       SEQ_AGAIN, 41, 56, 120, 138, 154, 228, 471, 479, 481, 525, 591,
-       605, 612, 618, 632, 670, 696, 825, 863, 867, 871, 884, 953, 985,
-       999, SEQ_END,
+       SEQ_AGAIN, SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 41, 56, 120, 138,
+       154, 228, 471, 479, 481, 525, 591, 605, 612, 618, 632, 670, 696,
+       825, 863, 867, 871, 884, 953, 985, 999, SEQ_PACKET_END,
+       SEQ_STREAM_END, SEQ_END,
 };
 
 static int64_t seq5[] = {
-       1, 4, 189, 1001, SEQ_END,
+       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 1, 4, 189, 1001,
+       SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
 };
 
 static
@@ -513,6 +525,7 @@ struct bt_notification_iterator_next_method_return src_iter_next_seq(
                .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
        };
        int64_t cur_ts_ns;
+       struct bt_stream *stream;
 
        assert(user_data->seq);
        cur_ts_ns = user_data->seq[user_data->at];
@@ -536,6 +549,20 @@ struct bt_notification_iterator_next_method_return src_iter_next_seq(
                        bt_notification_packet_end_create(user_data->packet);
                assert(next_return.notification);
                break;
+       case SEQ_STREAM_BEGIN:
+               stream = bt_packet_get_stream(user_data->packet);
+               next_return.notification =
+                       bt_notification_stream_begin_create(stream);
+               assert(next_return.notification);
+               bt_put(stream);
+               break;
+       case SEQ_STREAM_END:
+               stream = bt_packet_get_stream(user_data->packet);
+               next_return.notification =
+                       bt_notification_stream_end_create(stream);
+               assert(next_return.notification);
+               bt_put(stream);
+               break;
        default:
        {
                struct bt_event *event = src_create_event(
@@ -569,6 +596,7 @@ struct bt_notification_iterator_next_method_return src_iter_next(
                bt_private_connection_private_notification_iterator_get_user_data(priv_iterator);
        struct bt_private_component *private_component =
                bt_private_connection_private_notification_iterator_get_private_component(priv_iterator);
+       struct bt_stream *stream;
        int ret;
 
        assert(user_data);
@@ -578,11 +606,18 @@ struct bt_notification_iterator_next_method_return src_iter_next(
        case TEST_NO_TS:
                if (user_data->iter_index == 0) {
                        if (user_data->at == 0) {
+                               stream = bt_packet_get_stream(user_data->packet);
+                               next_return.notification =
+                                       bt_notification_stream_begin_create(
+                                               stream);
+                               bt_put(stream);
+                               assert(next_return.notification);
+                       } else if (user_data->at == 1) {
                                next_return.notification =
                                        bt_notification_packet_begin_create(
                                                user_data->packet);
                                assert(next_return.notification);
-                       } else if (user_data->at < 6) {
+                       } else if (user_data->at < 7) {
                                struct bt_event *event = src_create_event(
                                        user_data->packet, -1);
 
@@ -592,6 +627,18 @@ struct bt_notification_iterator_next_method_return src_iter_next(
                                                src_empty_cc_prio_map);
                                assert(next_return.notification);
                                bt_put(event);
+                       } else if (user_data->at == 7) {
+                               next_return.notification =
+                                       bt_notification_packet_end_create(
+                                               user_data->packet);
+                               assert(next_return.notification);
+                       } else if (user_data->at == 8) {
+                               stream = bt_packet_get_stream(user_data->packet);
+                               next_return.notification =
+                                       bt_notification_stream_end_create(
+                                               stream);
+                               bt_put(stream);
+                               assert(next_return.notification);
                        } else {
                                next_return.status =
                                        BT_NOTIFICATION_ITERATOR_STATUS_END;
@@ -846,7 +893,7 @@ void sink_port_connected(struct bt_private_component *private_component,
        assert(user_data);
        assert(priv_conn);
        conn_status = bt_private_connection_create_notification_iterator(
-               priv_conn, NULL, &user_data->notif_iter);
+               priv_conn, &user_data->notif_iter);
        assert(conn_status == 0);
        bt_put(priv_conn);
 }
This page took 0.112351 seconds and 4 git commands to generate.