From fa054faf3a18fd8003510c32718c1fd4fbf3dd46 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 2 May 2017 16:42:16 -0400 Subject: [PATCH] Subscribe to notifications when creating a notif. iterator MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit bt_private_connection_create_notification_iterator() now accepts a new parameter which is a BT_NOTIFICATION_TYPE_SENTINEL-terminated array of notification types to subscribe to. It is guaranteed that, after any bt_notification_iterator_next() called on the created iterator (if the status is BT_NOTIFICATION_ITERATOR_STATUS_OK), the following call to bt_notification_iterator_get_notification() returns a notification to which the iterator is subscribed. You can pass NULL to the notification types parameter of bt_private_connection_create_notification_iterator() to subscribe to all existing notifications (including the ones that will be added to the following versions of the library). The use case behind the subscription mechanism is for a notification iterator to avoid the generation of automatic notifications when the iterator's user does not expect them anyway. This should be the case of some filters and sinks, text.pretty being a current example (only needs event notifications). Tests and existing plugins are updated accordingly. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- .../graph/notification-iterator-internal.h | 19 +- include/babeltrace/graph/notification.h | 16 +- include/babeltrace/graph/private-connection.h | 5 +- lib/graph/connection.c | 13 +- lib/graph/iterator.c | 219 ++++++++++++++---- plugins/debug-info/plugin.c | 2 +- plugins/text/pretty/pretty.c | 7 +- plugins/utils/dummy/dummy.c | 2 +- plugins/utils/muxer/muxer.c | 2 +- plugins/utils/trimmer/iterator.c | 3 +- plugins/writer/writer.c | 5 +- tests/lib/test_bt_notification_iterator.c | 3 +- tests/plugins/test-utils-muxer.c | 3 +- 13 files changed, 235 insertions(+), 64 deletions(-) diff --git a/include/babeltrace/graph/notification-iterator-internal.h b/include/babeltrace/graph/notification-iterator-internal.h index dc4e4309..90a8ee47 100644 --- a/include/babeltrace/graph/notification-iterator-internal.h +++ b/include/babeltrace/graph/notification-iterator-internal.h @@ -35,6 +35,15 @@ struct bt_port; +enum bt_notification_iterator_notif_type { + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT = (1U << 0), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY = (1U << 1), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN = (1U << 2), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END = (1U << 3), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN = (1U << 4), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END = (1U << 5), +}; + struct bt_notification_iterator { struct bt_object base; struct bt_component *upstream_component; /* owned by this */ @@ -69,6 +78,13 @@ struct bt_notification_iterator { */ GArray *actions; + /* + * This is a mask of notifications to which the user of this + * iterator is subscribed + * (see enum bt_notification_iterator_notif_type above). + */ + uint32_t subscription_mask; + bool is_ended; void *user_data; }; @@ -97,7 +113,8 @@ bt_private_notification_iterator_from_notification_iterator( BT_HIDDEN struct bt_notification_iterator *bt_notification_iterator_create( struct bt_component *upstream_component, - struct bt_port *upstream_port); + struct bt_port *upstream_port, + const enum bt_notification_type *notification_types); /** * Validate a notification iterator. diff --git a/include/babeltrace/graph/notification.h b/include/babeltrace/graph/notification.h index ae5e22f9..632da9be 100644 --- a/include/babeltrace/graph/notification.h +++ b/include/babeltrace/graph/notification.h @@ -37,15 +37,15 @@ struct bt_notification; * Notification types. Unhandled notification types should be ignored. */ enum bt_notification_type { - BT_NOTIFICATION_TYPE_SENTINEL = -2, + BT_NOTIFICATION_TYPE_SENTINEL = -1000, BT_NOTIFICATION_TYPE_UNKNOWN = -1, - BT_NOTIFICATION_TYPE_ALL = 0, - BT_NOTIFICATION_TYPE_EVENT = 1, - BT_NOTIFICATION_TYPE_INACTIVITY = 2, - BT_NOTIFICATION_TYPE_STREAM_BEGIN = 3, - BT_NOTIFICATION_TYPE_STREAM_END = 4, - BT_NOTIFICATION_TYPE_PACKET_BEGIN = 5, - BT_NOTIFICATION_TYPE_PACKET_END = 6, + BT_NOTIFICATION_TYPE_ALL = -2, + BT_NOTIFICATION_TYPE_EVENT = 0, + BT_NOTIFICATION_TYPE_INACTIVITY = 1, + BT_NOTIFICATION_TYPE_STREAM_BEGIN = 2, + BT_NOTIFICATION_TYPE_STREAM_END = 3, + BT_NOTIFICATION_TYPE_PACKET_BEGIN = 4, + BT_NOTIFICATION_TYPE_PACKET_END = 5, BT_NOTIFICATION_TYPE_NR, /* Not part of ABI. */ }; diff --git a/include/babeltrace/graph/private-connection.h b/include/babeltrace/graph/private-connection.h index 76294604..9d3d39c4 100644 --- a/include/babeltrace/graph/private-connection.h +++ b/include/babeltrace/graph/private-connection.h @@ -23,6 +23,8 @@ * SOFTWARE. */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -36,7 +38,8 @@ struct bt_connection *bt_connection_from_private_connection( extern 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); #ifdef __cplusplus } diff --git a/lib/graph/connection.c b/lib/graph/connection.c index bfc9c04b..a9a5f9db 100644 --- a/lib/graph/connection.c +++ b/lib/graph/connection.c @@ -140,7 +140,8 @@ struct bt_port *bt_connection_get_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; @@ -150,11 +151,19 @@ bt_private_connection_create_notification_iterator( 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; } + if (!notification_types) { + notification_types = all_notif_types; + } + connection = bt_connection_from_private(private_connection); if (!connection->upstream_port || !connection->downstream_port) { @@ -180,7 +189,7 @@ bt_private_connection_create_notification_iterator( } iterator = bt_notification_iterator_create(upstream_component, - upstream_port); + upstream_port, notification_types); if (!iterator) { goto error; } diff --git a/lib/graph/iterator.c b/lib/graph/iterator.c index 389eec52..c76293a9 100644 --- a/lib/graph/iterator.c +++ b/lib/graph/iterator.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include struct stream_state { struct bt_ctf_stream *stream; /* owned by this */ @@ -341,16 +343,70 @@ void bt_notification_iterator_destroy(struct bt_object *obj) g_free(iterator); } +static +int create_subscription_mask_from_notification_types( + struct bt_notification_iterator *iterator, + const enum bt_notification_type *notif_types) +{ + const enum bt_notification_type *notif_type; + int ret = 0; + + 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_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; + break; + case BT_NOTIFICATION_TYPE_EVENT: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT; + break; + case BT_NOTIFICATION_TYPE_INACTIVITY: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY; + break; + case BT_NOTIFICATION_TYPE_STREAM_BEGIN: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN; + break; + case BT_NOTIFICATION_TYPE_STREAM_END: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END; + break; + case BT_NOTIFICATION_TYPE_PACKET_BEGIN: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN; + break; + case BT_NOTIFICATION_TYPE_PACKET_END: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; + break; + default: + ret = -1; + goto end; + } + } + +end: + return ret; +} + BT_HIDDEN struct bt_notification_iterator *bt_notification_iterator_create( struct bt_component *upstream_comp, - struct bt_port *upstream_port) + struct bt_port *upstream_port, + const enum bt_notification_type *notification_types) { enum bt_component_class_type type; struct bt_notification_iterator *iterator = NULL; assert(upstream_comp); assert(upstream_port); + assert(notification_types); assert(bt_port_is_connected(upstream_port)); type = bt_component_get_class_type(upstream_comp); @@ -369,6 +425,11 @@ struct bt_notification_iterator *bt_notification_iterator_create( bt_object_init(iterator, bt_notification_iterator_destroy); + if (create_subscription_mask_from_notification_types(iterator, + notification_types)) { + goto error; + } + iterator->stream_states = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) destroy_stream_state); if (!iterator->stream_states) { @@ -455,6 +516,39 @@ end: return notification; } +static +enum bt_notification_iterator_notif_type +bt_notification_iterator_notif_type_from_notif_type( + enum bt_notification_type notif_type) +{ + enum bt_notification_iterator_notif_type iter_notif_type; + + switch (notif_type) { + case BT_NOTIFICATION_TYPE_EVENT: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT; + break; + case BT_NOTIFICATION_TYPE_INACTIVITY: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY; + break; + case BT_NOTIFICATION_TYPE_STREAM_BEGIN: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN; + break; + case BT_NOTIFICATION_TYPE_STREAM_END: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END; + break; + case BT_NOTIFICATION_TYPE_PACKET_BEGIN: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN; + break; + case BT_NOTIFICATION_TYPE_PACKET_END: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; + break; + default: + assert(false); + } + + return iter_notif_type; +} + static bool validate_notification(struct bt_notification_iterator *iterator, struct bt_notification *notif, @@ -542,18 +636,32 @@ end: return is_valid; } +static +bool is_subscribed_to_notification_type(struct bt_notification_iterator *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) ? true : false; +} + static void add_action_push_notif(struct bt_notification_iterator *iterator, struct bt_notification *notif) { struct action action = { .type = ACTION_TYPE_PUSH_NOTIF, - .payload.push_notif = { - .notif = bt_get(notif), - }, }; assert(notif); + + if (!is_subscribed_to_notification_type(iterator, notif->type)) { + return; + } + + action.payload.push_notif.notif = bt_get(notif); add_action(iterator, &action); } @@ -565,6 +673,11 @@ int add_action_push_notif_stream_begin( int ret = 0; struct bt_notification *stream_begin_notif = NULL; + if (!is_subscribed_to_notification_type(iterator, + BT_NOTIFICATION_TYPE_STREAM_BEGIN)) { + goto end; + } + assert(stream); stream_begin_notif = bt_notification_stream_begin_create(stream); if (!stream_begin_notif) { @@ -590,6 +703,11 @@ int add_action_push_notif_stream_end( int ret = 0; struct bt_notification *stream_end_notif = NULL; + if (!is_subscribed_to_notification_type(iterator, + BT_NOTIFICATION_TYPE_STREAM_END)) { + goto end; + } + assert(stream); stream_end_notif = bt_notification_stream_end_create(stream); if (!stream_end_notif) { @@ -615,6 +733,11 @@ int add_action_push_notif_packet_begin( int ret = 0; struct bt_notification *packet_begin_notif = NULL; + if (!is_subscribed_to_notification_type(iterator, + BT_NOTIFICATION_TYPE_PACKET_BEGIN)) { + goto end; + } + assert(packet); packet_begin_notif = bt_notification_packet_begin_create(packet); if (!packet_begin_notif) { @@ -640,6 +763,11 @@ int add_action_push_notif_packet_end( int ret = 0; struct bt_notification *packet_end_notif = NULL; + if (!is_subscribed_to_notification_type(iterator, + BT_NOTIFICATION_TYPE_PACKET_END)) { + goto end; + } + assert(packet); packet_end_notif = bt_notification_packet_end_create(packet); if (!packet_end_notif) { @@ -967,6 +1095,9 @@ int enqueue_notification_and_automatic( assert(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: @@ -1165,55 +1296,57 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( /* * Call the user's "next" method to get the next notification - * and status, skipping the forwarded automatic notifications - * if any. + * and status. */ assert(next_method); - next_return = next_method(priv_iterator); - if (next_return.status < 0) { - status = next_return.status; - goto end; - } - switch (next_return.status) { - case BT_NOTIFICATION_ITERATOR_STATUS_END: - ret = handle_end(iterator); - if (ret) { - status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + while (iterator->queue->length == 0) { + next_return = next_method(priv_iterator); + if (next_return.status < 0) { + status = next_return.status; goto end; } - if (iterator->queue->length == 0) { - status = BT_NOTIFICATION_ITERATOR_STATUS_END; - } + switch (next_return.status) { + case BT_NOTIFICATION_ITERATOR_STATUS_END: + ret = handle_end(iterator); + if (ret) { + status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + goto end; + } - iterator->is_ended = true; - break; - case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN: - status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN; - break; - case BT_NOTIFICATION_ITERATOR_STATUS_OK: - if (!next_return.notification) { - status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; - goto end; - } + if (iterator->queue->length == 0) { + status = BT_NOTIFICATION_ITERATOR_STATUS_END; + } - /* - * 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) { - status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + iterator->is_ended = true; 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) { + status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + goto end; + } + + /* + * 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) { + status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; + goto end; + } + break; + default: + /* Unknown non-error status */ + assert(false); } - break; - default: - /* Unknown non-error status */ - assert(false); } end: diff --git a/plugins/debug-info/plugin.c b/plugins/debug-info/plugin.c index 9795bcf3..c9ae94fa 100644 --- a/plugins/debug-info/plugin.c +++ b/plugins/debug-info/plugin.c @@ -325,7 +325,7 @@ enum bt_notification_iterator_status debug_info_iterator_init( assert(connection); it_data->input_iterator = bt_private_connection_create_notification_iterator( - connection); + connection, NULL); if (!it_data->input_iterator) { ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; goto end; diff --git a/plugins/text/pretty/pretty.c b/plugins/text/pretty/pretty.c index cea5fe68..043ba4fc 100644 --- a/plugins/text/pretty/pretty.c +++ b/plugins/text/pretty/pretty.c @@ -145,6 +145,10 @@ void pretty_port_connected( { struct bt_private_connection *connection; struct pretty_component *pretty; + static const enum bt_notification_type notif_types[] = { + BT_NOTIFICATION_TYPE_EVENT, + BT_NOTIFICATION_TYPE_SENTINEL, + }; pretty = bt_private_component_get_user_data(component); assert(pretty); @@ -152,7 +156,8 @@ void pretty_port_connected( connection = bt_private_port_get_private_connection(self_port); assert(connection); pretty->input_iterator = - bt_private_connection_create_notification_iterator(connection); + bt_private_connection_create_notification_iterator(connection, + notif_types); if (!pretty->input_iterator) { pretty->error = true; diff --git a/plugins/utils/dummy/dummy.c b/plugins/utils/dummy/dummy.c index 978ecdea..5f7c62d6 100644 --- a/plugins/utils/dummy/dummy.c +++ b/plugins/utils/dummy/dummy.c @@ -106,7 +106,7 @@ void dummy_port_connected( connection = bt_private_port_get_private_connection(self_port); assert(connection); iterator = bt_private_connection_create_notification_iterator( - connection); + connection, NULL); if (!iterator) { dummy->error = true; goto end; diff --git a/plugins/utils/muxer/muxer.c b/plugins/utils/muxer/muxer.c index ba2fb3c0..b98a74e0 100644 --- a/plugins/utils/muxer/muxer.c +++ b/plugins/utils/muxer/muxer.c @@ -359,7 +359,7 @@ struct bt_notification_iterator *create_notif_iter_on_input_port( // returned notification by the muxer notification // iterator which creates it. notif_iter = bt_private_connection_create_notification_iterator( - priv_conn); + priv_conn, NULL); if (!notif_iter) { *ret = -1; goto end; diff --git a/plugins/utils/trimmer/iterator.c b/plugins/utils/trimmer/iterator.c index e6427307..2fba7f66 100644 --- a/plugins/utils/trimmer/iterator.c +++ b/plugins/utils/trimmer/iterator.c @@ -91,7 +91,8 @@ enum bt_notification_iterator_status trimmer_iterator_init( assert(connection); it_data->input_iterator = - bt_private_connection_create_notification_iterator(connection); + bt_private_connection_create_notification_iterator(connection, + NULL); if (!it_data->input_iterator) { ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM; goto end; diff --git a/plugins/writer/writer.c b/plugins/writer/writer.c index 118210ab..3bca09b6 100644 --- a/plugins/writer/writer.c +++ b/plugins/writer/writer.c @@ -198,8 +198,9 @@ void writer_component_port_connected( assert(!writer->input_iterator); connection = bt_private_port_get_private_connection(self_port); assert(connection); - writer->input_iterator = - bt_private_connection_create_notification_iterator(connection); + writer->input_iterator = + bt_private_connection_create_notification_iterator(connection, + NULL); if (!writer->input_iterator) { writer->error = true; diff --git a/tests/lib/test_bt_notification_iterator.c b/tests/lib/test_bt_notification_iterator.c index 303c42bd..99664498 100644 --- a/tests/lib/test_bt_notification_iterator.c +++ b/tests/lib/test_bt_notification_iterator.c @@ -831,7 +831,8 @@ void sink_port_connected(struct bt_private_component *private_component, assert(user_data); assert(priv_conn); user_data->notif_iter = - bt_private_connection_create_notification_iterator(priv_conn); + bt_private_connection_create_notification_iterator(priv_conn, + NULL); assert(user_data->notif_iter); bt_put(priv_conn); } diff --git a/tests/plugins/test-utils-muxer.c b/tests/plugins/test-utils-muxer.c index 1b4c94ec..2fd584c9 100644 --- a/tests/plugins/test-utils-muxer.c +++ b/tests/plugins/test-utils-muxer.c @@ -884,7 +884,8 @@ void sink_port_connected(struct bt_private_component *private_component, assert(user_data); assert(priv_conn); user_data->notif_iter = - bt_private_connection_create_notification_iterator(priv_conn); + bt_private_connection_create_notification_iterator(priv_conn, + NULL); assert(user_data->notif_iter); bt_put(priv_conn); } -- 2.34.1