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.h>
37 #include <babeltrace/graph/connection-internal.h>
38 #include <babeltrace/graph/component.h>
39 #include <babeltrace/graph/component-source-internal.h>
40 #include <babeltrace/graph/component-class-internal.h>
41 #include <babeltrace/graph/notification.h>
42 #include <babeltrace/graph/notification-iterator.h>
43 #include <babeltrace/graph/notification-iterator-internal.h>
44 #include <babeltrace/graph/notification-internal.h>
45 #include <babeltrace/graph/notification-event.h>
46 #include <babeltrace/graph/notification-event-internal.h>
47 #include <babeltrace/graph/notification-packet.h>
48 #include <babeltrace/graph/notification-packet-internal.h>
49 #include <babeltrace/graph/notification-stream.h>
50 #include <babeltrace/graph/notification-stream-internal.h>
51 #include <babeltrace/graph/port.h>
52 #include <babeltrace/types.h>
57 struct bt_ctf_stream
*stream
; /* owned by this */
58 struct bt_ctf_packet
*cur_packet
; /* owned by this */
63 ACTION_TYPE_PUSH_NOTIF
,
64 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
65 ACTION_TYPE_ADD_STREAM_STATE
,
66 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
67 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
71 enum action_type type
;
73 /* ACTION_TYPE_PUSH_NOTIF */
75 struct bt_notification
*notif
; /* owned by this */
78 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
80 struct bt_ctf_stream
*stream
; /* owned by this */
81 struct bt_component
*component
; /* owned by this */
82 struct bt_port
*port
; /* owned by this */
83 } map_port_to_comp_in_stream
;
85 /* ACTION_TYPE_ADD_STREAM_STATE */
87 struct bt_ctf_stream
*stream
; /* owned by this */
88 struct stream_state
*stream_state
; /* owned by this */
91 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
93 struct stream_state
*stream_state
; /* weak */
94 } set_stream_state_is_ended
;
96 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
98 struct stream_state
*stream_state
; /* weak */
99 struct bt_ctf_packet
*packet
; /* owned by this */
100 } set_stream_state_cur_packet
;
105 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
107 struct bt_notification_iterator
*iterator
= data
;
109 /* Remove associated stream state */
110 g_hash_table_remove(iterator
->stream_states
, stream
);
114 void destroy_stream_state(struct stream_state
*stream_state
)
120 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
121 BT_LOGV_STR("Putting stream state's current packet.");
122 bt_put(stream_state
->cur_packet
);
123 BT_LOGV_STR("Putting stream state's stream.");
124 bt_put(stream_state
->stream
);
125 g_free(stream_state
);
129 void destroy_action(struct action
*action
)
133 switch (action
->type
) {
134 case ACTION_TYPE_PUSH_NOTIF
:
135 BT_PUT(action
->payload
.push_notif
.notif
);
137 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
138 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
139 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
140 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
142 case ACTION_TYPE_ADD_STREAM_STATE
:
143 BT_PUT(action
->payload
.add_stream_state
.stream
);
144 destroy_stream_state(
145 action
->payload
.add_stream_state
.stream_state
);
146 action
->payload
.add_stream_state
.stream_state
= NULL
;
148 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
149 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
151 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
159 void add_action(struct bt_notification_iterator
*iterator
,
160 struct action
*action
)
162 g_array_append_val(iterator
->actions
, *action
);
166 void clear_actions(struct bt_notification_iterator
*iterator
)
170 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
171 struct action
*action
= &g_array_index(iterator
->actions
,
174 destroy_action(action
);
177 g_array_set_size(iterator
->actions
, 0);
181 const char *action_type_string(enum action_type type
)
184 case ACTION_TYPE_PUSH_NOTIF
:
185 return "ACTION_TYPE_PUSH_NOTIF";
186 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
187 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
188 case ACTION_TYPE_ADD_STREAM_STATE
:
189 return "ACTION_TYPE_ADD_STREAM_STATE";
190 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
191 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
192 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
193 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
200 void apply_actions(struct bt_notification_iterator
*iterator
)
204 BT_LOGV("Applying notification's iterator current actions: "
205 "count=%u", iterator
->actions
->len
);
207 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
208 struct action
*action
= &g_array_index(iterator
->actions
,
211 BT_LOGV("Applying action: index=%zu, type=%s",
212 i
, action_type_string(action
->type
));
214 switch (action
->type
) {
215 case ACTION_TYPE_PUSH_NOTIF
:
216 /* Move notification to queue */
217 g_queue_push_head(iterator
->queue
,
218 action
->payload
.push_notif
.notif
);
219 bt_notification_freeze(
220 action
->payload
.push_notif
.notif
);
221 action
->payload
.push_notif
.notif
= NULL
;
223 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
224 bt_ctf_stream_map_component_to_port(
225 action
->payload
.map_port_to_comp_in_stream
.stream
,
226 action
->payload
.map_port_to_comp_in_stream
.component
,
227 action
->payload
.map_port_to_comp_in_stream
.port
);
229 case ACTION_TYPE_ADD_STREAM_STATE
:
230 /* Move stream state to hash table */
231 g_hash_table_insert(iterator
->stream_states
,
232 action
->payload
.add_stream_state
.stream
,
233 action
->payload
.add_stream_state
.stream_state
);
235 action
->payload
.add_stream_state
.stream_state
= NULL
;
237 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
239 * We know that this stream is ended. We need to
240 * remember this as long as the stream exists to
241 * enforce that the same stream does not end
244 * Here we add a destroy listener to the stream
245 * which we put after (becomes weak as the hash
246 * table key). If we were the last object to own
247 * this stream, the destroy listener is called
248 * when we call bt_put() which removes this
249 * stream state completely. This is important
250 * because the memory used by this stream object
251 * could be reused for another stream, and they
252 * must have different states.
254 bt_ctf_stream_add_destroy_listener(
255 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
256 stream_destroy_listener
, iterator
);
257 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
258 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
260 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
261 /* Move packet to stream state's current packet */
262 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
263 action
->payload
.set_stream_state_cur_packet
.packet
);
270 clear_actions(iterator
);
274 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
276 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
279 BT_LOGE_STR("Failed to allocate one stream state.");
284 * We keep a reference to the stream until we know it's ended
285 * because we need to be able to create an automatic "stream
286 * end" notification when the user's "next" method returns
287 * BT_NOTIFICATION_ITERATOR_STATUS_END.
289 * We put this reference when the stream is marked as ended.
291 stream_state
->stream
= bt_get(stream
);
292 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
293 "stream-state-addr=%p",
294 stream
, bt_ctf_stream_get_name(stream
), stream_state
);
301 void bt_notification_iterator_destroy(struct bt_object
*obj
)
303 struct bt_notification_iterator
*iterator
;
308 * The notification iterator's reference count is 0 if we're
309 * here. Increment it to avoid a double-destroy (possibly
310 * infinitely recursive). This could happen for example if the
311 * notification iterator's finalization function does bt_get()
312 * (or anything that causes bt_get() to be called) on itself
313 * (ref. count goes from 0 to 1), and then bt_put(): the
314 * reference count would go from 1 to 0 again and this function
315 * would be called again.
317 obj
->ref_count
.count
++;
318 iterator
= container_of(obj
, struct bt_notification_iterator
, base
);
319 BT_LOGD("Destroying notification iterator object: addr=%p",
321 bt_notification_iterator_finalize(iterator
);
323 if (iterator
->queue
) {
324 struct bt_notification
*notif
;
326 BT_LOGD("Putting notifications in queue.");
328 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
332 g_queue_free(iterator
->queue
);
335 if (iterator
->stream_states
) {
337 * Remove our destroy listener from each stream which
338 * has a state in this iterator. Otherwise the destroy
339 * listener would be called with an invalid/other
340 * notification iterator object.
342 GHashTableIter ht_iter
;
343 gpointer stream_gptr
, stream_state_gptr
;
345 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
347 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
350 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
351 bt_ctf_stream_remove_destroy_listener(
352 (void *) stream_gptr
, stream_destroy_listener
,
356 g_hash_table_destroy(iterator
->stream_states
);
359 if (iterator
->actions
) {
360 g_array_free(iterator
->actions
, TRUE
);
363 if (iterator
->connection
) {
365 * Remove ourself from the originating connection so
366 * that it does not try to finalize a dangling pointer
369 bt_connection_remove_iterator(iterator
->connection
, iterator
);
372 BT_LOGD_STR("Putting current notification.");
373 bt_put(iterator
->current_notification
);
378 void bt_notification_iterator_finalize(
379 struct bt_notification_iterator
*iterator
)
381 struct bt_component_class
*comp_class
= NULL
;
382 bt_component_class_notification_iterator_finalize_method
383 finalize_method
= NULL
;
387 switch (iterator
->state
) {
388 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
389 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
390 /* Already finalized */
391 BT_LOGD("Not finalizing notification iterator: already finalized: "
392 "addr=%p", iterator
);
398 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
400 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_ENDED
) {
401 BT_LOGD("Updating notification iterator's state: "
402 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
403 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
405 BT_LOGD("Updating notification iterator's state: "
406 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
407 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
410 assert(iterator
->upstream_component
);
411 comp_class
= iterator
->upstream_component
->class;
413 /* Call user-defined destroy method */
414 switch (comp_class
->type
) {
415 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
417 struct bt_component_class_source
*source_class
;
419 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
420 finalize_method
= source_class
->methods
.iterator
.finalize
;
423 case BT_COMPONENT_CLASS_TYPE_FILTER
:
425 struct bt_component_class_filter
*filter_class
;
427 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
428 finalize_method
= filter_class
->methods
.iterator
.finalize
;
436 if (finalize_method
) {
437 BT_LOGD("Calling user's finalization method: addr=%p",
440 bt_private_notification_iterator_from_notification_iterator(iterator
));
443 iterator
->upstream_component
= NULL
;
444 iterator
->upstream_port
= NULL
;
445 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
449 void bt_notification_iterator_set_connection(
450 struct bt_notification_iterator
*iterator
,
451 struct bt_connection
*connection
)
454 iterator
->connection
= connection
;
455 BT_LOGV("Set notification iterator's connection: "
456 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
460 int create_subscription_mask_from_notification_types(
461 struct bt_notification_iterator
*iterator
,
462 const enum bt_notification_type
*notif_types
)
464 const enum bt_notification_type
*notif_type
;
468 iterator
->subscription_mask
= 0;
470 for (notif_type
= notif_types
;
471 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
473 switch (*notif_type
) {
474 case BT_NOTIFICATION_TYPE_ALL
:
475 iterator
->subscription_mask
|=
476 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
477 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
478 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
479 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
480 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
481 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
483 case BT_NOTIFICATION_TYPE_EVENT
:
484 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
486 case BT_NOTIFICATION_TYPE_INACTIVITY
:
487 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
489 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
490 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
492 case BT_NOTIFICATION_TYPE_STREAM_END
:
493 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
495 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
496 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
498 case BT_NOTIFICATION_TYPE_PACKET_END
:
499 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
506 BT_LOGV("Added notification type to subscription mask: "
508 bt_notification_type_string(*notif_type
),
509 iterator
->subscription_mask
);
517 enum bt_connection_status
bt_notification_iterator_create(
518 struct bt_component
*upstream_comp
,
519 struct bt_port
*upstream_port
,
520 const enum bt_notification_type
*notification_types
,
521 struct bt_connection
*connection
,
522 struct bt_notification_iterator
**user_iterator
)
524 enum bt_connection_status status
= BT_CONNECTION_STATUS_OK
;
525 enum bt_component_class_type type
;
526 struct bt_notification_iterator
*iterator
= NULL
;
528 assert(upstream_comp
);
529 assert(upstream_port
);
530 assert(notification_types
);
531 assert(bt_port_is_connected(upstream_port
));
532 assert(user_iterator
);
533 BT_LOGD("Creating notification iterator: "
534 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
535 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
537 upstream_comp
, bt_component_get_name(upstream_comp
),
538 upstream_port
, bt_port_get_name(upstream_port
),
540 type
= bt_component_get_class_type(upstream_comp
);
541 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
542 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
543 iterator
= g_new0(struct bt_notification_iterator
, 1);
545 BT_LOGE_STR("Failed to allocate one notification iterator.");
546 status
= BT_CONNECTION_STATUS_NOMEM
;
550 bt_object_init(iterator
, bt_notification_iterator_destroy
);
552 if (create_subscription_mask_from_notification_types(iterator
,
553 notification_types
)) {
554 BT_LOGW_STR("Cannot create subscription mask from notification types.");
555 status
= BT_CONNECTION_STATUS_INVALID
;
559 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
560 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
561 if (!iterator
->stream_states
) {
562 BT_LOGE_STR("Failed to allocate a GHashTable.");
563 status
= BT_CONNECTION_STATUS_NOMEM
;
567 iterator
->queue
= g_queue_new();
568 if (!iterator
->queue
) {
569 BT_LOGE_STR("Failed to allocate a GQueue.");
570 status
= BT_CONNECTION_STATUS_NOMEM
;
574 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
575 if (!iterator
->actions
) {
576 BT_LOGE_STR("Failed to allocate a GArray.");
577 status
= BT_CONNECTION_STATUS_NOMEM
;
581 iterator
->upstream_component
= upstream_comp
;
582 iterator
->upstream_port
= upstream_port
;
583 iterator
->connection
= connection
;
584 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
;
585 BT_LOGD("Created notification iterator: "
586 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
587 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
588 "conn-addr=%p, iter-addr=%p",
589 upstream_comp
, bt_component_get_name(upstream_comp
),
590 upstream_port
, bt_port_get_name(upstream_port
),
591 connection
, iterator
);
592 BT_MOVE(*user_iterator
, iterator
);
599 void *bt_private_notification_iterator_get_user_data(
600 struct bt_private_notification_iterator
*private_iterator
)
602 struct bt_notification_iterator
*iterator
=
603 bt_notification_iterator_from_private(private_iterator
);
605 return iterator
? iterator
->user_data
: NULL
;
608 enum bt_notification_iterator_status
609 bt_private_notification_iterator_set_user_data(
610 struct bt_private_notification_iterator
*private_iterator
,
613 enum bt_notification_iterator_status ret
=
614 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
615 struct bt_notification_iterator
*iterator
=
616 bt_notification_iterator_from_private(private_iterator
);
619 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
620 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
624 iterator
->user_data
= data
;
625 BT_LOGV("Set notification iterator's user data: "
626 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
632 struct bt_notification
*bt_notification_iterator_get_notification(
633 struct bt_notification_iterator
*iterator
)
635 struct bt_notification
*notification
= NULL
;
638 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
642 notification
= bt_get(iterator
->current_notification
);
649 enum bt_notification_iterator_notif_type
650 bt_notification_iterator_notif_type_from_notif_type(
651 enum bt_notification_type notif_type
)
653 enum bt_notification_iterator_notif_type iter_notif_type
;
655 switch (notif_type
) {
656 case BT_NOTIFICATION_TYPE_EVENT
:
657 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
659 case BT_NOTIFICATION_TYPE_INACTIVITY
:
660 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
662 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
663 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
665 case BT_NOTIFICATION_TYPE_STREAM_END
:
666 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
668 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
669 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
671 case BT_NOTIFICATION_TYPE_PACKET_END
:
672 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
678 return iter_notif_type
;
682 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
683 struct bt_notification
*notif
,
684 struct bt_ctf_stream
*notif_stream
,
685 struct bt_ctf_packet
*notif_packet
)
687 bt_bool is_valid
= BT_TRUE
;
688 struct stream_state
*stream_state
;
689 struct bt_port
*stream_comp_cur_port
;
691 assert(notif_stream
);
692 stream_comp_cur_port
=
693 bt_ctf_stream_port_for_component(notif_stream
,
694 iterator
->upstream_component
);
695 if (!stream_comp_cur_port
) {
697 * This is the first time this notification iterator
698 * bumps into this stream. Add an action to map the
699 * iterator's upstream component to the iterator's
700 * upstream port in this stream.
702 struct action action
= {
703 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
704 .payload
.map_port_to_comp_in_stream
= {
705 .stream
= bt_get(notif_stream
),
706 .component
= bt_get(iterator
->upstream_component
),
707 .port
= bt_get(iterator
->upstream_port
),
711 add_action(iterator
, &action
);
713 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
715 * It looks like two different ports of the same
716 * component are emitting notifications which
717 * have references to the same stream. This is
718 * bad: the API guarantees that it can never
721 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
722 "stream-addr=%p, stream-name=\"%s\", "
723 "stream-comp-cur-port-addr=%p, "
724 "stream-comp-cur-port-name=%p, "
725 "iter-upstream-port-addr=%p, "
726 "iter-upstream-port-name=%s",
728 bt_ctf_stream_get_name(notif_stream
),
729 stream_comp_cur_port
,
730 bt_port_get_name(stream_comp_cur_port
),
731 iterator
->upstream_port
,
732 bt_port_get_name(iterator
->upstream_port
));
739 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
742 BT_LOGV("Stream state already exists: "
743 "stream-addr=%p, stream-name=\"%s\", "
744 "stream-state-addr=%p",
746 bt_ctf_stream_get_name(notif_stream
), stream_state
);
748 if (stream_state
->is_ended
) {
750 * There's a new notification which has a
751 * reference to a stream which, from this
752 * iterator's point of view, is ended ("end of
753 * stream" notification was returned). This is
754 * bad: the API guarantees that it can never
757 BT_LOGW("Stream is already ended: "
758 "stream-addr=%p, stream-name=\"%s\"",
760 bt_ctf_stream_get_name(notif_stream
));
765 switch (notif
->type
) {
766 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
768 * We already have a stream state, which means
769 * we already returned a "stream begin"
770 * notification: this is an invalid duplicate.
772 BT_LOGW("Duplicate stream beginning notification: "
773 "stream-addr=%p, stream-name=\"%s\"",
775 bt_ctf_stream_get_name(notif_stream
));
778 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
779 if (notif_packet
== stream_state
->cur_packet
) {
780 /* Duplicate "packet begin" notification */
781 BT_LOGW("Duplicate stream beginning notification: "
782 "stream-addr=%p, stream-name=\"%s\", "
785 bt_ctf_stream_get_name(notif_stream
),
801 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
802 enum bt_notification_type notif_type
)
804 uint32_t iter_notif_type
=
805 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
808 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
812 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
813 struct bt_notification
*notif
)
815 struct action action
= {
816 .type
= ACTION_TYPE_PUSH_NOTIF
,
821 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
825 action
.payload
.push_notif
.notif
= bt_get(notif
);
826 add_action(iterator
, &action
);
827 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
831 int add_action_push_notif_stream_begin(
832 struct bt_notification_iterator
*iterator
,
833 struct bt_ctf_stream
*stream
)
836 struct bt_notification
*stream_begin_notif
= NULL
;
838 if (!is_subscribed_to_notification_type(iterator
,
839 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
840 BT_LOGV("Not adding \"push stream beginning notification\" action: "
841 "notification iterator is not subscribed: addr=%p",
847 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
848 if (!stream_begin_notif
) {
849 BT_LOGE_STR("Cannot create stream beginning notification.");
853 add_action_push_notif(iterator
, stream_begin_notif
);
854 BT_LOGV("Added \"push stream beginning notification\" action: "
855 "stream-addr=%p, stream-name=\"%s\"",
856 stream
, bt_ctf_stream_get_name(stream
));
863 bt_put(stream_begin_notif
);
868 int add_action_push_notif_stream_end(
869 struct bt_notification_iterator
*iterator
,
870 struct bt_ctf_stream
*stream
)
873 struct bt_notification
*stream_end_notif
= NULL
;
875 if (!is_subscribed_to_notification_type(iterator
,
876 BT_NOTIFICATION_TYPE_STREAM_END
)) {
877 BT_LOGV("Not adding \"push stream end notification\" action: "
878 "notification iterator is not subscribed: addr=%p",
884 stream_end_notif
= bt_notification_stream_end_create(stream
);
885 if (!stream_end_notif
) {
886 BT_LOGE_STR("Cannot create stream end notification.");
890 add_action_push_notif(iterator
, stream_end_notif
);
891 BT_LOGV("Added \"push stream end notification\" action: "
892 "stream-addr=%p, stream-name=\"%s\"",
893 stream
, bt_ctf_stream_get_name(stream
));
900 bt_put(stream_end_notif
);
905 int add_action_push_notif_packet_begin(
906 struct bt_notification_iterator
*iterator
,
907 struct bt_ctf_packet
*packet
)
910 struct bt_notification
*packet_begin_notif
= NULL
;
912 if (!is_subscribed_to_notification_type(iterator
,
913 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
914 BT_LOGV("Not adding \"push packet beginning notification\" action: "
915 "notification iterator is not subscribed: addr=%p",
921 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
922 if (!packet_begin_notif
) {
923 BT_LOGE_STR("Cannot create packet beginning notification.");
927 add_action_push_notif(iterator
, packet_begin_notif
);
928 BT_LOGV("Added \"push packet beginning notification\" action: "
929 "packet-addr=%p", packet
);
936 bt_put(packet_begin_notif
);
941 int add_action_push_notif_packet_end(
942 struct bt_notification_iterator
*iterator
,
943 struct bt_ctf_packet
*packet
)
946 struct bt_notification
*packet_end_notif
= NULL
;
948 if (!is_subscribed_to_notification_type(iterator
,
949 BT_NOTIFICATION_TYPE_PACKET_END
)) {
950 BT_LOGV("Not adding \"push packet end notification\" action: "
951 "notification iterator is not subscribed: addr=%p",
957 packet_end_notif
= bt_notification_packet_end_create(packet
);
958 if (!packet_end_notif
) {
959 BT_LOGE_STR("Cannot create packet end notification.");
963 add_action_push_notif(iterator
, packet_end_notif
);
964 BT_LOGV("Added \"push packet end notification\" action: "
965 "packet-addr=%p", packet
);
972 bt_put(packet_end_notif
);
977 void add_action_set_stream_state_is_ended(
978 struct bt_notification_iterator
*iterator
,
979 struct stream_state
*stream_state
)
981 struct action action
= {
982 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
983 .payload
.set_stream_state_is_ended
= {
984 .stream_state
= stream_state
,
988 assert(stream_state
);
989 add_action(iterator
, &action
);
990 BT_LOGV("Added \"set stream state's ended\" action: "
991 "stream-state-addr=%p", stream_state
);
995 void add_action_set_stream_state_cur_packet(
996 struct bt_notification_iterator
*iterator
,
997 struct stream_state
*stream_state
,
998 struct bt_ctf_packet
*packet
)
1000 struct action action
= {
1001 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
1002 .payload
.set_stream_state_cur_packet
= {
1003 .stream_state
= stream_state
,
1004 .packet
= bt_get(packet
),
1008 assert(stream_state
);
1009 add_action(iterator
, &action
);
1010 BT_LOGV("Added \"set stream state's current packet\" action: "
1011 "stream-state-addr=%p, packet-addr=%p",
1012 stream_state
, packet
);
1016 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
1017 struct bt_notification
*stream_begin_notif
,
1018 struct bt_ctf_stream
*notif_stream
,
1019 struct stream_state
**stream_state
)
1023 if (!notif_stream
) {
1025 * The notification does not reference any stream: no
1026 * need to get or create a stream state.
1031 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1033 if (!*stream_state
) {
1035 * This iterator did not bump into this stream yet:
1036 * create a stream state and a "stream begin"
1039 struct action action
= {
1040 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1041 .payload
.add_stream_state
= {
1042 .stream
= bt_get(notif_stream
),
1043 .stream_state
= NULL
,
1047 *stream_state
= create_stream_state(notif_stream
);
1048 if (!stream_state
) {
1049 BT_LOGE_STR("Cannot create stream state.");
1053 action
.payload
.add_stream_state
.stream_state
=
1055 add_action(iterator
, &action
);
1057 if (stream_begin_notif
) {
1058 add_action_push_notif(iterator
, stream_begin_notif
);
1060 ret
= add_action_push_notif_stream_begin(iterator
,
1063 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1072 destroy_stream_state(*stream_state
);
1080 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
1081 struct bt_notification
*packet_begin_notif
,
1082 struct bt_ctf_packet
*new_packet
,
1083 struct stream_state
*stream_state
)
1087 if (stream_state
->cur_packet
== new_packet
) {
1091 BT_LOGV("Handling packet switch: "
1092 "cur-packet-addr=%p, new-packet-addr=%p",
1093 stream_state
->cur_packet
, new_packet
);
1095 if (stream_state
->cur_packet
) {
1096 /* End of the current packet */
1097 ret
= add_action_push_notif_packet_end(iterator
,
1098 stream_state
->cur_packet
);
1100 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1105 /* Beginning of the new packet */
1106 if (packet_begin_notif
) {
1107 add_action_push_notif(iterator
, packet_begin_notif
);
1108 } else if (new_packet
) {
1109 ret
= add_action_push_notif_packet_begin(iterator
,
1112 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1117 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1129 int handle_notif_stream_begin(
1130 struct bt_notification_iterator
*iterator
,
1131 struct bt_notification
*notif
,
1132 struct bt_ctf_stream
*notif_stream
)
1135 struct stream_state
*stream_state
;
1137 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1138 assert(notif_stream
);
1139 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1142 BT_LOGE_STR("Cannot ensure that stream state exists.");
1156 int handle_notif_stream_end(
1157 struct bt_notification_iterator
*iterator
,
1158 struct bt_notification
*notif
,
1159 struct bt_ctf_stream
*notif_stream
)
1162 struct stream_state
*stream_state
;
1164 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1165 assert(notif_stream
);
1166 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1169 BT_LOGE_STR("Cannot ensure that stream state exists.");
1173 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1175 BT_LOGE_STR("Cannot handle packet switch.");
1179 add_action_push_notif(iterator
, notif
);
1180 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1191 int handle_notif_packet_begin(
1192 struct bt_notification_iterator
*iterator
,
1193 struct bt_notification
*notif
,
1194 struct bt_ctf_stream
*notif_stream
,
1195 struct bt_ctf_packet
*notif_packet
)
1198 struct stream_state
*stream_state
;
1200 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1201 assert(notif_packet
);
1202 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1205 BT_LOGE_STR("Cannot ensure that stream state exists.");
1209 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1211 BT_LOGE_STR("Cannot handle packet switch.");
1225 int handle_notif_packet_end(
1226 struct bt_notification_iterator
*iterator
,
1227 struct bt_notification
*notif
,
1228 struct bt_ctf_stream
*notif_stream
,
1229 struct bt_ctf_packet
*notif_packet
)
1232 struct stream_state
*stream_state
;
1234 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1235 assert(notif_packet
);
1236 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1239 BT_LOGE_STR("Cannot ensure that stream state exists.");
1243 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1245 BT_LOGE_STR("Cannot handle packet switch.");
1249 /* End of the current packet */
1250 add_action_push_notif(iterator
, notif
);
1251 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1262 int handle_notif_event(
1263 struct bt_notification_iterator
*iterator
,
1264 struct bt_notification
*notif
,
1265 struct bt_ctf_stream
*notif_stream
,
1266 struct bt_ctf_packet
*notif_packet
)
1269 struct stream_state
*stream_state
;
1271 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1272 assert(notif_packet
);
1273 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1276 BT_LOGE_STR("Cannot ensure that stream state exists.");
1280 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1282 BT_LOGE_STR("Cannot handle packet switch.");
1286 add_action_push_notif(iterator
, notif
);
1297 int enqueue_notification_and_automatic(
1298 struct bt_notification_iterator
*iterator
,
1299 struct bt_notification
*notif
)
1302 struct bt_ctf_event
*notif_event
= NULL
;
1303 struct bt_ctf_stream
*notif_stream
= NULL
;
1304 struct bt_ctf_packet
*notif_packet
= NULL
;
1308 BT_LOGV("Enqueuing user notification and automatic notifications: "
1309 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1311 // TODO: Skip most of this if the iterator is only subscribed
1312 // to event/inactivity notifications.
1314 /* Get the stream and packet referred by the notification */
1315 switch (notif
->type
) {
1316 case BT_NOTIFICATION_TYPE_EVENT
:
1317 notif_event
= bt_notification_event_borrow_event(notif
);
1318 assert(notif_event
);
1319 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1320 assert(notif_packet
);
1322 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1324 bt_notification_stream_begin_borrow_stream(notif
);
1325 assert(notif_stream
);
1327 case BT_NOTIFICATION_TYPE_STREAM_END
:
1328 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1329 assert(notif_stream
);
1331 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1333 bt_notification_packet_begin_borrow_packet(notif
);
1334 assert(notif_packet
);
1336 case BT_NOTIFICATION_TYPE_PACKET_END
:
1337 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1338 assert(notif_packet
);
1340 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1345 * Invalid type of notification. Only the notification
1346 * types above are allowed to be returned by a user
1353 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1354 assert(notif_stream
);
1357 if (!notif_stream
) {
1359 * The notification has no reference to a stream: it
1360 * cannot cause the creation of automatic notifications.
1362 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1366 if (!validate_notification(iterator
, notif
, notif_stream
,
1368 BT_LOGW_STR("Invalid notification.");
1373 switch (notif
->type
) {
1374 case BT_NOTIFICATION_TYPE_EVENT
:
1375 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1378 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1379 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1381 case BT_NOTIFICATION_TYPE_STREAM_END
:
1382 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1384 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1385 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1388 case BT_NOTIFICATION_TYPE_PACKET_END
:
1389 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1392 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1393 add_action_push_notif(iterator
, notif
);
1400 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1404 apply_actions(iterator
);
1405 BT_LOGV("Enqueued user notification and automatic notifications: "
1406 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1417 int handle_end(struct bt_notification_iterator
*iterator
)
1419 GHashTableIter stream_state_iter
;
1420 gpointer stream_gptr
, stream_state_gptr
;
1423 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
1426 * Emit a "stream end" notification for each non-ended stream
1427 * known by this iterator and mark them as ended.
1429 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1431 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1432 &stream_state_gptr
)) {
1433 struct stream_state
*stream_state
= stream_state_gptr
;
1435 assert(stream_state_gptr
);
1437 if (stream_state
->is_ended
) {
1441 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1443 BT_LOGE_STR("Cannot handle packet switch.");
1447 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1449 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
1453 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1456 apply_actions(iterator
);
1457 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
1468 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1469 struct bt_notification_iterator
*iterator
)
1471 struct bt_private_notification_iterator
*priv_iterator
=
1472 bt_private_notification_iterator_from_notification_iterator(iterator
);
1473 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1474 struct bt_notification_iterator_next_return next_return
= {
1475 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1476 .notification
= NULL
,
1478 enum bt_notification_iterator_status status
=
1479 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1483 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
1484 "iter-addr=%p, queue-size=%u, iter-state=%s",
1485 iterator
, iterator
->queue
->length
,
1486 bt_notification_iterator_state_string(iterator
->state
));
1488 if (iterator
->queue
->length
> 0) {
1490 * We already have enough. Even if this notification
1491 * iterator is finalized, its user can still flush its
1492 * current queue's content by calling its "next" method
1493 * since this content is local and has no impact on what
1494 * used to be the iterator's upstream component.
1496 BT_LOGD_STR("Queue already has at least one notification.");
1500 switch (iterator
->state
) {
1501 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
1502 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
1503 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
1504 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1506 case BT_NOTIFICATION_ITERATOR_STATE_ENDED
:
1507 BT_LOGD_STR("Notification iterator is ended.");
1508 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1514 assert(iterator
->upstream_component
);
1515 assert(iterator
->upstream_component
->class);
1517 /* Pick the appropriate "next" method */
1518 switch (iterator
->upstream_component
->class->type
) {
1519 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1521 struct bt_component_class_source
*source_class
=
1522 container_of(iterator
->upstream_component
->class,
1523 struct bt_component_class_source
, parent
);
1525 assert(source_class
->methods
.iterator
.next
);
1526 next_method
= source_class
->methods
.iterator
.next
;
1529 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1531 struct bt_component_class_filter
*filter_class
=
1532 container_of(iterator
->upstream_component
->class,
1533 struct bt_component_class_filter
, parent
);
1535 assert(filter_class
->methods
.iterator
.next
);
1536 next_method
= filter_class
->methods
.iterator
.next
;
1544 * Call the user's "next" method to get the next notification
1547 assert(next_method
);
1549 while (iterator
->queue
->length
== 0) {
1550 BT_LOGD_STR("Calling user's \"next\" method.");
1551 next_return
= next_method(priv_iterator
);
1552 BT_LOGD("User method returned: status=%s",
1553 bt_notification_iterator_status_string(next_return
.status
));
1554 if (next_return
.status
< 0) {
1555 BT_LOGW_STR("User method failed.");
1556 status
= next_return
.status
;
1560 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
||
1561 iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
) {
1563 * The user's "next" method, somehow, cancelled
1564 * its own notification iterator. This can
1565 * happen, for example, when the user's method
1566 * removes the port on which there's the
1567 * connection from which the iterator was
1568 * created. In this case, said connection is
1569 * ended, and all its notification iterators are
1572 * Only bt_put() the returned notification if
1574 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
1575 * otherwise this field could be garbage.
1577 if (next_return
.status
==
1578 BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1579 bt_put(next_return
.notification
);
1582 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1586 switch (next_return
.status
) {
1587 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1588 ret
= handle_end(iterator
);
1590 BT_LOGW_STR("Cannot handle end of iteration.");
1591 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1595 assert(iterator
->state
==
1596 BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
);
1597 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ENDED
;
1599 if (iterator
->queue
->length
== 0) {
1600 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1603 BT_LOGD("Set new status: status=%s",
1604 bt_notification_iterator_status_string(status
));
1606 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1607 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1609 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1610 if (!next_return
.notification
) {
1611 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
1612 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1617 * We know the notification is valid. Before we
1618 * push it to the head of the queue, push the
1619 * appropriate automatic notifications if any.
1621 ret
= enqueue_notification_and_automatic(iterator
,
1622 next_return
.notification
);
1623 BT_PUT(next_return
.notification
);
1625 BT_LOGW("Cannot enqueue notification and automatic notifications.");
1626 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1631 /* Unknown non-error status */
1640 enum bt_notification_iterator_status
1641 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1643 enum bt_notification_iterator_status status
;
1646 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
1647 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1651 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
1654 * Make sure that the iterator's queue contains at least one
1657 status
= ensure_queue_has_notifications(iterator
);
1658 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1664 * Move the notification at the tail of the queue to the
1665 * iterator's current notification.
1667 assert(iterator
->queue
->length
> 0);
1668 bt_put(iterator
->current_notification
);
1669 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1670 assert(iterator
->current_notification
);
1676 struct bt_component
*bt_notification_iterator_get_component(
1677 struct bt_notification_iterator
*iterator
)
1679 return bt_get(iterator
->upstream_component
);
1682 struct bt_private_component
*
1683 bt_private_notification_iterator_get_private_component(
1684 struct bt_private_notification_iterator
*private_iterator
)
1686 return bt_private_component_from_component(
1687 bt_notification_iterator_get_component(
1688 bt_notification_iterator_from_private(private_iterator
)));
1691 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1692 struct bt_notification_iterator
*iterator
,
1693 enum bt_notification_iterator_seek_origin seek_origin
,
1696 enum bt_notification_iterator_status ret
=
1697 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;