{
struct bt_connection *connection = container_of(obj,
struct bt_connection, base);
+ size_t i;
+
+ /*
+ * Make sure that each notification iterator which was created
+ * for this connection is finalized before we destroy it. Once a
+ * notification iterator is finalized, all its method return
+ * NULL or the BT_NOTIFICATION_ITERATOR_STATUS_CANCELED status.
+ *
+ * Because connections are destroyed before components within a
+ * graph, this ensures that notification iterators are always
+ * finalized before their upstream component.
+ */
+ if (connection->iterators) {
+ for (i = 0; i < connection->iterators->len; i++) {
+ struct bt_notification_iterator *iterator =
+ g_ptr_array_index(connection->iterators, i);
+
+ bt_notification_iterator_finalize(iterator);
+
+ /*
+ * Make sure this iterator does not try to
+ * remove itself from this connection's
+ * iterators on destruction because this
+ * connection won't exist anymore.
+ */
+ bt_notification_iterator_set_connection(iterator,
+ NULL);
+ }
+
+ g_ptr_array_free(connection->iterators, TRUE);
+ }
/*
* No bt_put on ports as a connection only holds _weak_ references
}
bt_object_init(connection, bt_connection_destroy);
+ connection->iterators = g_ptr_array_new();
+ if (!connection->iterators) {
+ BT_PUT(connection);
+ goto end;
+ }
+
/* Weak references are taken, see comment in header. */
connection->upstream_port = upstream_port;
connection->downstream_port = downstream_port;
struct bt_notification_iterator *
bt_private_connection_create_notification_iterator(
- struct bt_private_connection *private_connection)
+ struct bt_private_connection *private_connection,
+ const enum bt_notification_type *notification_types)
{
enum bt_notification_iterator_status ret_iterator;
enum bt_component_class_type upstream_comp_class_type;
struct bt_component_class *upstream_comp_class = NULL;
struct bt_connection *connection = NULL;
bt_component_class_notification_iterator_init_method init_method = NULL;
+ static const enum bt_notification_type all_notif_types[] = {
+ BT_NOTIFICATION_TYPE_ALL,
+ BT_NOTIFICATION_TYPE_SENTINEL,
+ };
if (!private_connection) {
goto error;
}
- connection = bt_connection_from_private(private_connection);
+ if (!notification_types) {
+ notification_types = all_notif_types;
+ }
+ connection = bt_connection_from_private(private_connection);
if (!connection->upstream_port || !connection->downstream_port) {
goto error;
}
}
iterator = bt_notification_iterator_create(upstream_component,
- upstream_port);
+ upstream_port, notification_types, connection);
if (!iterator) {
goto error;
}
goto error;
}
+ g_ptr_array_add(connection->iterators, iterator);
goto end;
error:
bt_put(upstream_component);
return iterator;
}
+
+BT_HIDDEN
+void bt_connection_remove_iterator(struct bt_connection *conn,
+ struct bt_notification_iterator *iterator)
+{
+ g_ptr_array_remove(conn->iterators, iterator);
+}