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-iterator.h>
37 #include <babeltrace/graph/notification-iterator-internal.h>
38 #include <babeltrace/graph/notification-internal.h>
39 #include <babeltrace/graph/notification-event.h>
40 #include <babeltrace/graph/notification-event-internal.h>
41 #include <babeltrace/graph/notification-packet.h>
42 #include <babeltrace/graph/notification-packet-internal.h>
43 #include <babeltrace/graph/notification-stream.h>
44 #include <babeltrace/graph/notification-stream-internal.h>
45 #include <babeltrace/graph/port.h>
48 struct bt_ctf_stream
*stream
; /* owned by this */
49 struct bt_ctf_packet
*cur_packet
; /* owned by this */
54 ACTION_TYPE_PUSH_NOTIF
,
55 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
56 ACTION_TYPE_ADD_STREAM_STATE
,
57 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
58 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
62 enum action_type type
;
64 /* ACTION_TYPE_PUSH_NOTIF */
66 struct bt_notification
*notif
; /* owned by this */
69 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
71 struct bt_ctf_stream
*stream
; /* owned by this */
72 struct bt_component
*component
; /* owned by this */
73 struct bt_port
*port
; /* owned by this */
74 } map_port_to_comp_in_stream
;
76 /* ACTION_TYPE_ADD_STREAM_STATE */
78 struct bt_ctf_stream
*stream
; /* owned by this */
79 struct stream_state
*stream_state
; /* owned by this */
82 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
84 struct stream_state
*stream_state
; /* weak */
85 } set_stream_state_is_ended
;
87 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
89 struct stream_state
*stream_state
; /* weak */
90 struct bt_ctf_packet
*packet
; /* owned by this */
91 } set_stream_state_cur_packet
;
96 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
98 struct bt_notification_iterator
*iterator
= data
;
100 /* Remove associated stream state */
101 g_hash_table_remove(iterator
->stream_states
, stream
);
105 void destroy_stream_state(struct stream_state
*stream_state
)
111 bt_put(stream_state
->cur_packet
);
112 bt_put(stream_state
->stream
);
113 g_free(stream_state
);
117 void destroy_action(struct action
*action
)
121 switch (action
->type
) {
122 case ACTION_TYPE_PUSH_NOTIF
:
123 BT_PUT(action
->payload
.push_notif
.notif
);
125 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
126 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
127 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
128 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
130 case ACTION_TYPE_ADD_STREAM_STATE
:
131 BT_PUT(action
->payload
.add_stream_state
.stream
);
132 destroy_stream_state(
133 action
->payload
.add_stream_state
.stream_state
);
134 action
->payload
.add_stream_state
.stream_state
= NULL
;
136 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
137 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
139 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
147 void add_action(struct bt_notification_iterator
*iterator
,
148 struct action
*action
)
150 g_array_append_val(iterator
->actions
, *action
);
154 void clear_actions(struct bt_notification_iterator
*iterator
)
158 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
159 struct action
*action
= &g_array_index(iterator
->actions
,
162 destroy_action(action
);
165 g_array_set_size(iterator
->actions
, 0);
169 void apply_actions(struct bt_notification_iterator
*iterator
)
173 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
174 struct action
*action
= &g_array_index(iterator
->actions
,
177 switch (action
->type
) {
178 case ACTION_TYPE_PUSH_NOTIF
:
179 /* Move notification to queue */
180 g_queue_push_head(iterator
->queue
,
181 action
->payload
.push_notif
.notif
);
182 bt_notification_freeze(
183 action
->payload
.push_notif
.notif
);
184 action
->payload
.push_notif
.notif
= NULL
;
186 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
187 bt_ctf_stream_map_component_to_port(
188 action
->payload
.map_port_to_comp_in_stream
.stream
,
189 action
->payload
.map_port_to_comp_in_stream
.component
,
190 action
->payload
.map_port_to_comp_in_stream
.port
);
192 case ACTION_TYPE_ADD_STREAM_STATE
:
193 /* Move stream state to hash table */
194 g_hash_table_insert(iterator
->stream_states
,
195 action
->payload
.add_stream_state
.stream
,
196 action
->payload
.add_stream_state
.stream_state
);
198 action
->payload
.add_stream_state
.stream_state
= NULL
;
200 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
202 * We know that this stream is ended. We need to
203 * remember this as long as the stream exists to
204 * enforce that the same stream does not end
207 * Here we add a destroy listener to the stream
208 * which we put after (becomes weak as the hash
209 * table key). If we were the last object to own
210 * this stream, the destroy listener is called
211 * when we call bt_put() which removes this
212 * stream state completely. This is important
213 * because the memory used by this stream object
214 * could be reused for another stream, and they
215 * must have different states.
217 bt_ctf_stream_add_destroy_listener(
218 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
219 stream_destroy_listener
, iterator
);
220 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= true;
221 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
223 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
224 /* Move packet to stream state's current packet */
225 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
226 action
->payload
.set_stream_state_cur_packet
.packet
);
233 clear_actions(iterator
);
237 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
239 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
246 * We keep a reference to the stream until we know it's ended
247 * because we need to be able to create an automatic "stream
248 * end" notification when the user's "next" method returns
249 * BT_NOTIFICATION_ITERATOR_STATUS_END.
251 * We put this reference when the stream is marked as ended.
253 stream_state
->stream
= bt_get(stream
);
260 void bt_notification_iterator_destroy(struct bt_object
*obj
)
262 struct bt_notification_iterator
*iterator
;
263 struct bt_component_class
*comp_class
;
266 iterator
= container_of(obj
, struct bt_notification_iterator
,
268 assert(iterator
->upstream_component
);
269 comp_class
= iterator
->upstream_component
->class;
271 /* Call user-defined destroy method */
272 switch (comp_class
->type
) {
273 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
275 struct bt_component_class_source
*source_class
;
277 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
279 if (source_class
->methods
.iterator
.finalize
) {
280 source_class
->methods
.iterator
.finalize(
281 bt_private_notification_iterator_from_notification_iterator(iterator
));
285 case BT_COMPONENT_CLASS_TYPE_FILTER
:
287 struct bt_component_class_filter
*filter_class
;
289 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
291 if (filter_class
->methods
.iterator
.finalize
) {
292 filter_class
->methods
.iterator
.finalize(
293 bt_private_notification_iterator_from_notification_iterator(iterator
));
302 if (iterator
->queue
) {
303 struct bt_notification
*notif
;
305 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
309 g_queue_free(iterator
->queue
);
312 if (iterator
->stream_states
) {
314 * Remove our destroy listener from each stream which
315 * has a state in this iterator. Otherwise the destroy
316 * listener would be called with an invalid/other
317 * notification iterator object.
319 GHashTableIter ht_iter
;
320 gpointer stream_gptr
, stream_state_gptr
;
322 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
324 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
326 bt_ctf_stream_remove_destroy_listener(
327 (void *) stream_gptr
, stream_destroy_listener
,
331 g_hash_table_destroy(iterator
->stream_states
);
334 if (iterator
->actions
) {
335 g_array_free(iterator
->actions
, TRUE
);
338 bt_put(iterator
->current_notification
);
339 bt_put(iterator
->upstream_component
);
340 bt_put(iterator
->upstream_port
);
345 struct bt_notification_iterator
*bt_notification_iterator_create(
346 struct bt_component
*upstream_comp
,
347 struct bt_port
*upstream_port
)
349 enum bt_component_class_type type
;
350 struct bt_notification_iterator
*iterator
= NULL
;
352 assert(upstream_comp
);
353 assert(upstream_port
);
354 assert(bt_port_is_connected(upstream_port
));
356 type
= bt_component_get_class_type(upstream_comp
);
358 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
359 case BT_COMPONENT_CLASS_TYPE_FILTER
:
365 iterator
= g_new0(struct bt_notification_iterator
, 1);
370 bt_object_init(iterator
, bt_notification_iterator_destroy
);
372 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
373 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
374 if (!iterator
->stream_states
) {
378 iterator
->queue
= g_queue_new();
379 if (!iterator
->queue
) {
383 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
384 if (!iterator
->actions
) {
388 iterator
->upstream_component
= bt_get(upstream_comp
);
389 iterator
->upstream_port
= bt_get(upstream_port
);
400 enum bt_notification_iterator_status
bt_notification_iterator_validate(
401 struct bt_notification_iterator
*iterator
)
403 enum bt_notification_iterator_status ret
=
404 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
407 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
414 void *bt_private_notification_iterator_get_user_data(
415 struct bt_private_notification_iterator
*private_iterator
)
417 struct bt_notification_iterator
*iterator
=
418 bt_notification_iterator_from_private(private_iterator
);
420 return iterator
? iterator
->user_data
: NULL
;
423 enum bt_notification_iterator_status
424 bt_private_notification_iterator_set_user_data(
425 struct bt_private_notification_iterator
*private_iterator
,
428 enum bt_notification_iterator_status ret
=
429 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
430 struct bt_notification_iterator
*iterator
=
431 bt_notification_iterator_from_private(private_iterator
);
434 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
438 iterator
->user_data
= data
;
443 struct bt_notification
*bt_notification_iterator_get_notification(
444 struct bt_notification_iterator
*iterator
)
446 struct bt_notification
*notification
= NULL
;
452 notification
= bt_get(iterator
->current_notification
);
459 bool validate_notification(struct bt_notification_iterator
*iterator
,
460 struct bt_notification
*notif
,
461 struct bt_ctf_stream
*notif_stream
,
462 struct bt_ctf_packet
*notif_packet
)
464 bool is_valid
= true;
465 struct stream_state
*stream_state
;
466 struct bt_port
*stream_comp_cur_port
;
468 assert(notif_stream
);
469 stream_comp_cur_port
=
470 bt_ctf_stream_port_for_component(notif_stream
,
471 iterator
->upstream_component
);
472 if (!stream_comp_cur_port
) {
474 * This is the first time this notification iterator
475 * bumps into this stream. Add an action to map the
476 * iterator's upstream component to the iterator's
477 * upstream port in this stream.
479 struct action action
= {
480 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
481 .payload
.map_port_to_comp_in_stream
= {
482 .stream
= bt_get(notif_stream
),
483 .component
= bt_get(iterator
->upstream_component
),
484 .port
= bt_get(iterator
->upstream_port
),
488 add_action(iterator
, &action
);
490 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
492 * It looks like two different ports of the same
493 * component are emitting notifications which
494 * have references to the same stream. This is
495 * bad: the API guarantees that it can never
504 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
507 if (stream_state
->is_ended
) {
509 * There's a new notification which has a
510 * reference to a stream which, from this
511 * iterator's point of view, is ended ("end of
512 * stream" notification was returned). This is
513 * bad: the API guarantees that it can never
520 switch (notif
->type
) {
521 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
523 * We already have a stream state, which means
524 * we already returned a "stream begin"
525 * notification: this is an invalid duplicate.
529 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
530 if (notif_packet
== stream_state
->cur_packet
) {
531 /* Duplicate "packet begin" notification */
546 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
547 struct bt_notification
*notif
)
549 struct action action
= {
550 .type
= ACTION_TYPE_PUSH_NOTIF
,
551 .payload
.push_notif
= {
552 .notif
= bt_get(notif
),
557 add_action(iterator
, &action
);
561 int add_action_push_notif_stream_begin(
562 struct bt_notification_iterator
*iterator
,
563 struct bt_ctf_stream
*stream
)
566 struct bt_notification
*stream_begin_notif
= NULL
;
569 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
570 if (!stream_begin_notif
) {
574 add_action_push_notif(iterator
, stream_begin_notif
);
581 bt_put(stream_begin_notif
);
586 int add_action_push_notif_stream_end(
587 struct bt_notification_iterator
*iterator
,
588 struct bt_ctf_stream
*stream
)
591 struct bt_notification
*stream_end_notif
= NULL
;
594 stream_end_notif
= bt_notification_stream_end_create(stream
);
595 if (!stream_end_notif
) {
599 add_action_push_notif(iterator
, stream_end_notif
);
606 bt_put(stream_end_notif
);
611 int add_action_push_notif_packet_begin(
612 struct bt_notification_iterator
*iterator
,
613 struct bt_ctf_packet
*packet
)
616 struct bt_notification
*packet_begin_notif
= NULL
;
619 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
620 if (!packet_begin_notif
) {
624 add_action_push_notif(iterator
, packet_begin_notif
);
631 bt_put(packet_begin_notif
);
636 int add_action_push_notif_packet_end(
637 struct bt_notification_iterator
*iterator
,
638 struct bt_ctf_packet
*packet
)
641 struct bt_notification
*packet_end_notif
= NULL
;
644 packet_end_notif
= bt_notification_packet_end_create(packet
);
645 if (!packet_end_notif
) {
649 add_action_push_notif(iterator
, packet_end_notif
);
656 bt_put(packet_end_notif
);
661 void add_action_set_stream_state_is_ended(
662 struct bt_notification_iterator
*iterator
,
663 struct stream_state
*stream_state
)
665 struct action action
= {
666 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
667 .payload
.set_stream_state_is_ended
= {
668 .stream_state
= stream_state
,
672 assert(stream_state
);
673 add_action(iterator
, &action
);
677 void add_action_set_stream_state_cur_packet(
678 struct bt_notification_iterator
*iterator
,
679 struct stream_state
*stream_state
,
680 struct bt_ctf_packet
*packet
)
682 struct action action
= {
683 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
684 .payload
.set_stream_state_cur_packet
= {
685 .stream_state
= stream_state
,
686 .packet
= bt_get(packet
),
690 assert(stream_state
);
691 add_action(iterator
, &action
);
695 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
696 struct bt_notification
*stream_begin_notif
,
697 struct bt_ctf_stream
*notif_stream
,
698 struct stream_state
**stream_state
)
704 * The notification does not reference any stream: no
705 * need to get or create a stream state.
710 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
712 if (!*stream_state
) {
714 * This iterator did not bump into this stream yet:
715 * create a stream state and a "stream begin"
718 struct action action
= {
719 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
720 .payload
.add_stream_state
= {
721 .stream
= bt_get(notif_stream
),
722 .stream_state
= NULL
,
726 *stream_state
= create_stream_state(notif_stream
);
731 action
.payload
.add_stream_state
.stream_state
=
733 add_action(iterator
, &action
);
735 if (stream_begin_notif
) {
736 add_action_push_notif(iterator
, stream_begin_notif
);
738 ret
= add_action_push_notif_stream_begin(iterator
,
749 destroy_stream_state(*stream_state
);
757 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
758 struct bt_notification
*packet_begin_notif
,
759 struct bt_ctf_packet
*new_packet
,
760 struct stream_state
*stream_state
)
764 if (stream_state
->cur_packet
== new_packet
) {
768 if (stream_state
->cur_packet
) {
769 /* End of the current packet */
770 ret
= add_action_push_notif_packet_end(iterator
,
771 stream_state
->cur_packet
);
777 /* Beginning of the new packet */
778 if (packet_begin_notif
) {
779 add_action_push_notif(iterator
, packet_begin_notif
);
780 } else if (new_packet
) {
781 ret
= add_action_push_notif_packet_begin(iterator
,
788 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
800 int handle_notif_stream_begin(
801 struct bt_notification_iterator
*iterator
,
802 struct bt_notification
*notif
,
803 struct bt_ctf_stream
*notif_stream
)
806 struct stream_state
*stream_state
;
808 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
809 assert(notif_stream
);
810 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
826 int handle_notif_stream_end(
827 struct bt_notification_iterator
*iterator
,
828 struct bt_notification
*notif
,
829 struct bt_ctf_stream
*notif_stream
)
832 struct stream_state
*stream_state
;
834 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
835 assert(notif_stream
);
836 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
842 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
847 add_action_push_notif(iterator
, notif
);
848 add_action_set_stream_state_is_ended(iterator
, stream_state
);
859 int handle_notif_packet_begin(
860 struct bt_notification_iterator
*iterator
,
861 struct bt_notification
*notif
,
862 struct bt_ctf_stream
*notif_stream
,
863 struct bt_ctf_packet
*notif_packet
)
866 struct stream_state
*stream_state
;
868 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
869 assert(notif_packet
);
870 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
876 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
891 int handle_notif_packet_end(
892 struct bt_notification_iterator
*iterator
,
893 struct bt_notification
*notif
,
894 struct bt_ctf_stream
*notif_stream
,
895 struct bt_ctf_packet
*notif_packet
)
898 struct stream_state
*stream_state
;
900 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
901 assert(notif_packet
);
902 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
908 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
913 /* End of the current packet */
914 add_action_push_notif(iterator
, notif
);
915 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
926 int handle_notif_event(
927 struct bt_notification_iterator
*iterator
,
928 struct bt_notification
*notif
,
929 struct bt_ctf_stream
*notif_stream
,
930 struct bt_ctf_packet
*notif_packet
)
933 struct stream_state
*stream_state
;
935 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
936 assert(notif_packet
);
937 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
943 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
948 add_action_push_notif(iterator
, notif
);
959 int enqueue_notification_and_automatic(
960 struct bt_notification_iterator
*iterator
,
961 struct bt_notification
*notif
)
964 struct bt_ctf_event
*notif_event
= NULL
;
965 struct bt_ctf_stream
*notif_stream
= NULL
;
966 struct bt_ctf_packet
*notif_packet
= NULL
;
970 /* Get the stream and packet referred by the notification */
971 switch (notif
->type
) {
972 case BT_NOTIFICATION_TYPE_EVENT
:
973 notif_event
= bt_notification_event_borrow_event(notif
);
975 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
976 assert(notif_packet
);
978 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
980 bt_notification_stream_begin_borrow_stream(notif
);
981 assert(notif_stream
);
983 case BT_NOTIFICATION_TYPE_STREAM_END
:
984 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
985 assert(notif_stream
);
987 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
989 bt_notification_packet_begin_borrow_packet(notif
);
990 assert(notif_packet
);
992 case BT_NOTIFICATION_TYPE_PACKET_END
:
993 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
994 assert(notif_packet
);
996 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1001 * Invalid type of notification. Only the notification
1002 * types above are allowed to be returned by a user
1009 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1010 assert(notif_stream
);
1013 if (!notif_stream
) {
1015 * The notification has no reference to a stream: it
1016 * cannot cause the creation of automatic notifications.
1021 if (!validate_notification(iterator
, notif
, notif_stream
,
1026 switch (notif
->type
) {
1027 case BT_NOTIFICATION_TYPE_EVENT
:
1028 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1031 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1032 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1034 case BT_NOTIFICATION_TYPE_STREAM_END
:
1035 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1037 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1038 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1041 case BT_NOTIFICATION_TYPE_PACKET_END
:
1042 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1053 apply_actions(iterator
);
1064 int handle_end(struct bt_notification_iterator
*iterator
)
1066 GHashTableIter stream_state_iter
;
1067 gpointer stream_gptr
, stream_state_gptr
;
1071 * Emit a "stream end" notification for each non-ended stream
1072 * known by this iterator and mark them as ended.
1074 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1076 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1077 &stream_state_gptr
)) {
1078 struct stream_state
*stream_state
= stream_state_gptr
;
1080 assert(stream_state_gptr
);
1082 if (stream_state
->is_ended
) {
1086 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1091 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1096 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1099 apply_actions(iterator
);
1110 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1111 struct bt_notification_iterator
*iterator
)
1113 struct bt_private_notification_iterator
*priv_iterator
=
1114 bt_private_notification_iterator_from_notification_iterator(iterator
);
1115 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1116 struct bt_notification_iterator_next_return next_return
= {
1117 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1118 .notification
= NULL
,
1120 enum bt_notification_iterator_status status
=
1121 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1126 if (iterator
->queue
->length
> 0) {
1127 /* We already have enough */
1131 if (iterator
->is_ended
) {
1132 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1136 assert(iterator
->upstream_component
);
1137 assert(iterator
->upstream_component
->class);
1139 /* Pick the appropriate "next" method */
1140 switch (iterator
->upstream_component
->class->type
) {
1141 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1143 struct bt_component_class_source
*source_class
=
1144 container_of(iterator
->upstream_component
->class,
1145 struct bt_component_class_source
, parent
);
1147 assert(source_class
->methods
.iterator
.next
);
1148 next_method
= source_class
->methods
.iterator
.next
;
1151 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1153 struct bt_component_class_filter
*filter_class
=
1154 container_of(iterator
->upstream_component
->class,
1155 struct bt_component_class_filter
, parent
);
1157 assert(filter_class
->methods
.iterator
.next
);
1158 next_method
= filter_class
->methods
.iterator
.next
;
1167 * Call the user's "next" method to get the next notification
1168 * and status, skipping the forwarded automatic notifications
1171 assert(next_method
);
1172 next_return
= next_method(priv_iterator
);
1173 if (next_return
.status
< 0) {
1174 status
= next_return
.status
;
1178 switch (next_return
.status
) {
1179 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1180 ret
= handle_end(iterator
);
1182 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1186 if (iterator
->queue
->length
== 0) {
1187 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1190 iterator
->is_ended
= true;
1192 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1193 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1195 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1196 if (!next_return
.notification
) {
1197 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1202 * We know the notification is valid. Before we push it
1203 * to the head of the queue, push the appropriate
1204 * automatic notifications if any.
1206 ret
= enqueue_notification_and_automatic(iterator
,
1207 next_return
.notification
);
1208 BT_PUT(next_return
.notification
);
1210 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1215 /* Unknown non-error status */
1223 enum bt_notification_iterator_status
1224 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1226 enum bt_notification_iterator_status status
;
1229 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1234 * Make sure that the iterator's queue contains at least one
1237 status
= ensure_queue_has_notifications(iterator
);
1238 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1243 * Move the notification at the tail of the queue to the
1244 * iterator's current notification.
1246 assert(iterator
->queue
->length
> 0);
1247 bt_put(iterator
->current_notification
);
1248 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1249 assert(iterator
->current_notification
);
1255 struct bt_component
*bt_notification_iterator_get_component(
1256 struct bt_notification_iterator
*iterator
)
1258 return bt_get(iterator
->upstream_component
);
1261 struct bt_private_component
*
1262 bt_private_notification_iterator_get_private_component(
1263 struct bt_private_notification_iterator
*private_iterator
)
1265 return bt_private_component_from_component(
1266 bt_notification_iterator_get_component(
1267 bt_notification_iterator_from_private(private_iterator
)));
1270 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1271 struct bt_notification_iterator
*iterator
,
1272 enum bt_notification_iterator_seek_origin seek_origin
,
1275 enum bt_notification_iterator_status ret
=
1276 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;