lib/ctf-ir/trace.c: validate PH `packet_seq_num` field
[babeltrace.git] / lib / graph / iterator.c
index 2428c72b68d4296433b6c201e416b0449d450619..87fe6376309de579986cc9422e12cf66a0c3f8fc 100644 (file)
@@ -33,6 +33,7 @@
 #include <babeltrace/ctf-ir/event-internal.h>
 #include <babeltrace/ctf-ir/packet-internal.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
+#include <babeltrace/graph/connection.h>
 #include <babeltrace/graph/connection-internal.h>
 #include <babeltrace/graph/component.h>
 #include <babeltrace/graph/component-source-internal.h>
@@ -50,6 +51,7 @@
 #include <babeltrace/graph/port.h>
 #include <babeltrace/types.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 struct stream_state {
        struct bt_ctf_stream *stream; /* owned by this */
@@ -149,7 +151,7 @@ void destroy_action(struct action *action)
        case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
                break;
        default:
-               assert(BT_FALSE);
+               abort();
        }
 }
 
@@ -261,7 +263,7 @@ void apply_actions(struct bt_notification_iterator *iterator)
                                action->payload.set_stream_state_cur_packet.packet);
                        break;
                default:
-                       assert(BT_FALSE);
+                       abort();
                }
        }
 
@@ -428,7 +430,7 @@ void bt_notification_iterator_finalize(
        }
        default:
                /* Unreachable */
-               assert(0);
+               abort();
        }
 
        if (finalize_method) {
@@ -512,12 +514,14 @@ end:
 }
 
 BT_HIDDEN
-struct bt_notification_iterator *bt_notification_iterator_create(
+enum bt_connection_status bt_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_connection *connection,
+               struct bt_notification_iterator **user_iterator)
 {
+       enum bt_connection_status status = BT_CONNECTION_STATUS_OK;
        enum bt_component_class_type type;
        struct bt_notification_iterator *iterator = NULL;
 
@@ -525,6 +529,7 @@ struct bt_notification_iterator *bt_notification_iterator_create(
        assert(upstream_port);
        assert(notification_types);
        assert(bt_port_is_connected(upstream_port));
+       assert(user_iterator);
        BT_LOGD("Creating notification iterator: "
                "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
                "upstream-port-addr=%p, upstream-port-name=\"%s\", "
@@ -538,7 +543,8 @@ struct bt_notification_iterator *bt_notification_iterator_create(
        iterator = g_new0(struct bt_notification_iterator, 1);
        if (!iterator) {
                BT_LOGE_STR("Failed to allocate one notification iterator.");
-               goto error;
+               status = BT_CONNECTION_STATUS_NOMEM;
+               goto end;
        }
 
        bt_object_init(iterator, bt_notification_iterator_destroy);
@@ -546,26 +552,30 @@ struct bt_notification_iterator *bt_notification_iterator_create(
        if (create_subscription_mask_from_notification_types(iterator,
                        notification_types)) {
                BT_LOGW_STR("Cannot create subscription mask from notification types.");
-               goto error;
+               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) {
                BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
+               status = BT_CONNECTION_STATUS_NOMEM;
+               goto end;
        }
 
        iterator->queue = g_queue_new();
        if (!iterator->queue) {
                BT_LOGE_STR("Failed to allocate a GQueue.");
-               goto error;
+               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.");
-               goto error;
+               status = BT_CONNECTION_STATUS_NOMEM;
+               goto end;
        }
 
        iterator->upstream_component = upstream_comp;
@@ -579,13 +589,14 @@ struct bt_notification_iterator *bt_notification_iterator_create(
                upstream_comp, bt_component_get_name(upstream_comp),
                upstream_port, bt_port_get_name(upstream_port),
                connection, iterator);
-       goto end;
 
-error:
-       BT_PUT(iterator);
+       /* Move reference to user */
+       *user_iterator = iterator;
+       iterator = NULL;
 
 end:
-       return iterator;
+       bt_put(iterator);
+       return status;
 }
 
 void *bt_private_notification_iterator_get_user_data(
@@ -664,7 +675,7 @@ bt_notification_iterator_notif_type_from_notif_type(
                iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
                break;
        default:
-               assert(BT_FALSE);
+               abort();
        }
 
        return iter_notif_type;
@@ -1473,17 +1484,25 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
 
        assert(iterator);
        BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
-               "iter-addr=%p, queue-size=%u",
-               iterator, iterator->queue->length);
+               "iter-addr=%p, queue-size=%u, iter-state=%s",
+               iterator, iterator->queue->length,
+               bt_notification_iterator_state_string(iterator->state));
 
        if (iterator->queue->length > 0) {
-               /* We already have enough */
+               /*
+                * 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_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
+       case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
                BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
                status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
                goto end;
@@ -1521,8 +1540,7 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
                break;
        }
        default:
-               assert(BT_FALSE);
-               break;
+               abort();
        }
 
        /*
@@ -1542,6 +1560,32 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
                        goto end;
                }
 
+               if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
+                               iterator->state == BT_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;
+               }
+
                switch (next_return.status) {
                case BT_NOTIFICATION_ITERATOR_STATUS_END:
                        ret = handle_end(iterator);
@@ -1551,20 +1595,12 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
                                goto end;
                        }
 
-                       if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED) {
-                               iterator->state =
-                                       BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
-
-                               if (iterator->queue->length == 0) {
-                                       status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
-                               }
-                       } else {
-                               iterator->state =
-                                       BT_NOTIFICATION_ITERATOR_STATE_ENDED;
+                       assert(iterator->state ==
+                               BT_NOTIFICATION_ITERATOR_STATE_ACTIVE);
+                       iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ENDED;
 
-                               if (iterator->queue->length == 0) {
-                                       status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-                               }
+                       if (iterator->queue->length == 0) {
+                               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
                        }
 
                        BT_LOGD("Set new status: status=%s",
@@ -1596,7 +1632,7 @@ enum bt_notification_iterator_status ensure_queue_has_notifications(
                        break;
                default:
                        /* Unknown non-error status */
-                       assert(BT_FALSE);
+                       abort();
                }
        }
 
This page took 0.027248 seconds and 4 git commands to generate.