4 * Babeltrace Notification Iterator
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #include <babeltrace/compiler-internal.h>
29 #include <babeltrace/ref.h>
30 #include <babeltrace/ctf-ir/event-internal.h>
31 #include <babeltrace/ctf-ir/packet-internal.h>
32 #include <babeltrace/ctf-ir/stream-internal.h>
33 #include <babeltrace/graph/connection-internal.h>
34 #include <babeltrace/graph/component.h>
35 #include <babeltrace/graph/component-source-internal.h>
36 #include <babeltrace/graph/component-class-internal.h>
37 #include <babeltrace/graph/notification.h>
38 #include <babeltrace/graph/notification-iterator.h>
39 #include <babeltrace/graph/notification-iterator-internal.h>
40 #include <babeltrace/graph/notification-internal.h>
41 #include <babeltrace/graph/notification-event.h>
42 #include <babeltrace/graph/notification-event-internal.h>
43 #include <babeltrace/graph/notification-packet.h>
44 #include <babeltrace/graph/notification-packet-internal.h>
45 #include <babeltrace/graph/notification-stream.h>
46 #include <babeltrace/graph/notification-stream-internal.h>
47 #include <babeltrace/graph/port.h>
48 #include <babeltrace/types.h>
52 struct bt_ctf_stream
*stream
; /* owned by this */
53 struct bt_ctf_packet
*cur_packet
; /* owned by this */
58 ACTION_TYPE_PUSH_NOTIF
,
59 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
60 ACTION_TYPE_ADD_STREAM_STATE
,
61 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
62 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
66 enum action_type type
;
68 /* ACTION_TYPE_PUSH_NOTIF */
70 struct bt_notification
*notif
; /* owned by this */
73 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
75 struct bt_ctf_stream
*stream
; /* owned by this */
76 struct bt_component
*component
; /* owned by this */
77 struct bt_port
*port
; /* owned by this */
78 } map_port_to_comp_in_stream
;
80 /* ACTION_TYPE_ADD_STREAM_STATE */
82 struct bt_ctf_stream
*stream
; /* owned by this */
83 struct stream_state
*stream_state
; /* owned by this */
86 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
88 struct stream_state
*stream_state
; /* weak */
89 } set_stream_state_is_ended
;
91 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
93 struct stream_state
*stream_state
; /* weak */
94 struct bt_ctf_packet
*packet
; /* owned by this */
95 } set_stream_state_cur_packet
;
100 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
102 struct bt_notification_iterator
*iterator
= data
;
104 /* Remove associated stream state */
105 g_hash_table_remove(iterator
->stream_states
, stream
);
109 void destroy_stream_state(struct stream_state
*stream_state
)
115 bt_put(stream_state
->cur_packet
);
116 bt_put(stream_state
->stream
);
117 g_free(stream_state
);
121 void destroy_action(struct action
*action
)
125 switch (action
->type
) {
126 case ACTION_TYPE_PUSH_NOTIF
:
127 BT_PUT(action
->payload
.push_notif
.notif
);
129 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
130 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
131 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
132 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
134 case ACTION_TYPE_ADD_STREAM_STATE
:
135 BT_PUT(action
->payload
.add_stream_state
.stream
);
136 destroy_stream_state(
137 action
->payload
.add_stream_state
.stream_state
);
138 action
->payload
.add_stream_state
.stream_state
= NULL
;
140 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
141 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
143 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
151 void add_action(struct bt_notification_iterator
*iterator
,
152 struct action
*action
)
154 g_array_append_val(iterator
->actions
, *action
);
158 void clear_actions(struct bt_notification_iterator
*iterator
)
162 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
163 struct action
*action
= &g_array_index(iterator
->actions
,
166 destroy_action(action
);
169 g_array_set_size(iterator
->actions
, 0);
173 void apply_actions(struct bt_notification_iterator
*iterator
)
177 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
178 struct action
*action
= &g_array_index(iterator
->actions
,
181 switch (action
->type
) {
182 case ACTION_TYPE_PUSH_NOTIF
:
183 /* Move notification to queue */
184 g_queue_push_head(iterator
->queue
,
185 action
->payload
.push_notif
.notif
);
186 bt_notification_freeze(
187 action
->payload
.push_notif
.notif
);
188 action
->payload
.push_notif
.notif
= NULL
;
190 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
191 bt_ctf_stream_map_component_to_port(
192 action
->payload
.map_port_to_comp_in_stream
.stream
,
193 action
->payload
.map_port_to_comp_in_stream
.component
,
194 action
->payload
.map_port_to_comp_in_stream
.port
);
196 case ACTION_TYPE_ADD_STREAM_STATE
:
197 /* Move stream state to hash table */
198 g_hash_table_insert(iterator
->stream_states
,
199 action
->payload
.add_stream_state
.stream
,
200 action
->payload
.add_stream_state
.stream_state
);
202 action
->payload
.add_stream_state
.stream_state
= NULL
;
204 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
206 * We know that this stream is ended. We need to
207 * remember this as long as the stream exists to
208 * enforce that the same stream does not end
211 * Here we add a destroy listener to the stream
212 * which we put after (becomes weak as the hash
213 * table key). If we were the last object to own
214 * this stream, the destroy listener is called
215 * when we call bt_put() which removes this
216 * stream state completely. This is important
217 * because the memory used by this stream object
218 * could be reused for another stream, and they
219 * must have different states.
221 bt_ctf_stream_add_destroy_listener(
222 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
223 stream_destroy_listener
, iterator
);
224 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
225 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
227 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
228 /* Move packet to stream state's current packet */
229 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
230 action
->payload
.set_stream_state_cur_packet
.packet
);
237 clear_actions(iterator
);
241 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
243 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
250 * We keep a reference to the stream until we know it's ended
251 * because we need to be able to create an automatic "stream
252 * end" notification when the user's "next" method returns
253 * BT_NOTIFICATION_ITERATOR_STATUS_END.
255 * We put this reference when the stream is marked as ended.
257 stream_state
->stream
= bt_get(stream
);
264 void bt_notification_iterator_destroy(struct bt_object
*obj
)
266 struct bt_notification_iterator
*iterator
;
271 * The notification iterator's reference count is 0 if we're
272 * here. Increment it to avoid a double-destroy (possibly
273 * infinitely recursive). This could happen for example if the
274 * notification iterator's finalization function does bt_get()
275 * (or anything that causes bt_get() to be called) on itself
276 * (ref. count goes from 0 to 1), and then bt_put(): the
277 * reference count would go from 1 to 0 again and this function
278 * would be called again.
280 obj
->ref_count
.count
++;
281 iterator
= container_of(obj
, struct bt_notification_iterator
, base
);
282 bt_notification_iterator_finalize(iterator
);
284 if (iterator
->queue
) {
285 struct bt_notification
*notif
;
287 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
291 g_queue_free(iterator
->queue
);
294 if (iterator
->stream_states
) {
296 * Remove our destroy listener from each stream which
297 * has a state in this iterator. Otherwise the destroy
298 * listener would be called with an invalid/other
299 * notification iterator object.
301 GHashTableIter ht_iter
;
302 gpointer stream_gptr
, stream_state_gptr
;
304 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
306 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
308 bt_ctf_stream_remove_destroy_listener(
309 (void *) stream_gptr
, stream_destroy_listener
,
313 g_hash_table_destroy(iterator
->stream_states
);
316 if (iterator
->actions
) {
317 g_array_free(iterator
->actions
, TRUE
);
320 if (iterator
->connection
) {
322 * Remove ourself from the originating connection so
323 * that it does not try to finalize a dangling pointer
326 bt_connection_remove_iterator(iterator
->connection
, iterator
);
329 bt_put(iterator
->current_notification
);
334 void bt_notification_iterator_finalize(
335 struct bt_notification_iterator
*iterator
)
337 struct bt_component_class
*comp_class
= NULL
;
338 bt_component_class_notification_iterator_finalize_method
339 finalize_method
= NULL
;
343 switch (iterator
->state
) {
344 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
345 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
346 /* Already finalized */
352 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_ENDED
) {
353 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
355 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
358 assert(iterator
->upstream_component
);
359 comp_class
= iterator
->upstream_component
->class;
361 /* Call user-defined destroy method */
362 switch (comp_class
->type
) {
363 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
365 struct bt_component_class_source
*source_class
;
367 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
368 finalize_method
= source_class
->methods
.iterator
.finalize
;
371 case BT_COMPONENT_CLASS_TYPE_FILTER
:
373 struct bt_component_class_filter
*filter_class
;
375 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
376 finalize_method
= filter_class
->methods
.iterator
.finalize
;
384 if (finalize_method
) {
386 bt_private_notification_iterator_from_notification_iterator(iterator
));
389 iterator
->upstream_component
= NULL
;
390 iterator
->upstream_port
= NULL
;
394 void bt_notification_iterator_set_connection(
395 struct bt_notification_iterator
*iterator
,
396 struct bt_connection
*connection
)
399 iterator
->connection
= connection
;
403 int create_subscription_mask_from_notification_types(
404 struct bt_notification_iterator
*iterator
,
405 const enum bt_notification_type
*notif_types
)
407 const enum bt_notification_type
*notif_type
;
411 iterator
->subscription_mask
= 0;
413 for (notif_type
= notif_types
;
414 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
416 switch (*notif_type
) {
417 case BT_NOTIFICATION_TYPE_ALL
:
418 iterator
->subscription_mask
|=
419 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
420 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
421 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
422 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
423 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
424 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
426 case BT_NOTIFICATION_TYPE_EVENT
:
427 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
429 case BT_NOTIFICATION_TYPE_INACTIVITY
:
430 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
432 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
433 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
435 case BT_NOTIFICATION_TYPE_STREAM_END
:
436 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
438 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
439 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
441 case BT_NOTIFICATION_TYPE_PACKET_END
:
442 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
455 struct bt_notification_iterator
*bt_notification_iterator_create(
456 struct bt_component
*upstream_comp
,
457 struct bt_port
*upstream_port
,
458 const enum bt_notification_type
*notification_types
,
459 struct bt_connection
*connection
)
461 enum bt_component_class_type type
;
462 struct bt_notification_iterator
*iterator
= NULL
;
464 assert(upstream_comp
);
465 assert(upstream_port
);
466 assert(notification_types
);
467 assert(bt_port_is_connected(upstream_port
));
469 type
= bt_component_get_class_type(upstream_comp
);
470 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
471 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
472 iterator
= g_new0(struct bt_notification_iterator
, 1);
477 bt_object_init(iterator
, bt_notification_iterator_destroy
);
479 if (create_subscription_mask_from_notification_types(iterator
,
480 notification_types
)) {
484 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
485 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
486 if (!iterator
->stream_states
) {
490 iterator
->queue
= g_queue_new();
491 if (!iterator
->queue
) {
495 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
496 if (!iterator
->actions
) {
500 iterator
->upstream_component
= upstream_comp
;
501 iterator
->upstream_port
= upstream_port
;
502 iterator
->connection
= connection
;
503 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
;
514 enum bt_notification_iterator_status
bt_notification_iterator_validate(
515 struct bt_notification_iterator
*iterator
)
517 enum bt_notification_iterator_status ret
=
518 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
521 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
528 void *bt_private_notification_iterator_get_user_data(
529 struct bt_private_notification_iterator
*private_iterator
)
531 struct bt_notification_iterator
*iterator
=
532 bt_notification_iterator_from_private(private_iterator
);
534 return iterator
? iterator
->user_data
: NULL
;
537 enum bt_notification_iterator_status
538 bt_private_notification_iterator_set_user_data(
539 struct bt_private_notification_iterator
*private_iterator
,
542 enum bt_notification_iterator_status ret
=
543 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
544 struct bt_notification_iterator
*iterator
=
545 bt_notification_iterator_from_private(private_iterator
);
548 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
552 iterator
->user_data
= data
;
557 struct bt_notification
*bt_notification_iterator_get_notification(
558 struct bt_notification_iterator
*iterator
)
560 struct bt_notification
*notification
= NULL
;
566 notification
= bt_get(iterator
->current_notification
);
573 enum bt_notification_iterator_notif_type
574 bt_notification_iterator_notif_type_from_notif_type(
575 enum bt_notification_type notif_type
)
577 enum bt_notification_iterator_notif_type iter_notif_type
;
579 switch (notif_type
) {
580 case BT_NOTIFICATION_TYPE_EVENT
:
581 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
583 case BT_NOTIFICATION_TYPE_INACTIVITY
:
584 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
586 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
587 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
589 case BT_NOTIFICATION_TYPE_STREAM_END
:
590 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
592 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
593 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
595 case BT_NOTIFICATION_TYPE_PACKET_END
:
596 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
602 return iter_notif_type
;
606 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
607 struct bt_notification
*notif
,
608 struct bt_ctf_stream
*notif_stream
,
609 struct bt_ctf_packet
*notif_packet
)
611 bt_bool is_valid
= BT_TRUE
;
612 struct stream_state
*stream_state
;
613 struct bt_port
*stream_comp_cur_port
;
615 assert(notif_stream
);
616 stream_comp_cur_port
=
617 bt_ctf_stream_port_for_component(notif_stream
,
618 iterator
->upstream_component
);
619 if (!stream_comp_cur_port
) {
621 * This is the first time this notification iterator
622 * bumps into this stream. Add an action to map the
623 * iterator's upstream component to the iterator's
624 * upstream port in this stream.
626 struct action action
= {
627 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
628 .payload
.map_port_to_comp_in_stream
= {
629 .stream
= bt_get(notif_stream
),
630 .component
= bt_get(iterator
->upstream_component
),
631 .port
= bt_get(iterator
->upstream_port
),
635 add_action(iterator
, &action
);
637 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
639 * It looks like two different ports of the same
640 * component are emitting notifications which
641 * have references to the same stream. This is
642 * bad: the API guarantees that it can never
651 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
654 if (stream_state
->is_ended
) {
656 * There's a new notification which has a
657 * reference to a stream which, from this
658 * iterator's point of view, is ended ("end of
659 * stream" notification was returned). This is
660 * bad: the API guarantees that it can never
667 switch (notif
->type
) {
668 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
670 * We already have a stream state, which means
671 * we already returned a "stream begin"
672 * notification: this is an invalid duplicate.
676 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
677 if (notif_packet
== stream_state
->cur_packet
) {
678 /* Duplicate "packet begin" notification */
693 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
694 enum bt_notification_type notif_type
)
696 uint32_t iter_notif_type
=
697 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
700 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
704 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
705 struct bt_notification
*notif
)
707 struct action action
= {
708 .type
= ACTION_TYPE_PUSH_NOTIF
,
713 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
717 action
.payload
.push_notif
.notif
= bt_get(notif
);
718 add_action(iterator
, &action
);
722 int add_action_push_notif_stream_begin(
723 struct bt_notification_iterator
*iterator
,
724 struct bt_ctf_stream
*stream
)
727 struct bt_notification
*stream_begin_notif
= NULL
;
729 if (!is_subscribed_to_notification_type(iterator
,
730 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
735 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
736 if (!stream_begin_notif
) {
740 add_action_push_notif(iterator
, stream_begin_notif
);
747 bt_put(stream_begin_notif
);
752 int add_action_push_notif_stream_end(
753 struct bt_notification_iterator
*iterator
,
754 struct bt_ctf_stream
*stream
)
757 struct bt_notification
*stream_end_notif
= NULL
;
759 if (!is_subscribed_to_notification_type(iterator
,
760 BT_NOTIFICATION_TYPE_STREAM_END
)) {
765 stream_end_notif
= bt_notification_stream_end_create(stream
);
766 if (!stream_end_notif
) {
770 add_action_push_notif(iterator
, stream_end_notif
);
777 bt_put(stream_end_notif
);
782 int add_action_push_notif_packet_begin(
783 struct bt_notification_iterator
*iterator
,
784 struct bt_ctf_packet
*packet
)
787 struct bt_notification
*packet_begin_notif
= NULL
;
789 if (!is_subscribed_to_notification_type(iterator
,
790 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
795 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
796 if (!packet_begin_notif
) {
800 add_action_push_notif(iterator
, packet_begin_notif
);
807 bt_put(packet_begin_notif
);
812 int add_action_push_notif_packet_end(
813 struct bt_notification_iterator
*iterator
,
814 struct bt_ctf_packet
*packet
)
817 struct bt_notification
*packet_end_notif
= NULL
;
819 if (!is_subscribed_to_notification_type(iterator
,
820 BT_NOTIFICATION_TYPE_PACKET_END
)) {
825 packet_end_notif
= bt_notification_packet_end_create(packet
);
826 if (!packet_end_notif
) {
830 add_action_push_notif(iterator
, packet_end_notif
);
837 bt_put(packet_end_notif
);
842 void add_action_set_stream_state_is_ended(
843 struct bt_notification_iterator
*iterator
,
844 struct stream_state
*stream_state
)
846 struct action action
= {
847 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
848 .payload
.set_stream_state_is_ended
= {
849 .stream_state
= stream_state
,
853 assert(stream_state
);
854 add_action(iterator
, &action
);
858 void add_action_set_stream_state_cur_packet(
859 struct bt_notification_iterator
*iterator
,
860 struct stream_state
*stream_state
,
861 struct bt_ctf_packet
*packet
)
863 struct action action
= {
864 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
865 .payload
.set_stream_state_cur_packet
= {
866 .stream_state
= stream_state
,
867 .packet
= bt_get(packet
),
871 assert(stream_state
);
872 add_action(iterator
, &action
);
876 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
877 struct bt_notification
*stream_begin_notif
,
878 struct bt_ctf_stream
*notif_stream
,
879 struct stream_state
**stream_state
)
885 * The notification does not reference any stream: no
886 * need to get or create a stream state.
891 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
893 if (!*stream_state
) {
895 * This iterator did not bump into this stream yet:
896 * create a stream state and a "stream begin"
899 struct action action
= {
900 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
901 .payload
.add_stream_state
= {
902 .stream
= bt_get(notif_stream
),
903 .stream_state
= NULL
,
907 *stream_state
= create_stream_state(notif_stream
);
912 action
.payload
.add_stream_state
.stream_state
=
914 add_action(iterator
, &action
);
916 if (stream_begin_notif
) {
917 add_action_push_notif(iterator
, stream_begin_notif
);
919 ret
= add_action_push_notif_stream_begin(iterator
,
930 destroy_stream_state(*stream_state
);
938 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
939 struct bt_notification
*packet_begin_notif
,
940 struct bt_ctf_packet
*new_packet
,
941 struct stream_state
*stream_state
)
945 if (stream_state
->cur_packet
== new_packet
) {
949 if (stream_state
->cur_packet
) {
950 /* End of the current packet */
951 ret
= add_action_push_notif_packet_end(iterator
,
952 stream_state
->cur_packet
);
958 /* Beginning of the new packet */
959 if (packet_begin_notif
) {
960 add_action_push_notif(iterator
, packet_begin_notif
);
961 } else if (new_packet
) {
962 ret
= add_action_push_notif_packet_begin(iterator
,
969 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
981 int handle_notif_stream_begin(
982 struct bt_notification_iterator
*iterator
,
983 struct bt_notification
*notif
,
984 struct bt_ctf_stream
*notif_stream
)
987 struct stream_state
*stream_state
;
989 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
990 assert(notif_stream
);
991 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1007 int handle_notif_stream_end(
1008 struct bt_notification_iterator
*iterator
,
1009 struct bt_notification
*notif
,
1010 struct bt_ctf_stream
*notif_stream
)
1013 struct stream_state
*stream_state
;
1015 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1016 assert(notif_stream
);
1017 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1023 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1028 add_action_push_notif(iterator
, notif
);
1029 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1040 int handle_notif_packet_begin(
1041 struct bt_notification_iterator
*iterator
,
1042 struct bt_notification
*notif
,
1043 struct bt_ctf_stream
*notif_stream
,
1044 struct bt_ctf_packet
*notif_packet
)
1047 struct stream_state
*stream_state
;
1049 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1050 assert(notif_packet
);
1051 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1057 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1072 int handle_notif_packet_end(
1073 struct bt_notification_iterator
*iterator
,
1074 struct bt_notification
*notif
,
1075 struct bt_ctf_stream
*notif_stream
,
1076 struct bt_ctf_packet
*notif_packet
)
1079 struct stream_state
*stream_state
;
1081 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1082 assert(notif_packet
);
1083 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1089 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1094 /* End of the current packet */
1095 add_action_push_notif(iterator
, notif
);
1096 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1107 int handle_notif_event(
1108 struct bt_notification_iterator
*iterator
,
1109 struct bt_notification
*notif
,
1110 struct bt_ctf_stream
*notif_stream
,
1111 struct bt_ctf_packet
*notif_packet
)
1114 struct stream_state
*stream_state
;
1116 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1117 assert(notif_packet
);
1118 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1124 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1129 add_action_push_notif(iterator
, notif
);
1140 int enqueue_notification_and_automatic(
1141 struct bt_notification_iterator
*iterator
,
1142 struct bt_notification
*notif
)
1145 struct bt_ctf_event
*notif_event
= NULL
;
1146 struct bt_ctf_stream
*notif_stream
= NULL
;
1147 struct bt_ctf_packet
*notif_packet
= NULL
;
1151 // TODO: Skip most of this if the iterator is only subscribed
1152 // to event/inactivity notifications.
1154 /* Get the stream and packet referred by the notification */
1155 switch (notif
->type
) {
1156 case BT_NOTIFICATION_TYPE_EVENT
:
1157 notif_event
= bt_notification_event_borrow_event(notif
);
1158 assert(notif_event
);
1159 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1160 assert(notif_packet
);
1162 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1164 bt_notification_stream_begin_borrow_stream(notif
);
1165 assert(notif_stream
);
1167 case BT_NOTIFICATION_TYPE_STREAM_END
:
1168 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1169 assert(notif_stream
);
1171 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1173 bt_notification_packet_begin_borrow_packet(notif
);
1174 assert(notif_packet
);
1176 case BT_NOTIFICATION_TYPE_PACKET_END
:
1177 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1178 assert(notif_packet
);
1180 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1185 * Invalid type of notification. Only the notification
1186 * types above are allowed to be returned by a user
1193 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1194 assert(notif_stream
);
1197 if (!notif_stream
) {
1199 * The notification has no reference to a stream: it
1200 * cannot cause the creation of automatic notifications.
1205 if (!validate_notification(iterator
, notif
, notif_stream
,
1211 switch (notif
->type
) {
1212 case BT_NOTIFICATION_TYPE_EVENT
:
1213 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1216 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1217 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1219 case BT_NOTIFICATION_TYPE_STREAM_END
:
1220 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1222 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1223 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1226 case BT_NOTIFICATION_TYPE_PACKET_END
:
1227 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1230 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1231 add_action_push_notif(iterator
, notif
);
1241 apply_actions(iterator
);
1252 int handle_end(struct bt_notification_iterator
*iterator
)
1254 GHashTableIter stream_state_iter
;
1255 gpointer stream_gptr
, stream_state_gptr
;
1259 * Emit a "stream end" notification for each non-ended stream
1260 * known by this iterator and mark them as ended.
1262 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1264 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1265 &stream_state_gptr
)) {
1266 struct stream_state
*stream_state
= stream_state_gptr
;
1268 assert(stream_state_gptr
);
1270 if (stream_state
->is_ended
) {
1274 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1279 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1284 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1287 apply_actions(iterator
);
1298 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1299 struct bt_notification_iterator
*iterator
)
1301 struct bt_private_notification_iterator
*priv_iterator
=
1302 bt_private_notification_iterator_from_notification_iterator(iterator
);
1303 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1304 struct bt_notification_iterator_next_return next_return
= {
1305 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1306 .notification
= NULL
,
1308 enum bt_notification_iterator_status status
=
1309 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1314 if (iterator
->queue
->length
> 0) {
1315 /* We already have enough */
1319 switch (iterator
->state
) {
1320 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
1321 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1323 case BT_NOTIFICATION_ITERATOR_STATE_ENDED
:
1324 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1330 assert(iterator
->upstream_component
);
1331 assert(iterator
->upstream_component
->class);
1333 /* Pick the appropriate "next" method */
1334 switch (iterator
->upstream_component
->class->type
) {
1335 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1337 struct bt_component_class_source
*source_class
=
1338 container_of(iterator
->upstream_component
->class,
1339 struct bt_component_class_source
, parent
);
1341 assert(source_class
->methods
.iterator
.next
);
1342 next_method
= source_class
->methods
.iterator
.next
;
1345 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1347 struct bt_component_class_filter
*filter_class
=
1348 container_of(iterator
->upstream_component
->class,
1349 struct bt_component_class_filter
, parent
);
1351 assert(filter_class
->methods
.iterator
.next
);
1352 next_method
= filter_class
->methods
.iterator
.next
;
1361 * Call the user's "next" method to get the next notification
1364 assert(next_method
);
1366 while (iterator
->queue
->length
== 0) {
1367 next_return
= next_method(priv_iterator
);
1368 if (next_return
.status
< 0) {
1369 status
= next_return
.status
;
1373 switch (next_return
.status
) {
1374 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1375 ret
= handle_end(iterator
);
1377 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1381 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
) {
1383 BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
1385 if (iterator
->queue
->length
== 0) {
1386 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1390 BT_NOTIFICATION_ITERATOR_STATE_ENDED
;
1392 if (iterator
->queue
->length
== 0) {
1393 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1397 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1398 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1400 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1401 if (!next_return
.notification
) {
1402 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1407 * We know the notification is valid. Before we
1408 * push it to the head of the queue, push the
1409 * appropriate automatic notifications if any.
1411 ret
= enqueue_notification_and_automatic(iterator
,
1412 next_return
.notification
);
1413 BT_PUT(next_return
.notification
);
1415 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1420 /* Unknown non-error status */
1429 enum bt_notification_iterator_status
1430 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1432 enum bt_notification_iterator_status status
;
1435 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1440 * Make sure that the iterator's queue contains at least one
1443 status
= ensure_queue_has_notifications(iterator
);
1444 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1449 * Move the notification at the tail of the queue to the
1450 * iterator's current notification.
1452 assert(iterator
->queue
->length
> 0);
1453 bt_put(iterator
->current_notification
);
1454 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1455 assert(iterator
->current_notification
);
1461 struct bt_component
*bt_notification_iterator_get_component(
1462 struct bt_notification_iterator
*iterator
)
1464 return bt_get(iterator
->upstream_component
);
1467 struct bt_private_component
*
1468 bt_private_notification_iterator_get_private_component(
1469 struct bt_private_notification_iterator
*private_iterator
)
1471 return bt_private_component_from_component(
1472 bt_notification_iterator_get_component(
1473 bt_notification_iterator_from_private(private_iterator
)));
1476 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1477 struct bt_notification_iterator
*iterator
,
1478 enum bt_notification_iterator_seek_origin seek_origin
,
1481 enum bt_notification_iterator_status ret
=
1482 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;