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 #define BT_LOG_TAG "NOTIF-ITER"
29 #include <babeltrace/lib-logging-internal.h>
31 #include <babeltrace/compiler-internal.h>
32 #include <babeltrace/ref.h>
33 #include <babeltrace/ctf-ir/event-internal.h>
34 #include <babeltrace/ctf-ir/packet-internal.h>
35 #include <babeltrace/ctf-ir/stream-internal.h>
36 #include <babeltrace/graph/connection-internal.h>
37 #include <babeltrace/graph/component.h>
38 #include <babeltrace/graph/component-source-internal.h>
39 #include <babeltrace/graph/component-class-internal.h>
40 #include <babeltrace/graph/notification.h>
41 #include <babeltrace/graph/notification-iterator.h>
42 #include <babeltrace/graph/notification-iterator-internal.h>
43 #include <babeltrace/graph/notification-internal.h>
44 #include <babeltrace/graph/notification-event.h>
45 #include <babeltrace/graph/notification-event-internal.h>
46 #include <babeltrace/graph/notification-packet.h>
47 #include <babeltrace/graph/notification-packet-internal.h>
48 #include <babeltrace/graph/notification-stream.h>
49 #include <babeltrace/graph/notification-stream-internal.h>
50 #include <babeltrace/graph/port.h>
51 #include <babeltrace/types.h>
56 struct bt_ctf_stream
*stream
; /* owned by this */
57 struct bt_ctf_packet
*cur_packet
; /* owned by this */
62 ACTION_TYPE_PUSH_NOTIF
,
63 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
64 ACTION_TYPE_ADD_STREAM_STATE
,
65 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
66 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
70 enum action_type type
;
72 /* ACTION_TYPE_PUSH_NOTIF */
74 struct bt_notification
*notif
; /* owned by this */
77 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
79 struct bt_ctf_stream
*stream
; /* owned by this */
80 struct bt_component
*component
; /* owned by this */
81 struct bt_port
*port
; /* owned by this */
82 } map_port_to_comp_in_stream
;
84 /* ACTION_TYPE_ADD_STREAM_STATE */
86 struct bt_ctf_stream
*stream
; /* owned by this */
87 struct stream_state
*stream_state
; /* owned by this */
90 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
92 struct stream_state
*stream_state
; /* weak */
93 } set_stream_state_is_ended
;
95 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
97 struct stream_state
*stream_state
; /* weak */
98 struct bt_ctf_packet
*packet
; /* owned by this */
99 } set_stream_state_cur_packet
;
104 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
106 struct bt_notification_iterator
*iterator
= data
;
108 /* Remove associated stream state */
109 g_hash_table_remove(iterator
->stream_states
, stream
);
113 void destroy_stream_state(struct stream_state
*stream_state
)
119 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
120 BT_LOGV_STR("Putting stream state's current packet.");
121 bt_put(stream_state
->cur_packet
);
122 BT_LOGV_STR("Putting stream state's stream.");
123 bt_put(stream_state
->stream
);
124 g_free(stream_state
);
128 void destroy_action(struct action
*action
)
132 switch (action
->type
) {
133 case ACTION_TYPE_PUSH_NOTIF
:
134 BT_PUT(action
->payload
.push_notif
.notif
);
136 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
137 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
138 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
139 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
141 case ACTION_TYPE_ADD_STREAM_STATE
:
142 BT_PUT(action
->payload
.add_stream_state
.stream
);
143 destroy_stream_state(
144 action
->payload
.add_stream_state
.stream_state
);
145 action
->payload
.add_stream_state
.stream_state
= NULL
;
147 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
148 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
150 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
158 void add_action(struct bt_notification_iterator
*iterator
,
159 struct action
*action
)
161 g_array_append_val(iterator
->actions
, *action
);
165 void clear_actions(struct bt_notification_iterator
*iterator
)
169 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
170 struct action
*action
= &g_array_index(iterator
->actions
,
173 destroy_action(action
);
176 g_array_set_size(iterator
->actions
, 0);
180 const char *action_type_string(enum action_type type
)
183 case ACTION_TYPE_PUSH_NOTIF
:
184 return "ACTION_TYPE_PUSH_NOTIF";
185 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
186 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
187 case ACTION_TYPE_ADD_STREAM_STATE
:
188 return "ACTION_TYPE_ADD_STREAM_STATE";
189 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
190 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
191 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
192 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
199 void apply_actions(struct bt_notification_iterator
*iterator
)
203 BT_LOGV("Applying notification's iterator current actions: "
204 "count=%u", iterator
->actions
->len
);
206 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
207 struct action
*action
= &g_array_index(iterator
->actions
,
210 BT_LOGV("Applying action: index=%zu, type=%s",
211 i
, action_type_string(action
->type
));
213 switch (action
->type
) {
214 case ACTION_TYPE_PUSH_NOTIF
:
215 /* Move notification to queue */
216 g_queue_push_head(iterator
->queue
,
217 action
->payload
.push_notif
.notif
);
218 bt_notification_freeze(
219 action
->payload
.push_notif
.notif
);
220 action
->payload
.push_notif
.notif
= NULL
;
222 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
223 bt_ctf_stream_map_component_to_port(
224 action
->payload
.map_port_to_comp_in_stream
.stream
,
225 action
->payload
.map_port_to_comp_in_stream
.component
,
226 action
->payload
.map_port_to_comp_in_stream
.port
);
228 case ACTION_TYPE_ADD_STREAM_STATE
:
229 /* Move stream state to hash table */
230 g_hash_table_insert(iterator
->stream_states
,
231 action
->payload
.add_stream_state
.stream
,
232 action
->payload
.add_stream_state
.stream_state
);
234 action
->payload
.add_stream_state
.stream_state
= NULL
;
236 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
238 * We know that this stream is ended. We need to
239 * remember this as long as the stream exists to
240 * enforce that the same stream does not end
243 * Here we add a destroy listener to the stream
244 * which we put after (becomes weak as the hash
245 * table key). If we were the last object to own
246 * this stream, the destroy listener is called
247 * when we call bt_put() which removes this
248 * stream state completely. This is important
249 * because the memory used by this stream object
250 * could be reused for another stream, and they
251 * must have different states.
253 bt_ctf_stream_add_destroy_listener(
254 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
255 stream_destroy_listener
, iterator
);
256 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
257 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
259 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
260 /* Move packet to stream state's current packet */
261 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
262 action
->payload
.set_stream_state_cur_packet
.packet
);
269 clear_actions(iterator
);
273 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
275 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
278 BT_LOGE_STR("Failed to allocate one stream state.");
283 * We keep a reference to the stream until we know it's ended
284 * because we need to be able to create an automatic "stream
285 * end" notification when the user's "next" method returns
286 * BT_NOTIFICATION_ITERATOR_STATUS_END.
288 * We put this reference when the stream is marked as ended.
290 stream_state
->stream
= bt_get(stream
);
291 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
292 "stream-state-addr=%p",
293 stream
, bt_ctf_stream_get_name(stream
), stream_state
);
300 void bt_notification_iterator_destroy(struct bt_object
*obj
)
302 struct bt_notification_iterator
*iterator
;
307 * The notification iterator's reference count is 0 if we're
308 * here. Increment it to avoid a double-destroy (possibly
309 * infinitely recursive). This could happen for example if the
310 * notification iterator's finalization function does bt_get()
311 * (or anything that causes bt_get() to be called) on itself
312 * (ref. count goes from 0 to 1), and then bt_put(): the
313 * reference count would go from 1 to 0 again and this function
314 * would be called again.
316 obj
->ref_count
.count
++;
317 iterator
= container_of(obj
, struct bt_notification_iterator
, base
);
318 BT_LOGD("Destroying notification iterator object: addr=%p",
320 bt_notification_iterator_finalize(iterator
);
322 if (iterator
->queue
) {
323 struct bt_notification
*notif
;
325 BT_LOGD("Putting notifications in queue.");
327 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
331 g_queue_free(iterator
->queue
);
334 if (iterator
->stream_states
) {
336 * Remove our destroy listener from each stream which
337 * has a state in this iterator. Otherwise the destroy
338 * listener would be called with an invalid/other
339 * notification iterator object.
341 GHashTableIter ht_iter
;
342 gpointer stream_gptr
, stream_state_gptr
;
344 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
346 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
349 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
350 bt_ctf_stream_remove_destroy_listener(
351 (void *) stream_gptr
, stream_destroy_listener
,
355 g_hash_table_destroy(iterator
->stream_states
);
358 if (iterator
->actions
) {
359 g_array_free(iterator
->actions
, TRUE
);
362 if (iterator
->connection
) {
364 * Remove ourself from the originating connection so
365 * that it does not try to finalize a dangling pointer
368 bt_connection_remove_iterator(iterator
->connection
, iterator
);
371 BT_LOGD_STR("Putting current notification.");
372 bt_put(iterator
->current_notification
);
377 void bt_notification_iterator_finalize(
378 struct bt_notification_iterator
*iterator
)
380 struct bt_component_class
*comp_class
= NULL
;
381 bt_component_class_notification_iterator_finalize_method
382 finalize_method
= NULL
;
386 switch (iterator
->state
) {
387 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
388 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
389 /* Already finalized */
390 BT_LOGD("Not finalizing notification iterator: already finalized: "
391 "addr=%p", iterator
);
397 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
399 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_ENDED
) {
400 BT_LOGD("Updating notification iterator's state: "
401 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
402 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
404 BT_LOGD("Updating notification iterator's state: "
405 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
406 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
409 assert(iterator
->upstream_component
);
410 comp_class
= iterator
->upstream_component
->class;
412 /* Call user-defined destroy method */
413 switch (comp_class
->type
) {
414 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
416 struct bt_component_class_source
*source_class
;
418 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
419 finalize_method
= source_class
->methods
.iterator
.finalize
;
422 case BT_COMPONENT_CLASS_TYPE_FILTER
:
424 struct bt_component_class_filter
*filter_class
;
426 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
427 finalize_method
= filter_class
->methods
.iterator
.finalize
;
435 if (finalize_method
) {
436 BT_LOGD("Calling user's finalization method: addr=%p",
439 bt_private_notification_iterator_from_notification_iterator(iterator
));
442 iterator
->upstream_component
= NULL
;
443 iterator
->upstream_port
= NULL
;
444 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
448 void bt_notification_iterator_set_connection(
449 struct bt_notification_iterator
*iterator
,
450 struct bt_connection
*connection
)
453 iterator
->connection
= connection
;
454 BT_LOGV("Set notification iterator's connection: "
455 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
459 int create_subscription_mask_from_notification_types(
460 struct bt_notification_iterator
*iterator
,
461 const enum bt_notification_type
*notif_types
)
463 const enum bt_notification_type
*notif_type
;
467 iterator
->subscription_mask
= 0;
469 for (notif_type
= notif_types
;
470 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
472 switch (*notif_type
) {
473 case BT_NOTIFICATION_TYPE_ALL
:
474 iterator
->subscription_mask
|=
475 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
476 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
477 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
478 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
479 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
480 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
482 case BT_NOTIFICATION_TYPE_EVENT
:
483 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
485 case BT_NOTIFICATION_TYPE_INACTIVITY
:
486 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
488 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
489 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
491 case BT_NOTIFICATION_TYPE_STREAM_END
:
492 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
494 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
495 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
497 case BT_NOTIFICATION_TYPE_PACKET_END
:
498 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
505 BT_LOGV("Added notification type to subscription mask: "
507 bt_notification_type_string(*notif_type
),
508 iterator
->subscription_mask
);
516 struct bt_notification_iterator
*bt_notification_iterator_create(
517 struct bt_component
*upstream_comp
,
518 struct bt_port
*upstream_port
,
519 const enum bt_notification_type
*notification_types
,
520 struct bt_connection
*connection
)
522 enum bt_component_class_type type
;
523 struct bt_notification_iterator
*iterator
= NULL
;
525 assert(upstream_comp
);
526 assert(upstream_port
);
527 assert(notification_types
);
528 assert(bt_port_is_connected(upstream_port
));
529 BT_LOGD("Creating notification iterator: "
530 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
531 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
533 upstream_comp
, bt_component_get_name(upstream_comp
),
534 upstream_port
, bt_port_get_name(upstream_port
),
536 type
= bt_component_get_class_type(upstream_comp
);
537 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
538 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
539 iterator
= g_new0(struct bt_notification_iterator
, 1);
541 BT_LOGE_STR("Failed to allocate one notification iterator.");
545 bt_object_init(iterator
, bt_notification_iterator_destroy
);
547 if (create_subscription_mask_from_notification_types(iterator
,
548 notification_types
)) {
549 BT_LOGW_STR("Cannot create subscription mask from notification types.");
553 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
554 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
555 if (!iterator
->stream_states
) {
556 BT_LOGE_STR("Failed to allocate a GHashTable.");
560 iterator
->queue
= g_queue_new();
561 if (!iterator
->queue
) {
562 BT_LOGE_STR("Failed to allocate a GQueue.");
566 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
567 if (!iterator
->actions
) {
568 BT_LOGE_STR("Failed to allocate a GArray.");
572 iterator
->upstream_component
= upstream_comp
;
573 iterator
->upstream_port
= upstream_port
;
574 iterator
->connection
= connection
;
575 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
;
576 BT_LOGD("Created notification iterator: "
577 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
578 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
579 "conn-addr=%p, iter-addr=%p",
580 upstream_comp
, bt_component_get_name(upstream_comp
),
581 upstream_port
, bt_port_get_name(upstream_port
),
582 connection
, iterator
);
592 void *bt_private_notification_iterator_get_user_data(
593 struct bt_private_notification_iterator
*private_iterator
)
595 struct bt_notification_iterator
*iterator
=
596 bt_notification_iterator_from_private(private_iterator
);
598 return iterator
? iterator
->user_data
: NULL
;
601 enum bt_notification_iterator_status
602 bt_private_notification_iterator_set_user_data(
603 struct bt_private_notification_iterator
*private_iterator
,
606 enum bt_notification_iterator_status ret
=
607 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
608 struct bt_notification_iterator
*iterator
=
609 bt_notification_iterator_from_private(private_iterator
);
612 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
613 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
617 iterator
->user_data
= data
;
618 BT_LOGV("Set notification iterator's user data: "
619 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
625 struct bt_notification
*bt_notification_iterator_get_notification(
626 struct bt_notification_iterator
*iterator
)
628 struct bt_notification
*notification
= NULL
;
631 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
635 notification
= bt_get(iterator
->current_notification
);
642 enum bt_notification_iterator_notif_type
643 bt_notification_iterator_notif_type_from_notif_type(
644 enum bt_notification_type notif_type
)
646 enum bt_notification_iterator_notif_type iter_notif_type
;
648 switch (notif_type
) {
649 case BT_NOTIFICATION_TYPE_EVENT
:
650 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
652 case BT_NOTIFICATION_TYPE_INACTIVITY
:
653 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
655 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
656 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
658 case BT_NOTIFICATION_TYPE_STREAM_END
:
659 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
661 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
662 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
664 case BT_NOTIFICATION_TYPE_PACKET_END
:
665 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
671 return iter_notif_type
;
675 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
676 struct bt_notification
*notif
,
677 struct bt_ctf_stream
*notif_stream
,
678 struct bt_ctf_packet
*notif_packet
)
680 bt_bool is_valid
= BT_TRUE
;
681 struct stream_state
*stream_state
;
682 struct bt_port
*stream_comp_cur_port
;
684 assert(notif_stream
);
685 stream_comp_cur_port
=
686 bt_ctf_stream_port_for_component(notif_stream
,
687 iterator
->upstream_component
);
688 if (!stream_comp_cur_port
) {
690 * This is the first time this notification iterator
691 * bumps into this stream. Add an action to map the
692 * iterator's upstream component to the iterator's
693 * upstream port in this stream.
695 struct action action
= {
696 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
697 .payload
.map_port_to_comp_in_stream
= {
698 .stream
= bt_get(notif_stream
),
699 .component
= bt_get(iterator
->upstream_component
),
700 .port
= bt_get(iterator
->upstream_port
),
704 add_action(iterator
, &action
);
706 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
708 * It looks like two different ports of the same
709 * component are emitting notifications which
710 * have references to the same stream. This is
711 * bad: the API guarantees that it can never
714 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
715 "stream-addr=%p, stream-name=\"%s\", "
716 "stream-comp-cur-port-addr=%p, "
717 "stream-comp-cur-port-name=%p, "
718 "iter-upstream-port-addr=%p, "
719 "iter-upstream-port-name=%s",
721 bt_ctf_stream_get_name(notif_stream
),
722 stream_comp_cur_port
,
723 bt_port_get_name(stream_comp_cur_port
),
724 iterator
->upstream_port
,
725 bt_port_get_name(iterator
->upstream_port
));
732 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
735 BT_LOGV("Stream state already exists: "
736 "stream-addr=%p, stream-name=\"%s\", "
737 "stream-state-addr=%p",
739 bt_ctf_stream_get_name(notif_stream
), stream_state
);
741 if (stream_state
->is_ended
) {
743 * There's a new notification which has a
744 * reference to a stream which, from this
745 * iterator's point of view, is ended ("end of
746 * stream" notification was returned). This is
747 * bad: the API guarantees that it can never
750 BT_LOGW("Stream is already ended: "
751 "stream-addr=%p, stream-name=\"%s\"",
753 bt_ctf_stream_get_name(notif_stream
));
758 switch (notif
->type
) {
759 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
761 * We already have a stream state, which means
762 * we already returned a "stream begin"
763 * notification: this is an invalid duplicate.
765 BT_LOGW("Duplicate stream beginning notification: "
766 "stream-addr=%p, stream-name=\"%s\"",
768 bt_ctf_stream_get_name(notif_stream
));
771 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
772 if (notif_packet
== stream_state
->cur_packet
) {
773 /* Duplicate "packet begin" notification */
774 BT_LOGW("Duplicate stream beginning notification: "
775 "stream-addr=%p, stream-name=\"%s\", "
778 bt_ctf_stream_get_name(notif_stream
),
794 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
795 enum bt_notification_type notif_type
)
797 uint32_t iter_notif_type
=
798 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
801 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
805 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
806 struct bt_notification
*notif
)
808 struct action action
= {
809 .type
= ACTION_TYPE_PUSH_NOTIF
,
814 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
818 action
.payload
.push_notif
.notif
= bt_get(notif
);
819 add_action(iterator
, &action
);
820 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
824 int add_action_push_notif_stream_begin(
825 struct bt_notification_iterator
*iterator
,
826 struct bt_ctf_stream
*stream
)
829 struct bt_notification
*stream_begin_notif
= NULL
;
831 if (!is_subscribed_to_notification_type(iterator
,
832 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
833 BT_LOGV("Not adding \"push stream beginning notification\" action: "
834 "notification iterator is not subscribed: addr=%p",
840 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
841 if (!stream_begin_notif
) {
842 BT_LOGE_STR("Cannot create stream beginning notification.");
846 add_action_push_notif(iterator
, stream_begin_notif
);
847 BT_LOGV("Added \"push stream beginning notification\" action: "
848 "stream-addr=%p, stream-name=\"%s\"",
849 stream
, bt_ctf_stream_get_name(stream
));
856 bt_put(stream_begin_notif
);
861 int add_action_push_notif_stream_end(
862 struct bt_notification_iterator
*iterator
,
863 struct bt_ctf_stream
*stream
)
866 struct bt_notification
*stream_end_notif
= NULL
;
868 if (!is_subscribed_to_notification_type(iterator
,
869 BT_NOTIFICATION_TYPE_STREAM_END
)) {
870 BT_LOGV("Not adding \"push stream end notification\" action: "
871 "notification iterator is not subscribed: addr=%p",
877 stream_end_notif
= bt_notification_stream_end_create(stream
);
878 if (!stream_end_notif
) {
879 BT_LOGE_STR("Cannot create stream end notification.");
883 add_action_push_notif(iterator
, stream_end_notif
);
884 BT_LOGV("Added \"push stream end notification\" action: "
885 "stream-addr=%p, stream-name=\"%s\"",
886 stream
, bt_ctf_stream_get_name(stream
));
893 bt_put(stream_end_notif
);
898 int add_action_push_notif_packet_begin(
899 struct bt_notification_iterator
*iterator
,
900 struct bt_ctf_packet
*packet
)
903 struct bt_notification
*packet_begin_notif
= NULL
;
905 if (!is_subscribed_to_notification_type(iterator
,
906 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
907 BT_LOGV("Not adding \"push packet beginning notification\" action: "
908 "notification iterator is not subscribed: addr=%p",
914 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
915 if (!packet_begin_notif
) {
916 BT_LOGE_STR("Cannot create packet beginning notification.");
920 add_action_push_notif(iterator
, packet_begin_notif
);
921 BT_LOGV("Added \"push packet beginning notification\" action: "
922 "packet-addr=%p", packet
);
929 bt_put(packet_begin_notif
);
934 int add_action_push_notif_packet_end(
935 struct bt_notification_iterator
*iterator
,
936 struct bt_ctf_packet
*packet
)
939 struct bt_notification
*packet_end_notif
= NULL
;
941 if (!is_subscribed_to_notification_type(iterator
,
942 BT_NOTIFICATION_TYPE_PACKET_END
)) {
943 BT_LOGV("Not adding \"push packet end notification\" action: "
944 "notification iterator is not subscribed: addr=%p",
950 packet_end_notif
= bt_notification_packet_end_create(packet
);
951 if (!packet_end_notif
) {
952 BT_LOGE_STR("Cannot create packet end notification.");
956 add_action_push_notif(iterator
, packet_end_notif
);
957 BT_LOGV("Added \"push packet end notification\" action: "
958 "packet-addr=%p", packet
);
965 bt_put(packet_end_notif
);
970 void add_action_set_stream_state_is_ended(
971 struct bt_notification_iterator
*iterator
,
972 struct stream_state
*stream_state
)
974 struct action action
= {
975 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
976 .payload
.set_stream_state_is_ended
= {
977 .stream_state
= stream_state
,
981 assert(stream_state
);
982 add_action(iterator
, &action
);
983 BT_LOGV("Added \"set stream state's ended\" action: "
984 "stream-state-addr=%p", stream_state
);
988 void add_action_set_stream_state_cur_packet(
989 struct bt_notification_iterator
*iterator
,
990 struct stream_state
*stream_state
,
991 struct bt_ctf_packet
*packet
)
993 struct action action
= {
994 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
995 .payload
.set_stream_state_cur_packet
= {
996 .stream_state
= stream_state
,
997 .packet
= bt_get(packet
),
1001 assert(stream_state
);
1002 add_action(iterator
, &action
);
1003 BT_LOGV("Added \"set stream state's current packet\" action: "
1004 "stream-state-addr=%p, packet-addr=%p",
1005 stream_state
, packet
);
1009 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
1010 struct bt_notification
*stream_begin_notif
,
1011 struct bt_ctf_stream
*notif_stream
,
1012 struct stream_state
**stream_state
)
1016 if (!notif_stream
) {
1018 * The notification does not reference any stream: no
1019 * need to get or create a stream state.
1024 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1026 if (!*stream_state
) {
1028 * This iterator did not bump into this stream yet:
1029 * create a stream state and a "stream begin"
1032 struct action action
= {
1033 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1034 .payload
.add_stream_state
= {
1035 .stream
= bt_get(notif_stream
),
1036 .stream_state
= NULL
,
1040 *stream_state
= create_stream_state(notif_stream
);
1041 if (!stream_state
) {
1042 BT_LOGE_STR("Cannot create stream state.");
1046 action
.payload
.add_stream_state
.stream_state
=
1048 add_action(iterator
, &action
);
1050 if (stream_begin_notif
) {
1051 add_action_push_notif(iterator
, stream_begin_notif
);
1053 ret
= add_action_push_notif_stream_begin(iterator
,
1056 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1065 destroy_stream_state(*stream_state
);
1073 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
1074 struct bt_notification
*packet_begin_notif
,
1075 struct bt_ctf_packet
*new_packet
,
1076 struct stream_state
*stream_state
)
1080 if (stream_state
->cur_packet
== new_packet
) {
1084 BT_LOGV("Handling packet switch: "
1085 "cur-packet-addr=%p, new-packet-addr=%p",
1086 stream_state
->cur_packet
, new_packet
);
1088 if (stream_state
->cur_packet
) {
1089 /* End of the current packet */
1090 ret
= add_action_push_notif_packet_end(iterator
,
1091 stream_state
->cur_packet
);
1093 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1098 /* Beginning of the new packet */
1099 if (packet_begin_notif
) {
1100 add_action_push_notif(iterator
, packet_begin_notif
);
1101 } else if (new_packet
) {
1102 ret
= add_action_push_notif_packet_begin(iterator
,
1105 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1110 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1122 int handle_notif_stream_begin(
1123 struct bt_notification_iterator
*iterator
,
1124 struct bt_notification
*notif
,
1125 struct bt_ctf_stream
*notif_stream
)
1128 struct stream_state
*stream_state
;
1130 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1131 assert(notif_stream
);
1132 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1135 BT_LOGE_STR("Cannot ensure that stream state exists.");
1149 int handle_notif_stream_end(
1150 struct bt_notification_iterator
*iterator
,
1151 struct bt_notification
*notif
,
1152 struct bt_ctf_stream
*notif_stream
)
1155 struct stream_state
*stream_state
;
1157 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1158 assert(notif_stream
);
1159 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1162 BT_LOGE_STR("Cannot ensure that stream state exists.");
1166 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1168 BT_LOGE_STR("Cannot handle packet switch.");
1172 add_action_push_notif(iterator
, notif
);
1173 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1184 int handle_notif_packet_begin(
1185 struct bt_notification_iterator
*iterator
,
1186 struct bt_notification
*notif
,
1187 struct bt_ctf_stream
*notif_stream
,
1188 struct bt_ctf_packet
*notif_packet
)
1191 struct stream_state
*stream_state
;
1193 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1194 assert(notif_packet
);
1195 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1198 BT_LOGE_STR("Cannot ensure that stream state exists.");
1202 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1204 BT_LOGE_STR("Cannot handle packet switch.");
1218 int handle_notif_packet_end(
1219 struct bt_notification_iterator
*iterator
,
1220 struct bt_notification
*notif
,
1221 struct bt_ctf_stream
*notif_stream
,
1222 struct bt_ctf_packet
*notif_packet
)
1225 struct stream_state
*stream_state
;
1227 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1228 assert(notif_packet
);
1229 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1232 BT_LOGE_STR("Cannot ensure that stream state exists.");
1236 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1238 BT_LOGE_STR("Cannot handle packet switch.");
1242 /* End of the current packet */
1243 add_action_push_notif(iterator
, notif
);
1244 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1255 int handle_notif_event(
1256 struct bt_notification_iterator
*iterator
,
1257 struct bt_notification
*notif
,
1258 struct bt_ctf_stream
*notif_stream
,
1259 struct bt_ctf_packet
*notif_packet
)
1262 struct stream_state
*stream_state
;
1264 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1265 assert(notif_packet
);
1266 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1269 BT_LOGE_STR("Cannot ensure that stream state exists.");
1273 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1275 BT_LOGE_STR("Cannot handle packet switch.");
1279 add_action_push_notif(iterator
, notif
);
1290 int enqueue_notification_and_automatic(
1291 struct bt_notification_iterator
*iterator
,
1292 struct bt_notification
*notif
)
1295 struct bt_ctf_event
*notif_event
= NULL
;
1296 struct bt_ctf_stream
*notif_stream
= NULL
;
1297 struct bt_ctf_packet
*notif_packet
= NULL
;
1301 BT_LOGV("Enqueuing user notification and automatic notifications: "
1302 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1304 // TODO: Skip most of this if the iterator is only subscribed
1305 // to event/inactivity notifications.
1307 /* Get the stream and packet referred by the notification */
1308 switch (notif
->type
) {
1309 case BT_NOTIFICATION_TYPE_EVENT
:
1310 notif_event
= bt_notification_event_borrow_event(notif
);
1311 assert(notif_event
);
1312 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1313 assert(notif_packet
);
1315 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1317 bt_notification_stream_begin_borrow_stream(notif
);
1318 assert(notif_stream
);
1320 case BT_NOTIFICATION_TYPE_STREAM_END
:
1321 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1322 assert(notif_stream
);
1324 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1326 bt_notification_packet_begin_borrow_packet(notif
);
1327 assert(notif_packet
);
1329 case BT_NOTIFICATION_TYPE_PACKET_END
:
1330 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1331 assert(notif_packet
);
1333 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1338 * Invalid type of notification. Only the notification
1339 * types above are allowed to be returned by a user
1346 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1347 assert(notif_stream
);
1350 if (!notif_stream
) {
1352 * The notification has no reference to a stream: it
1353 * cannot cause the creation of automatic notifications.
1355 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1359 if (!validate_notification(iterator
, notif
, notif_stream
,
1361 BT_LOGW_STR("Invalid notification.");
1366 switch (notif
->type
) {
1367 case BT_NOTIFICATION_TYPE_EVENT
:
1368 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1371 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1372 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1374 case BT_NOTIFICATION_TYPE_STREAM_END
:
1375 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1377 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1378 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1381 case BT_NOTIFICATION_TYPE_PACKET_END
:
1382 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1385 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1386 add_action_push_notif(iterator
, notif
);
1393 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1397 apply_actions(iterator
);
1398 BT_LOGV("Enqueued user notification and automatic notifications: "
1399 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1410 int handle_end(struct bt_notification_iterator
*iterator
)
1412 GHashTableIter stream_state_iter
;
1413 gpointer stream_gptr
, stream_state_gptr
;
1416 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
1419 * Emit a "stream end" notification for each non-ended stream
1420 * known by this iterator and mark them as ended.
1422 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1424 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1425 &stream_state_gptr
)) {
1426 struct stream_state
*stream_state
= stream_state_gptr
;
1428 assert(stream_state_gptr
);
1430 if (stream_state
->is_ended
) {
1434 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1436 BT_LOGE_STR("Cannot handle packet switch.");
1440 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1442 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
1446 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1449 apply_actions(iterator
);
1450 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
1461 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1462 struct bt_notification_iterator
*iterator
)
1464 struct bt_private_notification_iterator
*priv_iterator
=
1465 bt_private_notification_iterator_from_notification_iterator(iterator
);
1466 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1467 struct bt_notification_iterator_next_return next_return
= {
1468 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1469 .notification
= NULL
,
1471 enum bt_notification_iterator_status status
=
1472 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1476 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
1477 "iter-addr=%p, queue-size=%u, iter-state=%s",
1478 iterator
, iterator
->queue
->length
,
1479 bt_notification_iterator_state_string(iterator
->state
));
1481 if (iterator
->queue
->length
> 0) {
1483 * We already have enough. Even if this notification
1484 * iterator is finalized, its user can still flush its
1485 * current queue's content by calling its "next" method
1486 * since this content is local and has no impact on what
1487 * used to be the iterator's upstream component.
1489 BT_LOGD_STR("Queue already has at least one notification.");
1493 switch (iterator
->state
) {
1494 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
1495 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
1496 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
1497 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1499 case BT_NOTIFICATION_ITERATOR_STATE_ENDED
:
1500 BT_LOGD_STR("Notification iterator is ended.");
1501 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1507 assert(iterator
->upstream_component
);
1508 assert(iterator
->upstream_component
->class);
1510 /* Pick the appropriate "next" method */
1511 switch (iterator
->upstream_component
->class->type
) {
1512 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1514 struct bt_component_class_source
*source_class
=
1515 container_of(iterator
->upstream_component
->class,
1516 struct bt_component_class_source
, parent
);
1518 assert(source_class
->methods
.iterator
.next
);
1519 next_method
= source_class
->methods
.iterator
.next
;
1522 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1524 struct bt_component_class_filter
*filter_class
=
1525 container_of(iterator
->upstream_component
->class,
1526 struct bt_component_class_filter
, parent
);
1528 assert(filter_class
->methods
.iterator
.next
);
1529 next_method
= filter_class
->methods
.iterator
.next
;
1537 * Call the user's "next" method to get the next notification
1540 assert(next_method
);
1542 while (iterator
->queue
->length
== 0) {
1543 BT_LOGD_STR("Calling user's \"next\" method.");
1544 next_return
= next_method(priv_iterator
);
1545 BT_LOGD("User method returned: status=%s",
1546 bt_notification_iterator_status_string(next_return
.status
));
1547 if (next_return
.status
< 0) {
1548 BT_LOGW_STR("User method failed.");
1549 status
= next_return
.status
;
1553 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
||
1554 iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
) {
1556 * The user's "next" method, somehow, cancelled
1557 * its own notification iterator. This can
1558 * happen, for example, when the user's method
1559 * removes the port on which there's the
1560 * connection from which the iterator was
1561 * created. In this case, said connection is
1562 * ended, and all its notification iterators are
1565 * Only bt_put() the returned notification if
1567 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
1568 * otherwise this field could be garbage.
1570 if (next_return
.status
==
1571 BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1572 bt_put(next_return
.notification
);
1575 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1579 switch (next_return
.status
) {
1580 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1581 ret
= handle_end(iterator
);
1583 BT_LOGW_STR("Cannot handle end of iteration.");
1584 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1588 assert(iterator
->state
==
1589 BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
);
1590 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ENDED
;
1592 if (iterator
->queue
->length
== 0) {
1593 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1596 BT_LOGD("Set new status: status=%s",
1597 bt_notification_iterator_status_string(status
));
1599 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1600 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1602 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1603 if (!next_return
.notification
) {
1604 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
1605 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1610 * We know the notification is valid. Before we
1611 * push it to the head of the queue, push the
1612 * appropriate automatic notifications if any.
1614 ret
= enqueue_notification_and_automatic(iterator
,
1615 next_return
.notification
);
1616 BT_PUT(next_return
.notification
);
1618 BT_LOGW("Cannot enqueue notification and automatic notifications.");
1619 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1624 /* Unknown non-error status */
1633 enum bt_notification_iterator_status
1634 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1636 enum bt_notification_iterator_status status
;
1639 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
1640 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1644 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
1647 * Make sure that the iterator's queue contains at least one
1650 status
= ensure_queue_has_notifications(iterator
);
1651 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1657 * Move the notification at the tail of the queue to the
1658 * iterator's current notification.
1660 assert(iterator
->queue
->length
> 0);
1661 bt_put(iterator
->current_notification
);
1662 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1663 assert(iterator
->current_notification
);
1669 struct bt_component
*bt_notification_iterator_get_component(
1670 struct bt_notification_iterator
*iterator
)
1672 return bt_get(iterator
->upstream_component
);
1675 struct bt_private_component
*
1676 bt_private_notification_iterator_get_private_component(
1677 struct bt_private_notification_iterator
*private_iterator
)
1679 return bt_private_component_from_component(
1680 bt_notification_iterator_get_component(
1681 bt_notification_iterator_from_private(private_iterator
)));
1684 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1685 struct bt_notification_iterator
*iterator
,
1686 enum bt_notification_iterator_seek_origin seek_origin
,
1689 enum bt_notification_iterator_status ret
=
1690 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;