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>
47 #include <babeltrace/types.h>
51 struct bt_ctf_stream
*stream
; /* owned by this */
52 struct bt_ctf_packet
*cur_packet
; /* owned by this */
57 ACTION_TYPE_PUSH_NOTIF
,
58 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
59 ACTION_TYPE_ADD_STREAM_STATE
,
60 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
61 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
65 enum action_type type
;
67 /* ACTION_TYPE_PUSH_NOTIF */
69 struct bt_notification
*notif
; /* owned by this */
72 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
74 struct bt_ctf_stream
*stream
; /* owned by this */
75 struct bt_component
*component
; /* owned by this */
76 struct bt_port
*port
; /* owned by this */
77 } map_port_to_comp_in_stream
;
79 /* ACTION_TYPE_ADD_STREAM_STATE */
81 struct bt_ctf_stream
*stream
; /* owned by this */
82 struct stream_state
*stream_state
; /* owned by this */
85 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
87 struct stream_state
*stream_state
; /* weak */
88 } set_stream_state_is_ended
;
90 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
92 struct stream_state
*stream_state
; /* weak */
93 struct bt_ctf_packet
*packet
; /* owned by this */
94 } set_stream_state_cur_packet
;
99 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
101 struct bt_notification_iterator
*iterator
= data
;
103 /* Remove associated stream state */
104 g_hash_table_remove(iterator
->stream_states
, stream
);
108 void destroy_stream_state(struct stream_state
*stream_state
)
114 bt_put(stream_state
->cur_packet
);
115 bt_put(stream_state
->stream
);
116 g_free(stream_state
);
120 void destroy_action(struct action
*action
)
124 switch (action
->type
) {
125 case ACTION_TYPE_PUSH_NOTIF
:
126 BT_PUT(action
->payload
.push_notif
.notif
);
128 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
129 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
130 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
131 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
133 case ACTION_TYPE_ADD_STREAM_STATE
:
134 BT_PUT(action
->payload
.add_stream_state
.stream
);
135 destroy_stream_state(
136 action
->payload
.add_stream_state
.stream_state
);
137 action
->payload
.add_stream_state
.stream_state
= NULL
;
139 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
140 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
142 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
150 void add_action(struct bt_notification_iterator
*iterator
,
151 struct action
*action
)
153 g_array_append_val(iterator
->actions
, *action
);
157 void clear_actions(struct bt_notification_iterator
*iterator
)
161 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
162 struct action
*action
= &g_array_index(iterator
->actions
,
165 destroy_action(action
);
168 g_array_set_size(iterator
->actions
, 0);
172 void apply_actions(struct bt_notification_iterator
*iterator
)
176 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
177 struct action
*action
= &g_array_index(iterator
->actions
,
180 switch (action
->type
) {
181 case ACTION_TYPE_PUSH_NOTIF
:
182 /* Move notification to queue */
183 g_queue_push_head(iterator
->queue
,
184 action
->payload
.push_notif
.notif
);
185 bt_notification_freeze(
186 action
->payload
.push_notif
.notif
);
187 action
->payload
.push_notif
.notif
= NULL
;
189 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
190 bt_ctf_stream_map_component_to_port(
191 action
->payload
.map_port_to_comp_in_stream
.stream
,
192 action
->payload
.map_port_to_comp_in_stream
.component
,
193 action
->payload
.map_port_to_comp_in_stream
.port
);
195 case ACTION_TYPE_ADD_STREAM_STATE
:
196 /* Move stream state to hash table */
197 g_hash_table_insert(iterator
->stream_states
,
198 action
->payload
.add_stream_state
.stream
,
199 action
->payload
.add_stream_state
.stream_state
);
201 action
->payload
.add_stream_state
.stream_state
= NULL
;
203 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
205 * We know that this stream is ended. We need to
206 * remember this as long as the stream exists to
207 * enforce that the same stream does not end
210 * Here we add a destroy listener to the stream
211 * which we put after (becomes weak as the hash
212 * table key). If we were the last object to own
213 * this stream, the destroy listener is called
214 * when we call bt_put() which removes this
215 * stream state completely. This is important
216 * because the memory used by this stream object
217 * could be reused for another stream, and they
218 * must have different states.
220 bt_ctf_stream_add_destroy_listener(
221 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
222 stream_destroy_listener
, iterator
);
223 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
224 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
226 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
227 /* Move packet to stream state's current packet */
228 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
229 action
->payload
.set_stream_state_cur_packet
.packet
);
236 clear_actions(iterator
);
240 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
242 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
249 * We keep a reference to the stream until we know it's ended
250 * because we need to be able to create an automatic "stream
251 * end" notification when the user's "next" method returns
252 * BT_NOTIFICATION_ITERATOR_STATUS_END.
254 * We put this reference when the stream is marked as ended.
256 stream_state
->stream
= bt_get(stream
);
263 void bt_notification_iterator_destroy(struct bt_object
*obj
)
265 struct bt_notification_iterator
*iterator
;
266 struct bt_component_class
*comp_class
;
269 iterator
= container_of(obj
, struct bt_notification_iterator
,
271 assert(iterator
->upstream_component
);
272 comp_class
= iterator
->upstream_component
->class;
274 /* Call user-defined destroy method */
275 switch (comp_class
->type
) {
276 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
278 struct bt_component_class_source
*source_class
;
280 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
282 if (source_class
->methods
.iterator
.finalize
) {
283 source_class
->methods
.iterator
.finalize(
284 bt_private_notification_iterator_from_notification_iterator(iterator
));
288 case BT_COMPONENT_CLASS_TYPE_FILTER
:
290 struct bt_component_class_filter
*filter_class
;
292 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
294 if (filter_class
->methods
.iterator
.finalize
) {
295 filter_class
->methods
.iterator
.finalize(
296 bt_private_notification_iterator_from_notification_iterator(iterator
));
305 if (iterator
->queue
) {
306 struct bt_notification
*notif
;
308 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
312 g_queue_free(iterator
->queue
);
315 if (iterator
->stream_states
) {
317 * Remove our destroy listener from each stream which
318 * has a state in this iterator. Otherwise the destroy
319 * listener would be called with an invalid/other
320 * notification iterator object.
322 GHashTableIter ht_iter
;
323 gpointer stream_gptr
, stream_state_gptr
;
325 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
327 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
329 bt_ctf_stream_remove_destroy_listener(
330 (void *) stream_gptr
, stream_destroy_listener
,
334 g_hash_table_destroy(iterator
->stream_states
);
337 if (iterator
->actions
) {
338 g_array_free(iterator
->actions
, TRUE
);
341 bt_put(iterator
->current_notification
);
342 bt_put(iterator
->upstream_component
);
343 bt_put(iterator
->upstream_port
);
348 int create_subscription_mask_from_notification_types(
349 struct bt_notification_iterator
*iterator
,
350 const enum bt_notification_type
*notif_types
)
352 const enum bt_notification_type
*notif_type
;
356 iterator
->subscription_mask
= 0;
358 for (notif_type
= notif_types
;
359 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
361 switch (*notif_type
) {
362 case BT_NOTIFICATION_TYPE_ALL
:
363 iterator
->subscription_mask
|=
364 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
365 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
366 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
367 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
368 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
369 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
371 case BT_NOTIFICATION_TYPE_EVENT
:
372 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
374 case BT_NOTIFICATION_TYPE_INACTIVITY
:
375 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
377 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
378 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
380 case BT_NOTIFICATION_TYPE_STREAM_END
:
381 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
383 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
384 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
386 case BT_NOTIFICATION_TYPE_PACKET_END
:
387 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
400 struct bt_notification_iterator
*bt_notification_iterator_create(
401 struct bt_component
*upstream_comp
,
402 struct bt_port
*upstream_port
,
403 const enum bt_notification_type
*notification_types
)
405 enum bt_component_class_type type
;
406 struct bt_notification_iterator
*iterator
= NULL
;
408 assert(upstream_comp
);
409 assert(upstream_port
);
410 assert(notification_types
);
411 assert(bt_port_is_connected(upstream_port
));
413 type
= bt_component_get_class_type(upstream_comp
);
415 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
416 case BT_COMPONENT_CLASS_TYPE_FILTER
:
422 iterator
= g_new0(struct bt_notification_iterator
, 1);
427 bt_object_init(iterator
, bt_notification_iterator_destroy
);
429 if (create_subscription_mask_from_notification_types(iterator
,
430 notification_types
)) {
434 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
435 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
436 if (!iterator
->stream_states
) {
440 iterator
->queue
= g_queue_new();
441 if (!iterator
->queue
) {
445 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
446 if (!iterator
->actions
) {
450 iterator
->upstream_component
= bt_get(upstream_comp
);
451 iterator
->upstream_port
= bt_get(upstream_port
);
462 enum bt_notification_iterator_status
bt_notification_iterator_validate(
463 struct bt_notification_iterator
*iterator
)
465 enum bt_notification_iterator_status ret
=
466 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
469 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
476 void *bt_private_notification_iterator_get_user_data(
477 struct bt_private_notification_iterator
*private_iterator
)
479 struct bt_notification_iterator
*iterator
=
480 bt_notification_iterator_from_private(private_iterator
);
482 return iterator
? iterator
->user_data
: NULL
;
485 enum bt_notification_iterator_status
486 bt_private_notification_iterator_set_user_data(
487 struct bt_private_notification_iterator
*private_iterator
,
490 enum bt_notification_iterator_status ret
=
491 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
492 struct bt_notification_iterator
*iterator
=
493 bt_notification_iterator_from_private(private_iterator
);
496 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
500 iterator
->user_data
= data
;
505 struct bt_notification
*bt_notification_iterator_get_notification(
506 struct bt_notification_iterator
*iterator
)
508 struct bt_notification
*notification
= NULL
;
514 notification
= bt_get(iterator
->current_notification
);
521 enum bt_notification_iterator_notif_type
522 bt_notification_iterator_notif_type_from_notif_type(
523 enum bt_notification_type notif_type
)
525 enum bt_notification_iterator_notif_type iter_notif_type
;
527 switch (notif_type
) {
528 case BT_NOTIFICATION_TYPE_EVENT
:
529 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
531 case BT_NOTIFICATION_TYPE_INACTIVITY
:
532 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
534 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
535 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
537 case BT_NOTIFICATION_TYPE_STREAM_END
:
538 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
540 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
541 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
543 case BT_NOTIFICATION_TYPE_PACKET_END
:
544 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
550 return iter_notif_type
;
554 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
555 struct bt_notification
*notif
,
556 struct bt_ctf_stream
*notif_stream
,
557 struct bt_ctf_packet
*notif_packet
)
559 bt_bool is_valid
= BT_TRUE
;
560 struct stream_state
*stream_state
;
561 struct bt_port
*stream_comp_cur_port
;
563 assert(notif_stream
);
564 stream_comp_cur_port
=
565 bt_ctf_stream_port_for_component(notif_stream
,
566 iterator
->upstream_component
);
567 if (!stream_comp_cur_port
) {
569 * This is the first time this notification iterator
570 * bumps into this stream. Add an action to map the
571 * iterator's upstream component to the iterator's
572 * upstream port in this stream.
574 struct action action
= {
575 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
576 .payload
.map_port_to_comp_in_stream
= {
577 .stream
= bt_get(notif_stream
),
578 .component
= bt_get(iterator
->upstream_component
),
579 .port
= bt_get(iterator
->upstream_port
),
583 add_action(iterator
, &action
);
585 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
587 * It looks like two different ports of the same
588 * component are emitting notifications which
589 * have references to the same stream. This is
590 * bad: the API guarantees that it can never
599 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
602 if (stream_state
->is_ended
) {
604 * There's a new notification which has a
605 * reference to a stream which, from this
606 * iterator's point of view, is ended ("end of
607 * stream" notification was returned). This is
608 * bad: the API guarantees that it can never
615 switch (notif
->type
) {
616 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
618 * We already have a stream state, which means
619 * we already returned a "stream begin"
620 * notification: this is an invalid duplicate.
624 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
625 if (notif_packet
== stream_state
->cur_packet
) {
626 /* Duplicate "packet begin" notification */
641 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
642 enum bt_notification_type notif_type
)
644 uint32_t iter_notif_type
=
645 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
648 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
652 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
653 struct bt_notification
*notif
)
655 struct action action
= {
656 .type
= ACTION_TYPE_PUSH_NOTIF
,
661 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
665 action
.payload
.push_notif
.notif
= bt_get(notif
);
666 add_action(iterator
, &action
);
670 int add_action_push_notif_stream_begin(
671 struct bt_notification_iterator
*iterator
,
672 struct bt_ctf_stream
*stream
)
675 struct bt_notification
*stream_begin_notif
= NULL
;
677 if (!is_subscribed_to_notification_type(iterator
,
678 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
683 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
684 if (!stream_begin_notif
) {
688 add_action_push_notif(iterator
, stream_begin_notif
);
695 bt_put(stream_begin_notif
);
700 int add_action_push_notif_stream_end(
701 struct bt_notification_iterator
*iterator
,
702 struct bt_ctf_stream
*stream
)
705 struct bt_notification
*stream_end_notif
= NULL
;
707 if (!is_subscribed_to_notification_type(iterator
,
708 BT_NOTIFICATION_TYPE_STREAM_END
)) {
713 stream_end_notif
= bt_notification_stream_end_create(stream
);
714 if (!stream_end_notif
) {
718 add_action_push_notif(iterator
, stream_end_notif
);
725 bt_put(stream_end_notif
);
730 int add_action_push_notif_packet_begin(
731 struct bt_notification_iterator
*iterator
,
732 struct bt_ctf_packet
*packet
)
735 struct bt_notification
*packet_begin_notif
= NULL
;
737 if (!is_subscribed_to_notification_type(iterator
,
738 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
743 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
744 if (!packet_begin_notif
) {
748 add_action_push_notif(iterator
, packet_begin_notif
);
755 bt_put(packet_begin_notif
);
760 int add_action_push_notif_packet_end(
761 struct bt_notification_iterator
*iterator
,
762 struct bt_ctf_packet
*packet
)
765 struct bt_notification
*packet_end_notif
= NULL
;
767 if (!is_subscribed_to_notification_type(iterator
,
768 BT_NOTIFICATION_TYPE_PACKET_END
)) {
773 packet_end_notif
= bt_notification_packet_end_create(packet
);
774 if (!packet_end_notif
) {
778 add_action_push_notif(iterator
, packet_end_notif
);
785 bt_put(packet_end_notif
);
790 void add_action_set_stream_state_is_ended(
791 struct bt_notification_iterator
*iterator
,
792 struct stream_state
*stream_state
)
794 struct action action
= {
795 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
796 .payload
.set_stream_state_is_ended
= {
797 .stream_state
= stream_state
,
801 assert(stream_state
);
802 add_action(iterator
, &action
);
806 void add_action_set_stream_state_cur_packet(
807 struct bt_notification_iterator
*iterator
,
808 struct stream_state
*stream_state
,
809 struct bt_ctf_packet
*packet
)
811 struct action action
= {
812 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
813 .payload
.set_stream_state_cur_packet
= {
814 .stream_state
= stream_state
,
815 .packet
= bt_get(packet
),
819 assert(stream_state
);
820 add_action(iterator
, &action
);
824 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
825 struct bt_notification
*stream_begin_notif
,
826 struct bt_ctf_stream
*notif_stream
,
827 struct stream_state
**stream_state
)
833 * The notification does not reference any stream: no
834 * need to get or create a stream state.
839 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
841 if (!*stream_state
) {
843 * This iterator did not bump into this stream yet:
844 * create a stream state and a "stream begin"
847 struct action action
= {
848 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
849 .payload
.add_stream_state
= {
850 .stream
= bt_get(notif_stream
),
851 .stream_state
= NULL
,
855 *stream_state
= create_stream_state(notif_stream
);
860 action
.payload
.add_stream_state
.stream_state
=
862 add_action(iterator
, &action
);
864 if (stream_begin_notif
) {
865 add_action_push_notif(iterator
, stream_begin_notif
);
867 ret
= add_action_push_notif_stream_begin(iterator
,
878 destroy_stream_state(*stream_state
);
886 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
887 struct bt_notification
*packet_begin_notif
,
888 struct bt_ctf_packet
*new_packet
,
889 struct stream_state
*stream_state
)
893 if (stream_state
->cur_packet
== new_packet
) {
897 if (stream_state
->cur_packet
) {
898 /* End of the current packet */
899 ret
= add_action_push_notif_packet_end(iterator
,
900 stream_state
->cur_packet
);
906 /* Beginning of the new packet */
907 if (packet_begin_notif
) {
908 add_action_push_notif(iterator
, packet_begin_notif
);
909 } else if (new_packet
) {
910 ret
= add_action_push_notif_packet_begin(iterator
,
917 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
929 int handle_notif_stream_begin(
930 struct bt_notification_iterator
*iterator
,
931 struct bt_notification
*notif
,
932 struct bt_ctf_stream
*notif_stream
)
935 struct stream_state
*stream_state
;
937 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
938 assert(notif_stream
);
939 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
955 int handle_notif_stream_end(
956 struct bt_notification_iterator
*iterator
,
957 struct bt_notification
*notif
,
958 struct bt_ctf_stream
*notif_stream
)
961 struct stream_state
*stream_state
;
963 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
964 assert(notif_stream
);
965 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
971 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
976 add_action_push_notif(iterator
, notif
);
977 add_action_set_stream_state_is_ended(iterator
, stream_state
);
988 int handle_notif_packet_begin(
989 struct bt_notification_iterator
*iterator
,
990 struct bt_notification
*notif
,
991 struct bt_ctf_stream
*notif_stream
,
992 struct bt_ctf_packet
*notif_packet
)
995 struct stream_state
*stream_state
;
997 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
998 assert(notif_packet
);
999 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1005 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1020 int handle_notif_packet_end(
1021 struct bt_notification_iterator
*iterator
,
1022 struct bt_notification
*notif
,
1023 struct bt_ctf_stream
*notif_stream
,
1024 struct bt_ctf_packet
*notif_packet
)
1027 struct stream_state
*stream_state
;
1029 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1030 assert(notif_packet
);
1031 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1037 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1042 /* End of the current packet */
1043 add_action_push_notif(iterator
, notif
);
1044 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1055 int handle_notif_event(
1056 struct bt_notification_iterator
*iterator
,
1057 struct bt_notification
*notif
,
1058 struct bt_ctf_stream
*notif_stream
,
1059 struct bt_ctf_packet
*notif_packet
)
1062 struct stream_state
*stream_state
;
1064 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1065 assert(notif_packet
);
1066 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1072 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1077 add_action_push_notif(iterator
, notif
);
1088 int enqueue_notification_and_automatic(
1089 struct bt_notification_iterator
*iterator
,
1090 struct bt_notification
*notif
)
1093 struct bt_ctf_event
*notif_event
= NULL
;
1094 struct bt_ctf_stream
*notif_stream
= NULL
;
1095 struct bt_ctf_packet
*notif_packet
= NULL
;
1099 // TODO: Skip most of this if the iterator is only subscribed
1100 // to event/inactivity notifications.
1102 /* Get the stream and packet referred by the notification */
1103 switch (notif
->type
) {
1104 case BT_NOTIFICATION_TYPE_EVENT
:
1105 notif_event
= bt_notification_event_borrow_event(notif
);
1106 assert(notif_event
);
1107 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1108 assert(notif_packet
);
1110 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1112 bt_notification_stream_begin_borrow_stream(notif
);
1113 assert(notif_stream
);
1115 case BT_NOTIFICATION_TYPE_STREAM_END
:
1116 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1117 assert(notif_stream
);
1119 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1121 bt_notification_packet_begin_borrow_packet(notif
);
1122 assert(notif_packet
);
1124 case BT_NOTIFICATION_TYPE_PACKET_END
:
1125 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1126 assert(notif_packet
);
1128 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1133 * Invalid type of notification. Only the notification
1134 * types above are allowed to be returned by a user
1141 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1142 assert(notif_stream
);
1145 if (!notif_stream
) {
1147 * The notification has no reference to a stream: it
1148 * cannot cause the creation of automatic notifications.
1153 if (!validate_notification(iterator
, notif
, notif_stream
,
1158 switch (notif
->type
) {
1159 case BT_NOTIFICATION_TYPE_EVENT
:
1160 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1163 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1164 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1166 case BT_NOTIFICATION_TYPE_STREAM_END
:
1167 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1169 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1170 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1173 case BT_NOTIFICATION_TYPE_PACKET_END
:
1174 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1185 apply_actions(iterator
);
1196 int handle_end(struct bt_notification_iterator
*iterator
)
1198 GHashTableIter stream_state_iter
;
1199 gpointer stream_gptr
, stream_state_gptr
;
1203 * Emit a "stream end" notification for each non-ended stream
1204 * known by this iterator and mark them as ended.
1206 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1208 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1209 &stream_state_gptr
)) {
1210 struct stream_state
*stream_state
= stream_state_gptr
;
1212 assert(stream_state_gptr
);
1214 if (stream_state
->is_ended
) {
1218 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1223 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1228 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1231 apply_actions(iterator
);
1242 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1243 struct bt_notification_iterator
*iterator
)
1245 struct bt_private_notification_iterator
*priv_iterator
=
1246 bt_private_notification_iterator_from_notification_iterator(iterator
);
1247 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1248 struct bt_notification_iterator_next_return next_return
= {
1249 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1250 .notification
= NULL
,
1252 enum bt_notification_iterator_status status
=
1253 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1258 if (iterator
->queue
->length
> 0) {
1259 /* We already have enough */
1263 if (iterator
->is_ended
) {
1264 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1268 assert(iterator
->upstream_component
);
1269 assert(iterator
->upstream_component
->class);
1271 /* Pick the appropriate "next" method */
1272 switch (iterator
->upstream_component
->class->type
) {
1273 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1275 struct bt_component_class_source
*source_class
=
1276 container_of(iterator
->upstream_component
->class,
1277 struct bt_component_class_source
, parent
);
1279 assert(source_class
->methods
.iterator
.next
);
1280 next_method
= source_class
->methods
.iterator
.next
;
1283 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1285 struct bt_component_class_filter
*filter_class
=
1286 container_of(iterator
->upstream_component
->class,
1287 struct bt_component_class_filter
, parent
);
1289 assert(filter_class
->methods
.iterator
.next
);
1290 next_method
= filter_class
->methods
.iterator
.next
;
1299 * Call the user's "next" method to get the next notification
1302 assert(next_method
);
1304 while (iterator
->queue
->length
== 0) {
1305 next_return
= next_method(priv_iterator
);
1306 if (next_return
.status
< 0) {
1307 status
= next_return
.status
;
1311 switch (next_return
.status
) {
1312 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1313 ret
= handle_end(iterator
);
1315 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1319 if (iterator
->queue
->length
== 0) {
1320 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1323 iterator
->is_ended
= BT_TRUE
;
1325 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1326 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1328 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1329 if (!next_return
.notification
) {
1330 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1335 * We know the notification is valid. Before we
1336 * push it to the head of the queue, push the
1337 * appropriate automatic notifications if any.
1339 ret
= enqueue_notification_and_automatic(iterator
,
1340 next_return
.notification
);
1341 BT_PUT(next_return
.notification
);
1343 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1348 /* Unknown non-error status */
1357 enum bt_notification_iterator_status
1358 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1360 enum bt_notification_iterator_status status
;
1363 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1368 * Make sure that the iterator's queue contains at least one
1371 status
= ensure_queue_has_notifications(iterator
);
1372 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1377 * Move the notification at the tail of the queue to the
1378 * iterator's current notification.
1380 assert(iterator
->queue
->length
> 0);
1381 bt_put(iterator
->current_notification
);
1382 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1383 assert(iterator
->current_notification
);
1389 struct bt_component
*bt_notification_iterator_get_component(
1390 struct bt_notification_iterator
*iterator
)
1392 return bt_get(iterator
->upstream_component
);
1395 struct bt_private_component
*
1396 bt_private_notification_iterator_get_private_component(
1397 struct bt_private_notification_iterator
*private_iterator
)
1399 return bt_private_component_from_component(
1400 bt_notification_iterator_get_component(
1401 bt_notification_iterator_from_private(private_iterator
)));
1404 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1405 struct bt_notification_iterator
*iterator
,
1406 enum bt_notification_iterator_seek_origin seek_origin
,
1409 enum bt_notification_iterator_status ret
=
1410 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;