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/component.h>
34 #include <babeltrace/graph/component-source-internal.h>
35 #include <babeltrace/graph/component-class-internal.h>
36 #include <babeltrace/graph/notification.h>
37 #include <babeltrace/graph/notification-iterator.h>
38 #include <babeltrace/graph/notification-iterator-internal.h>
39 #include <babeltrace/graph/notification-internal.h>
40 #include <babeltrace/graph/notification-event.h>
41 #include <babeltrace/graph/notification-event-internal.h>
42 #include <babeltrace/graph/notification-packet.h>
43 #include <babeltrace/graph/notification-packet-internal.h>
44 #include <babeltrace/graph/notification-stream.h>
45 #include <babeltrace/graph/notification-stream-internal.h>
46 #include <babeltrace/graph/port.h>
50 struct bt_ctf_stream
*stream
; /* owned by this */
51 struct bt_ctf_packet
*cur_packet
; /* owned by this */
56 ACTION_TYPE_PUSH_NOTIF
,
57 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
58 ACTION_TYPE_ADD_STREAM_STATE
,
59 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
60 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
64 enum action_type type
;
66 /* ACTION_TYPE_PUSH_NOTIF */
68 struct bt_notification
*notif
; /* owned by this */
71 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
73 struct bt_ctf_stream
*stream
; /* owned by this */
74 struct bt_component
*component
; /* owned by this */
75 struct bt_port
*port
; /* owned by this */
76 } map_port_to_comp_in_stream
;
78 /* ACTION_TYPE_ADD_STREAM_STATE */
80 struct bt_ctf_stream
*stream
; /* owned by this */
81 struct stream_state
*stream_state
; /* owned by this */
84 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
86 struct stream_state
*stream_state
; /* weak */
87 } set_stream_state_is_ended
;
89 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
91 struct stream_state
*stream_state
; /* weak */
92 struct bt_ctf_packet
*packet
; /* owned by this */
93 } set_stream_state_cur_packet
;
98 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
100 struct bt_notification_iterator
*iterator
= data
;
102 /* Remove associated stream state */
103 g_hash_table_remove(iterator
->stream_states
, stream
);
107 void destroy_stream_state(struct stream_state
*stream_state
)
113 bt_put(stream_state
->cur_packet
);
114 bt_put(stream_state
->stream
);
115 g_free(stream_state
);
119 void destroy_action(struct action
*action
)
123 switch (action
->type
) {
124 case ACTION_TYPE_PUSH_NOTIF
:
125 BT_PUT(action
->payload
.push_notif
.notif
);
127 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
128 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
129 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
130 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
132 case ACTION_TYPE_ADD_STREAM_STATE
:
133 BT_PUT(action
->payload
.add_stream_state
.stream
);
134 destroy_stream_state(
135 action
->payload
.add_stream_state
.stream_state
);
136 action
->payload
.add_stream_state
.stream_state
= NULL
;
138 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
139 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
141 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
149 void add_action(struct bt_notification_iterator
*iterator
,
150 struct action
*action
)
152 g_array_append_val(iterator
->actions
, *action
);
156 void clear_actions(struct bt_notification_iterator
*iterator
)
160 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
161 struct action
*action
= &g_array_index(iterator
->actions
,
164 destroy_action(action
);
167 g_array_set_size(iterator
->actions
, 0);
171 void apply_actions(struct bt_notification_iterator
*iterator
)
175 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
176 struct action
*action
= &g_array_index(iterator
->actions
,
179 switch (action
->type
) {
180 case ACTION_TYPE_PUSH_NOTIF
:
181 /* Move notification to queue */
182 g_queue_push_head(iterator
->queue
,
183 action
->payload
.push_notif
.notif
);
184 bt_notification_freeze(
185 action
->payload
.push_notif
.notif
);
186 action
->payload
.push_notif
.notif
= NULL
;
188 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
189 bt_ctf_stream_map_component_to_port(
190 action
->payload
.map_port_to_comp_in_stream
.stream
,
191 action
->payload
.map_port_to_comp_in_stream
.component
,
192 action
->payload
.map_port_to_comp_in_stream
.port
);
194 case ACTION_TYPE_ADD_STREAM_STATE
:
195 /* Move stream state to hash table */
196 g_hash_table_insert(iterator
->stream_states
,
197 action
->payload
.add_stream_state
.stream
,
198 action
->payload
.add_stream_state
.stream_state
);
200 action
->payload
.add_stream_state
.stream_state
= NULL
;
202 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
204 * We know that this stream is ended. We need to
205 * remember this as long as the stream exists to
206 * enforce that the same stream does not end
209 * Here we add a destroy listener to the stream
210 * which we put after (becomes weak as the hash
211 * table key). If we were the last object to own
212 * this stream, the destroy listener is called
213 * when we call bt_put() which removes this
214 * stream state completely. This is important
215 * because the memory used by this stream object
216 * could be reused for another stream, and they
217 * must have different states.
219 bt_ctf_stream_add_destroy_listener(
220 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
221 stream_destroy_listener
, iterator
);
222 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= true;
223 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
225 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
226 /* Move packet to stream state's current packet */
227 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
228 action
->payload
.set_stream_state_cur_packet
.packet
);
235 clear_actions(iterator
);
239 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
241 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
248 * We keep a reference to the stream until we know it's ended
249 * because we need to be able to create an automatic "stream
250 * end" notification when the user's "next" method returns
251 * BT_NOTIFICATION_ITERATOR_STATUS_END.
253 * We put this reference when the stream is marked as ended.
255 stream_state
->stream
= bt_get(stream
);
262 void bt_notification_iterator_destroy(struct bt_object
*obj
)
264 struct bt_notification_iterator
*iterator
;
265 struct bt_component_class
*comp_class
;
268 iterator
= container_of(obj
, struct bt_notification_iterator
,
270 assert(iterator
->upstream_component
);
271 comp_class
= iterator
->upstream_component
->class;
273 /* Call user-defined destroy method */
274 switch (comp_class
->type
) {
275 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
277 struct bt_component_class_source
*source_class
;
279 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
281 if (source_class
->methods
.iterator
.finalize
) {
282 source_class
->methods
.iterator
.finalize(
283 bt_private_notification_iterator_from_notification_iterator(iterator
));
287 case BT_COMPONENT_CLASS_TYPE_FILTER
:
289 struct bt_component_class_filter
*filter_class
;
291 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
293 if (filter_class
->methods
.iterator
.finalize
) {
294 filter_class
->methods
.iterator
.finalize(
295 bt_private_notification_iterator_from_notification_iterator(iterator
));
304 if (iterator
->queue
) {
305 struct bt_notification
*notif
;
307 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
311 g_queue_free(iterator
->queue
);
314 if (iterator
->stream_states
) {
316 * Remove our destroy listener from each stream which
317 * has a state in this iterator. Otherwise the destroy
318 * listener would be called with an invalid/other
319 * notification iterator object.
321 GHashTableIter ht_iter
;
322 gpointer stream_gptr
, stream_state_gptr
;
324 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
326 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
328 bt_ctf_stream_remove_destroy_listener(
329 (void *) stream_gptr
, stream_destroy_listener
,
333 g_hash_table_destroy(iterator
->stream_states
);
336 if (iterator
->actions
) {
337 g_array_free(iterator
->actions
, TRUE
);
340 bt_put(iterator
->current_notification
);
341 bt_put(iterator
->upstream_component
);
342 bt_put(iterator
->upstream_port
);
347 int create_subscription_mask_from_notification_types(
348 struct bt_notification_iterator
*iterator
,
349 const enum bt_notification_type
*notif_types
)
351 const enum bt_notification_type
*notif_type
;
355 iterator
->subscription_mask
= 0;
357 for (notif_type
= notif_types
;
358 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
360 switch (*notif_type
) {
361 case BT_NOTIFICATION_TYPE_ALL
:
362 iterator
->subscription_mask
|=
363 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
364 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
365 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
366 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
367 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
368 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
370 case BT_NOTIFICATION_TYPE_EVENT
:
371 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
373 case BT_NOTIFICATION_TYPE_INACTIVITY
:
374 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
376 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
377 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
379 case BT_NOTIFICATION_TYPE_STREAM_END
:
380 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
382 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
383 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
385 case BT_NOTIFICATION_TYPE_PACKET_END
:
386 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
399 struct bt_notification_iterator
*bt_notification_iterator_create(
400 struct bt_component
*upstream_comp
,
401 struct bt_port
*upstream_port
,
402 const enum bt_notification_type
*notification_types
)
404 enum bt_component_class_type type
;
405 struct bt_notification_iterator
*iterator
= NULL
;
407 assert(upstream_comp
);
408 assert(upstream_port
);
409 assert(notification_types
);
410 assert(bt_port_is_connected(upstream_port
));
412 type
= bt_component_get_class_type(upstream_comp
);
414 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
415 case BT_COMPONENT_CLASS_TYPE_FILTER
:
421 iterator
= g_new0(struct bt_notification_iterator
, 1);
426 bt_object_init(iterator
, bt_notification_iterator_destroy
);
428 if (create_subscription_mask_from_notification_types(iterator
,
429 notification_types
)) {
433 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
434 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
435 if (!iterator
->stream_states
) {
439 iterator
->queue
= g_queue_new();
440 if (!iterator
->queue
) {
444 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
445 if (!iterator
->actions
) {
449 iterator
->upstream_component
= bt_get(upstream_comp
);
450 iterator
->upstream_port
= bt_get(upstream_port
);
461 enum bt_notification_iterator_status
bt_notification_iterator_validate(
462 struct bt_notification_iterator
*iterator
)
464 enum bt_notification_iterator_status ret
=
465 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
468 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
475 void *bt_private_notification_iterator_get_user_data(
476 struct bt_private_notification_iterator
*private_iterator
)
478 struct bt_notification_iterator
*iterator
=
479 bt_notification_iterator_from_private(private_iterator
);
481 return iterator
? iterator
->user_data
: NULL
;
484 enum bt_notification_iterator_status
485 bt_private_notification_iterator_set_user_data(
486 struct bt_private_notification_iterator
*private_iterator
,
489 enum bt_notification_iterator_status ret
=
490 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
491 struct bt_notification_iterator
*iterator
=
492 bt_notification_iterator_from_private(private_iterator
);
495 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
499 iterator
->user_data
= data
;
504 struct bt_notification
*bt_notification_iterator_get_notification(
505 struct bt_notification_iterator
*iterator
)
507 struct bt_notification
*notification
= NULL
;
513 notification
= bt_get(iterator
->current_notification
);
520 enum bt_notification_iterator_notif_type
521 bt_notification_iterator_notif_type_from_notif_type(
522 enum bt_notification_type notif_type
)
524 enum bt_notification_iterator_notif_type iter_notif_type
;
526 switch (notif_type
) {
527 case BT_NOTIFICATION_TYPE_EVENT
:
528 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
530 case BT_NOTIFICATION_TYPE_INACTIVITY
:
531 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
533 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
534 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
536 case BT_NOTIFICATION_TYPE_STREAM_END
:
537 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
539 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
540 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
542 case BT_NOTIFICATION_TYPE_PACKET_END
:
543 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
549 return iter_notif_type
;
553 bool validate_notification(struct bt_notification_iterator
*iterator
,
554 struct bt_notification
*notif
,
555 struct bt_ctf_stream
*notif_stream
,
556 struct bt_ctf_packet
*notif_packet
)
558 bool is_valid
= true;
559 struct stream_state
*stream_state
;
560 struct bt_port
*stream_comp_cur_port
;
562 assert(notif_stream
);
563 stream_comp_cur_port
=
564 bt_ctf_stream_port_for_component(notif_stream
,
565 iterator
->upstream_component
);
566 if (!stream_comp_cur_port
) {
568 * This is the first time this notification iterator
569 * bumps into this stream. Add an action to map the
570 * iterator's upstream component to the iterator's
571 * upstream port in this stream.
573 struct action action
= {
574 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
575 .payload
.map_port_to_comp_in_stream
= {
576 .stream
= bt_get(notif_stream
),
577 .component
= bt_get(iterator
->upstream_component
),
578 .port
= bt_get(iterator
->upstream_port
),
582 add_action(iterator
, &action
);
584 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
586 * It looks like two different ports of the same
587 * component are emitting notifications which
588 * have references to the same stream. This is
589 * bad: the API guarantees that it can never
598 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
601 if (stream_state
->is_ended
) {
603 * There's a new notification which has a
604 * reference to a stream which, from this
605 * iterator's point of view, is ended ("end of
606 * stream" notification was returned). This is
607 * bad: the API guarantees that it can never
614 switch (notif
->type
) {
615 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
617 * We already have a stream state, which means
618 * we already returned a "stream begin"
619 * notification: this is an invalid duplicate.
623 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
624 if (notif_packet
== stream_state
->cur_packet
) {
625 /* Duplicate "packet begin" notification */
640 bool is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
641 enum bt_notification_type notif_type
)
643 uint32_t iter_notif_type
=
644 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
647 return (iter_notif_type
& iterator
->subscription_mask
) ? true : false;
651 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
652 struct bt_notification
*notif
)
654 struct action action
= {
655 .type
= ACTION_TYPE_PUSH_NOTIF
,
660 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
664 action
.payload
.push_notif
.notif
= bt_get(notif
);
665 add_action(iterator
, &action
);
669 int add_action_push_notif_stream_begin(
670 struct bt_notification_iterator
*iterator
,
671 struct bt_ctf_stream
*stream
)
674 struct bt_notification
*stream_begin_notif
= NULL
;
676 if (!is_subscribed_to_notification_type(iterator
,
677 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
682 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
683 if (!stream_begin_notif
) {
687 add_action_push_notif(iterator
, stream_begin_notif
);
694 bt_put(stream_begin_notif
);
699 int add_action_push_notif_stream_end(
700 struct bt_notification_iterator
*iterator
,
701 struct bt_ctf_stream
*stream
)
704 struct bt_notification
*stream_end_notif
= NULL
;
706 if (!is_subscribed_to_notification_type(iterator
,
707 BT_NOTIFICATION_TYPE_STREAM_END
)) {
712 stream_end_notif
= bt_notification_stream_end_create(stream
);
713 if (!stream_end_notif
) {
717 add_action_push_notif(iterator
, stream_end_notif
);
724 bt_put(stream_end_notif
);
729 int add_action_push_notif_packet_begin(
730 struct bt_notification_iterator
*iterator
,
731 struct bt_ctf_packet
*packet
)
734 struct bt_notification
*packet_begin_notif
= NULL
;
736 if (!is_subscribed_to_notification_type(iterator
,
737 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
742 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
743 if (!packet_begin_notif
) {
747 add_action_push_notif(iterator
, packet_begin_notif
);
754 bt_put(packet_begin_notif
);
759 int add_action_push_notif_packet_end(
760 struct bt_notification_iterator
*iterator
,
761 struct bt_ctf_packet
*packet
)
764 struct bt_notification
*packet_end_notif
= NULL
;
766 if (!is_subscribed_to_notification_type(iterator
,
767 BT_NOTIFICATION_TYPE_PACKET_END
)) {
772 packet_end_notif
= bt_notification_packet_end_create(packet
);
773 if (!packet_end_notif
) {
777 add_action_push_notif(iterator
, packet_end_notif
);
784 bt_put(packet_end_notif
);
789 void add_action_set_stream_state_is_ended(
790 struct bt_notification_iterator
*iterator
,
791 struct stream_state
*stream_state
)
793 struct action action
= {
794 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
795 .payload
.set_stream_state_is_ended
= {
796 .stream_state
= stream_state
,
800 assert(stream_state
);
801 add_action(iterator
, &action
);
805 void add_action_set_stream_state_cur_packet(
806 struct bt_notification_iterator
*iterator
,
807 struct stream_state
*stream_state
,
808 struct bt_ctf_packet
*packet
)
810 struct action action
= {
811 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
812 .payload
.set_stream_state_cur_packet
= {
813 .stream_state
= stream_state
,
814 .packet
= bt_get(packet
),
818 assert(stream_state
);
819 add_action(iterator
, &action
);
823 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
824 struct bt_notification
*stream_begin_notif
,
825 struct bt_ctf_stream
*notif_stream
,
826 struct stream_state
**stream_state
)
832 * The notification does not reference any stream: no
833 * need to get or create a stream state.
838 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
840 if (!*stream_state
) {
842 * This iterator did not bump into this stream yet:
843 * create a stream state and a "stream begin"
846 struct action action
= {
847 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
848 .payload
.add_stream_state
= {
849 .stream
= bt_get(notif_stream
),
850 .stream_state
= NULL
,
854 *stream_state
= create_stream_state(notif_stream
);
859 action
.payload
.add_stream_state
.stream_state
=
861 add_action(iterator
, &action
);
863 if (stream_begin_notif
) {
864 add_action_push_notif(iterator
, stream_begin_notif
);
866 ret
= add_action_push_notif_stream_begin(iterator
,
877 destroy_stream_state(*stream_state
);
885 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
886 struct bt_notification
*packet_begin_notif
,
887 struct bt_ctf_packet
*new_packet
,
888 struct stream_state
*stream_state
)
892 if (stream_state
->cur_packet
== new_packet
) {
896 if (stream_state
->cur_packet
) {
897 /* End of the current packet */
898 ret
= add_action_push_notif_packet_end(iterator
,
899 stream_state
->cur_packet
);
905 /* Beginning of the new packet */
906 if (packet_begin_notif
) {
907 add_action_push_notif(iterator
, packet_begin_notif
);
908 } else if (new_packet
) {
909 ret
= add_action_push_notif_packet_begin(iterator
,
916 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
928 int handle_notif_stream_begin(
929 struct bt_notification_iterator
*iterator
,
930 struct bt_notification
*notif
,
931 struct bt_ctf_stream
*notif_stream
)
934 struct stream_state
*stream_state
;
936 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
937 assert(notif_stream
);
938 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
954 int handle_notif_stream_end(
955 struct bt_notification_iterator
*iterator
,
956 struct bt_notification
*notif
,
957 struct bt_ctf_stream
*notif_stream
)
960 struct stream_state
*stream_state
;
962 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
963 assert(notif_stream
);
964 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
970 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
975 add_action_push_notif(iterator
, notif
);
976 add_action_set_stream_state_is_ended(iterator
, stream_state
);
987 int handle_notif_packet_begin(
988 struct bt_notification_iterator
*iterator
,
989 struct bt_notification
*notif
,
990 struct bt_ctf_stream
*notif_stream
,
991 struct bt_ctf_packet
*notif_packet
)
994 struct stream_state
*stream_state
;
996 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
997 assert(notif_packet
);
998 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1004 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1019 int handle_notif_packet_end(
1020 struct bt_notification_iterator
*iterator
,
1021 struct bt_notification
*notif
,
1022 struct bt_ctf_stream
*notif_stream
,
1023 struct bt_ctf_packet
*notif_packet
)
1026 struct stream_state
*stream_state
;
1028 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1029 assert(notif_packet
);
1030 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1036 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1041 /* End of the current packet */
1042 add_action_push_notif(iterator
, notif
);
1043 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1054 int handle_notif_event(
1055 struct bt_notification_iterator
*iterator
,
1056 struct bt_notification
*notif
,
1057 struct bt_ctf_stream
*notif_stream
,
1058 struct bt_ctf_packet
*notif_packet
)
1061 struct stream_state
*stream_state
;
1063 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1064 assert(notif_packet
);
1065 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1071 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1076 add_action_push_notif(iterator
, notif
);
1087 int enqueue_notification_and_automatic(
1088 struct bt_notification_iterator
*iterator
,
1089 struct bt_notification
*notif
)
1092 struct bt_ctf_event
*notif_event
= NULL
;
1093 struct bt_ctf_stream
*notif_stream
= NULL
;
1094 struct bt_ctf_packet
*notif_packet
= NULL
;
1098 // TODO: Skip most of this if the iterator is only subscribed
1099 // to event/inactivity notifications.
1101 /* Get the stream and packet referred by the notification */
1102 switch (notif
->type
) {
1103 case BT_NOTIFICATION_TYPE_EVENT
:
1104 notif_event
= bt_notification_event_borrow_event(notif
);
1105 assert(notif_event
);
1106 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1107 assert(notif_packet
);
1109 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1111 bt_notification_stream_begin_borrow_stream(notif
);
1112 assert(notif_stream
);
1114 case BT_NOTIFICATION_TYPE_STREAM_END
:
1115 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1116 assert(notif_stream
);
1118 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1120 bt_notification_packet_begin_borrow_packet(notif
);
1121 assert(notif_packet
);
1123 case BT_NOTIFICATION_TYPE_PACKET_END
:
1124 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1125 assert(notif_packet
);
1127 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1132 * Invalid type of notification. Only the notification
1133 * types above are allowed to be returned by a user
1140 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1141 assert(notif_stream
);
1144 if (!notif_stream
) {
1146 * The notification has no reference to a stream: it
1147 * cannot cause the creation of automatic notifications.
1152 if (!validate_notification(iterator
, notif
, notif_stream
,
1157 switch (notif
->type
) {
1158 case BT_NOTIFICATION_TYPE_EVENT
:
1159 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1162 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1163 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1165 case BT_NOTIFICATION_TYPE_STREAM_END
:
1166 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1168 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1169 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1172 case BT_NOTIFICATION_TYPE_PACKET_END
:
1173 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1184 apply_actions(iterator
);
1195 int handle_end(struct bt_notification_iterator
*iterator
)
1197 GHashTableIter stream_state_iter
;
1198 gpointer stream_gptr
, stream_state_gptr
;
1202 * Emit a "stream end" notification for each non-ended stream
1203 * known by this iterator and mark them as ended.
1205 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1207 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1208 &stream_state_gptr
)) {
1209 struct stream_state
*stream_state
= stream_state_gptr
;
1211 assert(stream_state_gptr
);
1213 if (stream_state
->is_ended
) {
1217 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1222 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1227 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1230 apply_actions(iterator
);
1241 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1242 struct bt_notification_iterator
*iterator
)
1244 struct bt_private_notification_iterator
*priv_iterator
=
1245 bt_private_notification_iterator_from_notification_iterator(iterator
);
1246 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1247 struct bt_notification_iterator_next_return next_return
= {
1248 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1249 .notification
= NULL
,
1251 enum bt_notification_iterator_status status
=
1252 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1257 if (iterator
->queue
->length
> 0) {
1258 /* We already have enough */
1262 if (iterator
->is_ended
) {
1263 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1267 assert(iterator
->upstream_component
);
1268 assert(iterator
->upstream_component
->class);
1270 /* Pick the appropriate "next" method */
1271 switch (iterator
->upstream_component
->class->type
) {
1272 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1274 struct bt_component_class_source
*source_class
=
1275 container_of(iterator
->upstream_component
->class,
1276 struct bt_component_class_source
, parent
);
1278 assert(source_class
->methods
.iterator
.next
);
1279 next_method
= source_class
->methods
.iterator
.next
;
1282 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1284 struct bt_component_class_filter
*filter_class
=
1285 container_of(iterator
->upstream_component
->class,
1286 struct bt_component_class_filter
, parent
);
1288 assert(filter_class
->methods
.iterator
.next
);
1289 next_method
= filter_class
->methods
.iterator
.next
;
1298 * Call the user's "next" method to get the next notification
1301 assert(next_method
);
1303 while (iterator
->queue
->length
== 0) {
1304 next_return
= next_method(priv_iterator
);
1305 if (next_return
.status
< 0) {
1306 status
= next_return
.status
;
1310 switch (next_return
.status
) {
1311 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1312 ret
= handle_end(iterator
);
1314 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1318 if (iterator
->queue
->length
== 0) {
1319 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1322 iterator
->is_ended
= true;
1324 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1325 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1327 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1328 if (!next_return
.notification
) {
1329 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1334 * We know the notification is valid. Before we
1335 * push it to the head of the queue, push the
1336 * appropriate automatic notifications if any.
1338 ret
= enqueue_notification_and_automatic(iterator
,
1339 next_return
.notification
);
1340 BT_PUT(next_return
.notification
);
1342 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1347 /* Unknown non-error status */
1356 enum bt_notification_iterator_status
1357 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1359 enum bt_notification_iterator_status status
;
1362 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1367 * Make sure that the iterator's queue contains at least one
1370 status
= ensure_queue_has_notifications(iterator
);
1371 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1376 * Move the notification at the tail of the queue to the
1377 * iterator's current notification.
1379 assert(iterator
->queue
->length
> 0);
1380 bt_put(iterator
->current_notification
);
1381 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1382 assert(iterator
->current_notification
);
1388 struct bt_component
*bt_notification_iterator_get_component(
1389 struct bt_notification_iterator
*iterator
)
1391 return bt_get(iterator
->upstream_component
);
1394 struct bt_private_component
*
1395 bt_private_notification_iterator_get_private_component(
1396 struct bt_private_notification_iterator
*private_iterator
)
1398 return bt_private_component_from_component(
1399 bt_notification_iterator_get_component(
1400 bt_notification_iterator_from_private(private_iterator
)));
1403 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1404 struct bt_notification_iterator
*iterator
,
1405 enum bt_notification_iterator_seek_origin seek_origin
,
1408 enum bt_notification_iterator_status ret
=
1409 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;