X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fgraph%2Fiterator.c;h=56f4a2512e2227dbb2bccd8bde57adf4654e3b15;hb=330cb9e025c2c1162763c75e8198efe229a635bc;hp=c76293a972baac05b618233390dba0d8c0c3a7ef;hpb=fa054faf3a18fd8003510c32718c1fd4fbf3dd46;p=babeltrace.git diff --git a/lib/graph/iterator.c b/lib/graph/iterator.c index c76293a9..56f4a251 100644 --- a/lib/graph/iterator.c +++ b/lib/graph/iterator.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -44,12 +45,13 @@ #include #include #include +#include #include struct stream_state { struct bt_ctf_stream *stream; /* owned by this */ struct bt_ctf_packet *cur_packet; /* owned by this */ - bool is_ended; + bt_bool is_ended; }; enum action_type { @@ -141,7 +143,7 @@ void destroy_action(struct action *action) case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED: break; default: - assert(false); + assert(BT_FALSE); } } @@ -219,7 +221,7 @@ void apply_actions(struct bt_notification_iterator *iterator) bt_ctf_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 = true; + 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: @@ -228,7 +230,7 @@ void apply_actions(struct bt_notification_iterator *iterator) action->payload.set_stream_state_cur_packet.packet); break; default: - assert(false); + assert(BT_FALSE); } } @@ -262,44 +264,22 @@ static void bt_notification_iterator_destroy(struct bt_object *obj) { struct bt_notification_iterator *iterator; - struct bt_component_class *comp_class; assert(obj); - iterator = container_of(obj, struct bt_notification_iterator, - base); - assert(iterator->upstream_component); - comp_class = iterator->upstream_component->class; - - /* Call user-defined destroy method */ - switch (comp_class->type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - { - struct bt_component_class_source *source_class; - - source_class = container_of(comp_class, struct bt_component_class_source, parent); - - if (source_class->methods.iterator.finalize) { - source_class->methods.iterator.finalize( - bt_private_notification_iterator_from_notification_iterator(iterator)); - } - break; - } - case BT_COMPONENT_CLASS_TYPE_FILTER: - { - struct bt_component_class_filter *filter_class; - filter_class = container_of(comp_class, struct bt_component_class_filter, parent); - - if (filter_class->methods.iterator.finalize) { - filter_class->methods.iterator.finalize( - bt_private_notification_iterator_from_notification_iterator(iterator)); - } - break; - } - default: - /* Unreachable */ - assert(0); - } + /* + * The notification iterator's reference count is 0 if we're + * here. Increment it to avoid a double-destroy (possibly + * infinitely recursive). This could happen for example if the + * notification iterator's finalization function does bt_get() + * (or anything that causes bt_get() to be called) on itself + * (ref. count goes from 0 to 1), and then bt_put(): the + * reference count would go from 1 to 0 again and this function + * would be called again. + */ + obj->ref_count.count++; + iterator = container_of(obj, struct bt_notification_iterator, base); + bt_notification_iterator_finalize(iterator); if (iterator->queue) { struct bt_notification *notif; @@ -337,12 +317,88 @@ void bt_notification_iterator_destroy(struct bt_object *obj) g_array_free(iterator->actions, TRUE); } + if (iterator->connection) { + /* + * Remove ourself from the originating connection so + * that it does not try to finalize a dangling pointer + * later. + */ + bt_connection_remove_iterator(iterator->connection, iterator); + } + bt_put(iterator->current_notification); - bt_put(iterator->upstream_component); - bt_put(iterator->upstream_port); g_free(iterator); } +BT_HIDDEN +void bt_notification_iterator_finalize( + struct bt_notification_iterator *iterator) +{ + struct bt_component_class *comp_class = NULL; + bt_component_class_notification_iterator_finalize_method + finalize_method = NULL; + + assert(iterator); + + switch (iterator->state) { + case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED: + case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED: + /* Already finalized */ + return; + default: + break; + } + + if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_ENDED) { + iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED; + } else { + iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED; + } + + assert(iterator->upstream_component); + comp_class = iterator->upstream_component->class; + + /* Call user-defined destroy method */ + switch (comp_class->type) { + case BT_COMPONENT_CLASS_TYPE_SOURCE: + { + struct bt_component_class_source *source_class; + + source_class = container_of(comp_class, struct bt_component_class_source, parent); + finalize_method = source_class->methods.iterator.finalize; + break; + } + case BT_COMPONENT_CLASS_TYPE_FILTER: + { + struct bt_component_class_filter *filter_class; + + filter_class = container_of(comp_class, struct bt_component_class_filter, parent); + finalize_method = filter_class->methods.iterator.finalize; + break; + } + default: + /* Unreachable */ + assert(0); + } + + if (finalize_method) { + finalize_method( + bt_private_notification_iterator_from_notification_iterator(iterator)); + } + + iterator->upstream_component = NULL; + iterator->upstream_port = NULL; +} + +BT_HIDDEN +void bt_notification_iterator_set_connection( + struct bt_notification_iterator *iterator, + struct bt_connection *connection) +{ + assert(iterator); + iterator->connection = connection; +} + static int create_subscription_mask_from_notification_types( struct bt_notification_iterator *iterator, @@ -399,7 +455,8 @@ BT_HIDDEN struct bt_notification_iterator *bt_notification_iterator_create( struct bt_component *upstream_comp, struct bt_port *upstream_port, - const enum bt_notification_type *notification_types) + const enum bt_notification_type *notification_types, + struct bt_connection *connection) { enum bt_component_class_type type; struct bt_notification_iterator *iterator = NULL; @@ -410,14 +467,8 @@ struct bt_notification_iterator *bt_notification_iterator_create( assert(bt_port_is_connected(upstream_port)); type = bt_component_get_class_type(upstream_comp); - switch (type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - case BT_COMPONENT_CLASS_TYPE_FILTER: - break; - default: - goto error; - } - + assert(type == BT_COMPONENT_CLASS_TYPE_SOURCE || + type == BT_COMPONENT_CLASS_TYPE_FILTER); iterator = g_new0(struct bt_notification_iterator, 1); if (!iterator) { goto error; @@ -446,8 +497,10 @@ struct bt_notification_iterator *bt_notification_iterator_create( goto error; } - iterator->upstream_component = bt_get(upstream_comp); - iterator->upstream_port = bt_get(upstream_port); + iterator->upstream_component = upstream_comp; + iterator->upstream_port = upstream_port; + iterator->connection = connection; + iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ACTIVE; goto end; error: @@ -457,21 +510,6 @@ end: return iterator; } -BT_HIDDEN -enum bt_notification_iterator_status bt_notification_iterator_validate( - struct bt_notification_iterator *iterator) -{ - enum bt_notification_iterator_status ret = - BT_NOTIFICATION_ITERATOR_STATUS_OK; - - if (!iterator) { - ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID; - goto end; - } -end: - return ret; -} - void *bt_private_notification_iterator_get_user_data( struct bt_private_notification_iterator *private_iterator) { @@ -543,19 +581,19 @@ bt_notification_iterator_notif_type_from_notif_type( iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; break; default: - assert(false); + assert(BT_FALSE); } return iter_notif_type; } static -bool validate_notification(struct bt_notification_iterator *iterator, +bt_bool validate_notification(struct bt_notification_iterator *iterator, struct bt_notification *notif, struct bt_ctf_stream *notif_stream, struct bt_ctf_packet *notif_packet) { - bool is_valid = true; + bt_bool is_valid = BT_TRUE; struct stream_state *stream_state; struct bt_port *stream_comp_cur_port; @@ -589,7 +627,7 @@ bool validate_notification(struct bt_notification_iterator *iterator, * bad: the API guarantees that it can never * happen. */ - is_valid = false; + is_valid = BT_FALSE; goto end; } @@ -607,7 +645,7 @@ bool validate_notification(struct bt_notification_iterator *iterator, * bad: the API guarantees that it can never * happen. */ - is_valid = false; + is_valid = BT_FALSE; goto end; } @@ -618,12 +656,12 @@ bool validate_notification(struct bt_notification_iterator *iterator, * we already returned a "stream begin" * notification: this is an invalid duplicate. */ - is_valid = false; + is_valid = BT_FALSE; goto end; case BT_NOTIFICATION_TYPE_PACKET_BEGIN: if (notif_packet == stream_state->cur_packet) { /* Duplicate "packet begin" notification */ - is_valid = false; + is_valid = BT_FALSE; goto end; } break; @@ -637,14 +675,14 @@ end: } static -bool is_subscribed_to_notification_type(struct bt_notification_iterator *iterator, +bt_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; + return (iter_notif_type & iterator->subscription_mask) ? BT_TRUE : BT_FALSE; } static @@ -1126,7 +1164,7 @@ int enqueue_notification_and_automatic( break; case BT_NOTIFICATION_TYPE_INACTIVITY: /* Always valid */ - break; + goto handle_notif; default: /* * Invalid type of notification. Only the notification @@ -1154,6 +1192,7 @@ int enqueue_notification_and_automatic( goto error; } +handle_notif: switch (notif->type) { case BT_NOTIFICATION_TYPE_EVENT: ret = handle_notif_event(iterator, notif, notif_stream, @@ -1173,6 +1212,9 @@ int enqueue_notification_and_automatic( ret = handle_notif_packet_end(iterator, notif, notif_stream, notif_packet); break; + case BT_NOTIFICATION_TYPE_INACTIVITY: + add_action_push_notif(iterator, notif); + break; default: break; } @@ -1259,9 +1301,15 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( goto end; } - if (iterator->is_ended) { + switch (iterator->state) { + case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED: + status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED; + goto end; + case BT_NOTIFICATION_ITERATOR_STATE_ENDED: status = BT_NOTIFICATION_ITERATOR_STATUS_END; goto end; + default: + break; } assert(iterator->upstream_component); @@ -1290,7 +1338,7 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( break; } default: - assert(false); + assert(BT_FALSE); break; } @@ -1315,11 +1363,21 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( goto end; } - if (iterator->queue->length == 0) { - status = BT_NOTIFICATION_ITERATOR_STATUS_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; - iterator->is_ended = true; + if (iterator->queue->length == 0) { + status = BT_NOTIFICATION_ITERATOR_STATUS_END; + } + } goto end; case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN: status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN; @@ -1345,7 +1403,7 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( break; default: /* Unknown non-error status */ - assert(false); + assert(BT_FALSE); } }