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>
55 struct bt_ctf_stream
*stream
; /* owned by this */
56 struct bt_ctf_packet
*cur_packet
; /* owned by this */
61 ACTION_TYPE_PUSH_NOTIF
,
62 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
63 ACTION_TYPE_ADD_STREAM_STATE
,
64 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
65 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
69 enum action_type type
;
71 /* ACTION_TYPE_PUSH_NOTIF */
73 struct bt_notification
*notif
; /* owned by this */
76 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
78 struct bt_ctf_stream
*stream
; /* owned by this */
79 struct bt_component
*component
; /* owned by this */
80 struct bt_port
*port
; /* owned by this */
81 } map_port_to_comp_in_stream
;
83 /* ACTION_TYPE_ADD_STREAM_STATE */
85 struct bt_ctf_stream
*stream
; /* owned by this */
86 struct stream_state
*stream_state
; /* owned by this */
89 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
91 struct stream_state
*stream_state
; /* weak */
92 } set_stream_state_is_ended
;
94 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
96 struct stream_state
*stream_state
; /* weak */
97 struct bt_ctf_packet
*packet
; /* owned by this */
98 } set_stream_state_cur_packet
;
103 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
105 struct bt_notification_iterator
*iterator
= data
;
107 /* Remove associated stream state */
108 g_hash_table_remove(iterator
->stream_states
, stream
);
112 void destroy_stream_state(struct stream_state
*stream_state
)
118 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
119 BT_LOGV_STR("Putting stream state's current packet.");
120 bt_put(stream_state
->cur_packet
);
121 BT_LOGV_STR("Putting stream state's stream.");
122 bt_put(stream_state
->stream
);
123 g_free(stream_state
);
127 void destroy_action(struct action
*action
)
131 switch (action
->type
) {
132 case ACTION_TYPE_PUSH_NOTIF
:
133 BT_PUT(action
->payload
.push_notif
.notif
);
135 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
136 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
137 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
138 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
140 case ACTION_TYPE_ADD_STREAM_STATE
:
141 BT_PUT(action
->payload
.add_stream_state
.stream
);
142 destroy_stream_state(
143 action
->payload
.add_stream_state
.stream_state
);
144 action
->payload
.add_stream_state
.stream_state
= NULL
;
146 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
147 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
149 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
157 void add_action(struct bt_notification_iterator
*iterator
,
158 struct action
*action
)
160 g_array_append_val(iterator
->actions
, *action
);
164 void clear_actions(struct bt_notification_iterator
*iterator
)
168 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
169 struct action
*action
= &g_array_index(iterator
->actions
,
172 destroy_action(action
);
175 g_array_set_size(iterator
->actions
, 0);
179 const char *action_type_string(enum action_type type
)
182 case ACTION_TYPE_PUSH_NOTIF
:
183 return "ACTION_TYPE_PUSH_NOTIF";
184 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
185 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
186 case ACTION_TYPE_ADD_STREAM_STATE
:
187 return "ACTION_TYPE_ADD_STREAM_STATE";
188 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
189 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
190 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
191 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
198 void apply_actions(struct bt_notification_iterator
*iterator
)
202 BT_LOGV("Applying notification's iterator current actions: "
203 "count=%u", iterator
->actions
->len
);
205 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
206 struct action
*action
= &g_array_index(iterator
->actions
,
209 BT_LOGV("Applying action: index=%zu, type=%s",
210 i
, action_type_string(action
->type
));
212 switch (action
->type
) {
213 case ACTION_TYPE_PUSH_NOTIF
:
214 /* Move notification to queue */
215 g_queue_push_head(iterator
->queue
,
216 action
->payload
.push_notif
.notif
);
217 bt_notification_freeze(
218 action
->payload
.push_notif
.notif
);
219 action
->payload
.push_notif
.notif
= NULL
;
221 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
222 bt_ctf_stream_map_component_to_port(
223 action
->payload
.map_port_to_comp_in_stream
.stream
,
224 action
->payload
.map_port_to_comp_in_stream
.component
,
225 action
->payload
.map_port_to_comp_in_stream
.port
);
227 case ACTION_TYPE_ADD_STREAM_STATE
:
228 /* Move stream state to hash table */
229 g_hash_table_insert(iterator
->stream_states
,
230 action
->payload
.add_stream_state
.stream
,
231 action
->payload
.add_stream_state
.stream_state
);
233 action
->payload
.add_stream_state
.stream_state
= NULL
;
235 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
237 * We know that this stream is ended. We need to
238 * remember this as long as the stream exists to
239 * enforce that the same stream does not end
242 * Here we add a destroy listener to the stream
243 * which we put after (becomes weak as the hash
244 * table key). If we were the last object to own
245 * this stream, the destroy listener is called
246 * when we call bt_put() which removes this
247 * stream state completely. This is important
248 * because the memory used by this stream object
249 * could be reused for another stream, and they
250 * must have different states.
252 bt_ctf_stream_add_destroy_listener(
253 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
254 stream_destroy_listener
, iterator
);
255 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
256 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
258 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
259 /* Move packet to stream state's current packet */
260 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
261 action
->payload
.set_stream_state_cur_packet
.packet
);
268 clear_actions(iterator
);
272 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
274 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
277 BT_LOGE_STR("Failed to allocate one stream state.");
282 * We keep a reference to the stream until we know it's ended
283 * because we need to be able to create an automatic "stream
284 * end" notification when the user's "next" method returns
285 * BT_NOTIFICATION_ITERATOR_STATUS_END.
287 * We put this reference when the stream is marked as ended.
289 stream_state
->stream
= bt_get(stream
);
290 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
291 "stream-state-addr=%p",
292 stream
, bt_ctf_stream_get_name(stream
), stream_state
);
299 void bt_notification_iterator_destroy(struct bt_object
*obj
)
301 struct bt_notification_iterator
*iterator
;
306 * The notification iterator's reference count is 0 if we're
307 * here. Increment it to avoid a double-destroy (possibly
308 * infinitely recursive). This could happen for example if the
309 * notification iterator's finalization function does bt_get()
310 * (or anything that causes bt_get() to be called) on itself
311 * (ref. count goes from 0 to 1), and then bt_put(): the
312 * reference count would go from 1 to 0 again and this function
313 * would be called again.
315 obj
->ref_count
.count
++;
316 iterator
= container_of(obj
, struct bt_notification_iterator
, base
);
317 BT_LOGD("Destroying notification iterator object: addr=%p",
319 bt_notification_iterator_finalize(iterator
);
321 if (iterator
->queue
) {
322 struct bt_notification
*notif
;
324 BT_LOGD("Putting notifications in queue.");
326 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
330 g_queue_free(iterator
->queue
);
333 if (iterator
->stream_states
) {
335 * Remove our destroy listener from each stream which
336 * has a state in this iterator. Otherwise the destroy
337 * listener would be called with an invalid/other
338 * notification iterator object.
340 GHashTableIter ht_iter
;
341 gpointer stream_gptr
, stream_state_gptr
;
343 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
345 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
348 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
349 bt_ctf_stream_remove_destroy_listener(
350 (void *) stream_gptr
, stream_destroy_listener
,
354 g_hash_table_destroy(iterator
->stream_states
);
357 if (iterator
->actions
) {
358 g_array_free(iterator
->actions
, TRUE
);
361 if (iterator
->connection
) {
363 * Remove ourself from the originating connection so
364 * that it does not try to finalize a dangling pointer
367 bt_connection_remove_iterator(iterator
->connection
, iterator
);
370 BT_LOGD_STR("Putting current notification.");
371 bt_put(iterator
->current_notification
);
376 void bt_notification_iterator_finalize(
377 struct bt_notification_iterator
*iterator
)
379 struct bt_component_class
*comp_class
= NULL
;
380 bt_component_class_notification_iterator_finalize_method
381 finalize_method
= NULL
;
385 switch (iterator
->state
) {
386 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
387 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
388 /* Already finalized */
389 BT_LOGD("Not finalizing notification iterator: already finalized: "
390 "addr=%p", iterator
);
396 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
398 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_ENDED
) {
399 BT_LOGD("Updating notification iterator's state: "
400 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
401 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
403 BT_LOGD("Updating notification iterator's state: "
404 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
405 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
408 assert(iterator
->upstream_component
);
409 comp_class
= iterator
->upstream_component
->class;
411 /* Call user-defined destroy method */
412 switch (comp_class
->type
) {
413 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
415 struct bt_component_class_source
*source_class
;
417 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
418 finalize_method
= source_class
->methods
.iterator
.finalize
;
421 case BT_COMPONENT_CLASS_TYPE_FILTER
:
423 struct bt_component_class_filter
*filter_class
;
425 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
426 finalize_method
= filter_class
->methods
.iterator
.finalize
;
434 if (finalize_method
) {
435 BT_LOGD("Calling user's finalization method: addr=%p",
438 bt_private_notification_iterator_from_notification_iterator(iterator
));
441 iterator
->upstream_component
= NULL
;
442 iterator
->upstream_port
= NULL
;
443 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
447 void bt_notification_iterator_set_connection(
448 struct bt_notification_iterator
*iterator
,
449 struct bt_connection
*connection
)
452 iterator
->connection
= connection
;
453 BT_LOGV("Set notification iterator's connection: "
454 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
458 int create_subscription_mask_from_notification_types(
459 struct bt_notification_iterator
*iterator
,
460 const enum bt_notification_type
*notif_types
)
462 const enum bt_notification_type
*notif_type
;
466 iterator
->subscription_mask
= 0;
468 for (notif_type
= notif_types
;
469 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
471 switch (*notif_type
) {
472 case BT_NOTIFICATION_TYPE_ALL
:
473 iterator
->subscription_mask
|=
474 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
475 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
476 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
477 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
478 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
479 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
481 case BT_NOTIFICATION_TYPE_EVENT
:
482 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
484 case BT_NOTIFICATION_TYPE_INACTIVITY
:
485 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
487 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
488 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
490 case BT_NOTIFICATION_TYPE_STREAM_END
:
491 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
493 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
494 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
496 case BT_NOTIFICATION_TYPE_PACKET_END
:
497 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
504 BT_LOGV("Added notification type to subscription mask: "
506 bt_notification_type_string(*notif_type
),
507 iterator
->subscription_mask
);
515 struct bt_notification_iterator
*bt_notification_iterator_create(
516 struct bt_component
*upstream_comp
,
517 struct bt_port
*upstream_port
,
518 const enum bt_notification_type
*notification_types
,
519 struct bt_connection
*connection
)
521 enum bt_component_class_type type
;
522 struct bt_notification_iterator
*iterator
= NULL
;
524 assert(upstream_comp
);
525 assert(upstream_port
);
526 assert(notification_types
);
527 assert(bt_port_is_connected(upstream_port
));
528 BT_LOGD("Creating notification iterator: "
529 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
530 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
532 upstream_comp
, bt_component_get_name(upstream_comp
),
533 upstream_port
, bt_port_get_name(upstream_port
),
535 type
= bt_component_get_class_type(upstream_comp
);
536 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
537 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
538 iterator
= g_new0(struct bt_notification_iterator
, 1);
540 BT_LOGE_STR("Failed to allocate one notification iterator.");
544 bt_object_init(iterator
, bt_notification_iterator_destroy
);
546 if (create_subscription_mask_from_notification_types(iterator
,
547 notification_types
)) {
548 BT_LOGW_STR("Cannot create subscription mask from notification types.");
552 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
553 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
554 if (!iterator
->stream_states
) {
555 BT_LOGE_STR("Failed to allocate a GHashTable.");
559 iterator
->queue
= g_queue_new();
560 if (!iterator
->queue
) {
561 BT_LOGE_STR("Failed to allocate a GQueue.");
565 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
566 if (!iterator
->actions
) {
567 BT_LOGE_STR("Failed to allocate a GArray.");
571 iterator
->upstream_component
= upstream_comp
;
572 iterator
->upstream_port
= upstream_port
;
573 iterator
->connection
= connection
;
574 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
;
575 BT_LOGD("Created notification iterator: "
576 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
577 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
578 "conn-addr=%p, iter-addr=%p",
579 upstream_comp
, bt_component_get_name(upstream_comp
),
580 upstream_port
, bt_port_get_name(upstream_port
),
581 connection
, iterator
);
591 void *bt_private_notification_iterator_get_user_data(
592 struct bt_private_notification_iterator
*private_iterator
)
594 struct bt_notification_iterator
*iterator
=
595 bt_notification_iterator_from_private(private_iterator
);
597 return iterator
? iterator
->user_data
: NULL
;
600 enum bt_notification_iterator_status
601 bt_private_notification_iterator_set_user_data(
602 struct bt_private_notification_iterator
*private_iterator
,
605 enum bt_notification_iterator_status ret
=
606 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
607 struct bt_notification_iterator
*iterator
=
608 bt_notification_iterator_from_private(private_iterator
);
611 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
612 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
616 iterator
->user_data
= data
;
617 BT_LOGV("Set notification iterator's user data: "
618 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
624 struct bt_notification
*bt_notification_iterator_get_notification(
625 struct bt_notification_iterator
*iterator
)
627 struct bt_notification
*notification
= NULL
;
630 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
634 notification
= bt_get(iterator
->current_notification
);
641 enum bt_notification_iterator_notif_type
642 bt_notification_iterator_notif_type_from_notif_type(
643 enum bt_notification_type notif_type
)
645 enum bt_notification_iterator_notif_type iter_notif_type
;
647 switch (notif_type
) {
648 case BT_NOTIFICATION_TYPE_EVENT
:
649 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
651 case BT_NOTIFICATION_TYPE_INACTIVITY
:
652 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
654 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
655 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
657 case BT_NOTIFICATION_TYPE_STREAM_END
:
658 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
660 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
661 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
663 case BT_NOTIFICATION_TYPE_PACKET_END
:
664 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
670 return iter_notif_type
;
674 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
675 struct bt_notification
*notif
,
676 struct bt_ctf_stream
*notif_stream
,
677 struct bt_ctf_packet
*notif_packet
)
679 bt_bool is_valid
= BT_TRUE
;
680 struct stream_state
*stream_state
;
681 struct bt_port
*stream_comp_cur_port
;
683 assert(notif_stream
);
684 stream_comp_cur_port
=
685 bt_ctf_stream_port_for_component(notif_stream
,
686 iterator
->upstream_component
);
687 if (!stream_comp_cur_port
) {
689 * This is the first time this notification iterator
690 * bumps into this stream. Add an action to map the
691 * iterator's upstream component to the iterator's
692 * upstream port in this stream.
694 struct action action
= {
695 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
696 .payload
.map_port_to_comp_in_stream
= {
697 .stream
= bt_get(notif_stream
),
698 .component
= bt_get(iterator
->upstream_component
),
699 .port
= bt_get(iterator
->upstream_port
),
703 add_action(iterator
, &action
);
705 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
707 * It looks like two different ports of the same
708 * component are emitting notifications which
709 * have references to the same stream. This is
710 * bad: the API guarantees that it can never
713 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
714 "stream-addr=%p, stream-name=\"%s\", "
715 "stream-comp-cur-port-addr=%p, "
716 "stream-comp-cur-port-name=%p, "
717 "iter-upstream-port-addr=%p, "
718 "iter-upstream-port-name=%s",
720 bt_ctf_stream_get_name(notif_stream
),
721 stream_comp_cur_port
,
722 bt_port_get_name(stream_comp_cur_port
),
723 iterator
->upstream_port
,
724 bt_port_get_name(iterator
->upstream_port
));
731 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
734 BT_LOGV("Stream state already exists: "
735 "stream-addr=%p, stream-name=\"%s\", "
736 "stream-state-addr=%p",
738 bt_ctf_stream_get_name(notif_stream
), stream_state
);
740 if (stream_state
->is_ended
) {
742 * There's a new notification which has a
743 * reference to a stream which, from this
744 * iterator's point of view, is ended ("end of
745 * stream" notification was returned). This is
746 * bad: the API guarantees that it can never
749 BT_LOGW("Stream is already ended: "
750 "stream-addr=%p, stream-name=\"%s\"",
752 bt_ctf_stream_get_name(notif_stream
));
757 switch (notif
->type
) {
758 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
760 * We already have a stream state, which means
761 * we already returned a "stream begin"
762 * notification: this is an invalid duplicate.
764 BT_LOGW("Duplicate stream beginning notification: "
765 "stream-addr=%p, stream-name=\"%s\"",
767 bt_ctf_stream_get_name(notif_stream
));
770 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
771 if (notif_packet
== stream_state
->cur_packet
) {
772 /* Duplicate "packet begin" notification */
773 BT_LOGW("Duplicate stream beginning notification: "
774 "stream-addr=%p, stream-name=\"%s\", "
777 bt_ctf_stream_get_name(notif_stream
),
793 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
794 enum bt_notification_type notif_type
)
796 uint32_t iter_notif_type
=
797 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
800 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
804 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
805 struct bt_notification
*notif
)
807 struct action action
= {
808 .type
= ACTION_TYPE_PUSH_NOTIF
,
813 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
817 action
.payload
.push_notif
.notif
= bt_get(notif
);
818 add_action(iterator
, &action
);
819 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
823 int add_action_push_notif_stream_begin(
824 struct bt_notification_iterator
*iterator
,
825 struct bt_ctf_stream
*stream
)
828 struct bt_notification
*stream_begin_notif
= NULL
;
830 if (!is_subscribed_to_notification_type(iterator
,
831 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
832 BT_LOGV("Not adding \"push stream beginning notification\" action: "
833 "notification iterator is not subscribed: addr=%p",
839 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
840 if (!stream_begin_notif
) {
841 BT_LOGE_STR("Cannot create stream beginning notification.");
845 add_action_push_notif(iterator
, stream_begin_notif
);
846 BT_LOGV("Added \"push stream beginning notification\" action: "
847 "stream-addr=%p, stream-name=\"%s\"",
848 stream
, bt_ctf_stream_get_name(stream
));
855 bt_put(stream_begin_notif
);
860 int add_action_push_notif_stream_end(
861 struct bt_notification_iterator
*iterator
,
862 struct bt_ctf_stream
*stream
)
865 struct bt_notification
*stream_end_notif
= NULL
;
867 if (!is_subscribed_to_notification_type(iterator
,
868 BT_NOTIFICATION_TYPE_STREAM_END
)) {
869 BT_LOGV("Not adding \"push stream end notification\" action: "
870 "notification iterator is not subscribed: addr=%p",
876 stream_end_notif
= bt_notification_stream_end_create(stream
);
877 if (!stream_end_notif
) {
878 BT_LOGE_STR("Cannot create stream end notification.");
882 add_action_push_notif(iterator
, stream_end_notif
);
883 BT_LOGV("Added \"push stream end notification\" action: "
884 "stream-addr=%p, stream-name=\"%s\"",
885 stream
, bt_ctf_stream_get_name(stream
));
892 bt_put(stream_end_notif
);
897 int add_action_push_notif_packet_begin(
898 struct bt_notification_iterator
*iterator
,
899 struct bt_ctf_packet
*packet
)
902 struct bt_notification
*packet_begin_notif
= NULL
;
904 if (!is_subscribed_to_notification_type(iterator
,
905 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
906 BT_LOGV("Not adding \"push packet beginning notification\" action: "
907 "notification iterator is not subscribed: addr=%p",
913 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
914 if (!packet_begin_notif
) {
915 BT_LOGE_STR("Cannot create packet beginning notification.");
919 add_action_push_notif(iterator
, packet_begin_notif
);
920 BT_LOGV("Added \"push packet beginning notification\" action: "
921 "packet-addr=%p", packet
);
928 bt_put(packet_begin_notif
);
933 int add_action_push_notif_packet_end(
934 struct bt_notification_iterator
*iterator
,
935 struct bt_ctf_packet
*packet
)
938 struct bt_notification
*packet_end_notif
= NULL
;
940 if (!is_subscribed_to_notification_type(iterator
,
941 BT_NOTIFICATION_TYPE_PACKET_END
)) {
942 BT_LOGV("Not adding \"push packet end notification\" action: "
943 "notification iterator is not subscribed: addr=%p",
949 packet_end_notif
= bt_notification_packet_end_create(packet
);
950 if (!packet_end_notif
) {
951 BT_LOGE_STR("Cannot create packet end notification.");
955 add_action_push_notif(iterator
, packet_end_notif
);
956 BT_LOGV("Added \"push packet end notification\" action: "
957 "packet-addr=%p", packet
);
964 bt_put(packet_end_notif
);
969 void add_action_set_stream_state_is_ended(
970 struct bt_notification_iterator
*iterator
,
971 struct stream_state
*stream_state
)
973 struct action action
= {
974 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
975 .payload
.set_stream_state_is_ended
= {
976 .stream_state
= stream_state
,
980 assert(stream_state
);
981 add_action(iterator
, &action
);
982 BT_LOGV("Added \"set stream state's ended\" action: "
983 "stream-state-addr=%p", stream_state
);
987 void add_action_set_stream_state_cur_packet(
988 struct bt_notification_iterator
*iterator
,
989 struct stream_state
*stream_state
,
990 struct bt_ctf_packet
*packet
)
992 struct action action
= {
993 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
994 .payload
.set_stream_state_cur_packet
= {
995 .stream_state
= stream_state
,
996 .packet
= bt_get(packet
),
1000 assert(stream_state
);
1001 add_action(iterator
, &action
);
1002 BT_LOGV("Added \"set stream state's current packet\" action: "
1003 "stream-state-addr=%p, packet-addr=%p",
1004 stream_state
, packet
);
1008 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
1009 struct bt_notification
*stream_begin_notif
,
1010 struct bt_ctf_stream
*notif_stream
,
1011 struct stream_state
**stream_state
)
1015 if (!notif_stream
) {
1017 * The notification does not reference any stream: no
1018 * need to get or create a stream state.
1023 *stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1025 if (!*stream_state
) {
1027 * This iterator did not bump into this stream yet:
1028 * create a stream state and a "stream begin"
1031 struct action action
= {
1032 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1033 .payload
.add_stream_state
= {
1034 .stream
= bt_get(notif_stream
),
1035 .stream_state
= NULL
,
1039 *stream_state
= create_stream_state(notif_stream
);
1040 if (!stream_state
) {
1041 BT_LOGE_STR("Cannot create stream state.");
1045 action
.payload
.add_stream_state
.stream_state
=
1047 add_action(iterator
, &action
);
1049 if (stream_begin_notif
) {
1050 add_action_push_notif(iterator
, stream_begin_notif
);
1052 ret
= add_action_push_notif_stream_begin(iterator
,
1055 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1064 destroy_stream_state(*stream_state
);
1072 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
1073 struct bt_notification
*packet_begin_notif
,
1074 struct bt_ctf_packet
*new_packet
,
1075 struct stream_state
*stream_state
)
1079 if (stream_state
->cur_packet
== new_packet
) {
1083 BT_LOGV("Handling packet switch: "
1084 "cur-packet-addr=%p, new-packet-addr=%p",
1085 stream_state
->cur_packet
, new_packet
);
1087 if (stream_state
->cur_packet
) {
1088 /* End of the current packet */
1089 ret
= add_action_push_notif_packet_end(iterator
,
1090 stream_state
->cur_packet
);
1092 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1097 /* Beginning of the new packet */
1098 if (packet_begin_notif
) {
1099 add_action_push_notif(iterator
, packet_begin_notif
);
1100 } else if (new_packet
) {
1101 ret
= add_action_push_notif_packet_begin(iterator
,
1104 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1109 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1121 int handle_notif_stream_begin(
1122 struct bt_notification_iterator
*iterator
,
1123 struct bt_notification
*notif
,
1124 struct bt_ctf_stream
*notif_stream
)
1127 struct stream_state
*stream_state
;
1129 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1130 assert(notif_stream
);
1131 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1134 BT_LOGE_STR("Cannot ensure that stream state exists.");
1148 int handle_notif_stream_end(
1149 struct bt_notification_iterator
*iterator
,
1150 struct bt_notification
*notif
,
1151 struct bt_ctf_stream
*notif_stream
)
1154 struct stream_state
*stream_state
;
1156 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1157 assert(notif_stream
);
1158 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1161 BT_LOGE_STR("Cannot ensure that stream state exists.");
1165 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1167 BT_LOGE_STR("Cannot handle packet switch.");
1171 add_action_push_notif(iterator
, notif
);
1172 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1183 int handle_notif_packet_begin(
1184 struct bt_notification_iterator
*iterator
,
1185 struct bt_notification
*notif
,
1186 struct bt_ctf_stream
*notif_stream
,
1187 struct bt_ctf_packet
*notif_packet
)
1190 struct stream_state
*stream_state
;
1192 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1193 assert(notif_packet
);
1194 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1197 BT_LOGE_STR("Cannot ensure that stream state exists.");
1201 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1203 BT_LOGE_STR("Cannot handle packet switch.");
1217 int handle_notif_packet_end(
1218 struct bt_notification_iterator
*iterator
,
1219 struct bt_notification
*notif
,
1220 struct bt_ctf_stream
*notif_stream
,
1221 struct bt_ctf_packet
*notif_packet
)
1224 struct stream_state
*stream_state
;
1226 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1227 assert(notif_packet
);
1228 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1231 BT_LOGE_STR("Cannot ensure that stream state exists.");
1235 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1237 BT_LOGE_STR("Cannot handle packet switch.");
1241 /* End of the current packet */
1242 add_action_push_notif(iterator
, notif
);
1243 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1254 int handle_notif_event(
1255 struct bt_notification_iterator
*iterator
,
1256 struct bt_notification
*notif
,
1257 struct bt_ctf_stream
*notif_stream
,
1258 struct bt_ctf_packet
*notif_packet
)
1261 struct stream_state
*stream_state
;
1263 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1264 assert(notif_packet
);
1265 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1268 BT_LOGE_STR("Cannot ensure that stream state exists.");
1272 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1274 BT_LOGE_STR("Cannot handle packet switch.");
1278 add_action_push_notif(iterator
, notif
);
1289 int enqueue_notification_and_automatic(
1290 struct bt_notification_iterator
*iterator
,
1291 struct bt_notification
*notif
)
1294 struct bt_ctf_event
*notif_event
= NULL
;
1295 struct bt_ctf_stream
*notif_stream
= NULL
;
1296 struct bt_ctf_packet
*notif_packet
= NULL
;
1300 BT_LOGV("Enqueuing user notification and automatic notifications: "
1301 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1303 // TODO: Skip most of this if the iterator is only subscribed
1304 // to event/inactivity notifications.
1306 /* Get the stream and packet referred by the notification */
1307 switch (notif
->type
) {
1308 case BT_NOTIFICATION_TYPE_EVENT
:
1309 notif_event
= bt_notification_event_borrow_event(notif
);
1310 assert(notif_event
);
1311 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1312 assert(notif_packet
);
1314 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1316 bt_notification_stream_begin_borrow_stream(notif
);
1317 assert(notif_stream
);
1319 case BT_NOTIFICATION_TYPE_STREAM_END
:
1320 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1321 assert(notif_stream
);
1323 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1325 bt_notification_packet_begin_borrow_packet(notif
);
1326 assert(notif_packet
);
1328 case BT_NOTIFICATION_TYPE_PACKET_END
:
1329 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1330 assert(notif_packet
);
1332 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1337 * Invalid type of notification. Only the notification
1338 * types above are allowed to be returned by a user
1345 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1346 assert(notif_stream
);
1349 if (!notif_stream
) {
1351 * The notification has no reference to a stream: it
1352 * cannot cause the creation of automatic notifications.
1354 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1358 if (!validate_notification(iterator
, notif
, notif_stream
,
1360 BT_LOGW_STR("Invalid notification.");
1365 switch (notif
->type
) {
1366 case BT_NOTIFICATION_TYPE_EVENT
:
1367 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1370 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1371 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1373 case BT_NOTIFICATION_TYPE_STREAM_END
:
1374 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1376 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1377 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1380 case BT_NOTIFICATION_TYPE_PACKET_END
:
1381 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1384 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1385 add_action_push_notif(iterator
, notif
);
1392 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1396 apply_actions(iterator
);
1397 BT_LOGV("Enqueued user notification and automatic notifications: "
1398 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1409 int handle_end(struct bt_notification_iterator
*iterator
)
1411 GHashTableIter stream_state_iter
;
1412 gpointer stream_gptr
, stream_state_gptr
;
1415 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
1418 * Emit a "stream end" notification for each non-ended stream
1419 * known by this iterator and mark them as ended.
1421 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1423 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1424 &stream_state_gptr
)) {
1425 struct stream_state
*stream_state
= stream_state_gptr
;
1427 assert(stream_state_gptr
);
1429 if (stream_state
->is_ended
) {
1433 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1435 BT_LOGE_STR("Cannot handle packet switch.");
1439 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1441 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
1445 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1448 apply_actions(iterator
);
1449 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
1460 enum bt_notification_iterator_status
ensure_queue_has_notifications(
1461 struct bt_notification_iterator
*iterator
)
1463 struct bt_private_notification_iterator
*priv_iterator
=
1464 bt_private_notification_iterator_from_notification_iterator(iterator
);
1465 bt_component_class_notification_iterator_next_method next_method
= NULL
;
1466 struct bt_notification_iterator_next_return next_return
= {
1467 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
1468 .notification
= NULL
,
1470 enum bt_notification_iterator_status status
=
1471 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
1475 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
1476 "iter-addr=%p, queue-size=%u",
1477 iterator
, iterator
->queue
->length
);
1479 if (iterator
->queue
->length
> 0) {
1480 /* We already have enough */
1481 BT_LOGD_STR("Queue already has at least one notification.");
1485 switch (iterator
->state
) {
1486 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
1487 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
1488 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1490 case BT_NOTIFICATION_ITERATOR_STATE_ENDED
:
1491 BT_LOGD_STR("Notification iterator is ended.");
1492 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1498 assert(iterator
->upstream_component
);
1499 assert(iterator
->upstream_component
->class);
1501 /* Pick the appropriate "next" method */
1502 switch (iterator
->upstream_component
->class->type
) {
1503 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
1505 struct bt_component_class_source
*source_class
=
1506 container_of(iterator
->upstream_component
->class,
1507 struct bt_component_class_source
, parent
);
1509 assert(source_class
->methods
.iterator
.next
);
1510 next_method
= source_class
->methods
.iterator
.next
;
1513 case BT_COMPONENT_CLASS_TYPE_FILTER
:
1515 struct bt_component_class_filter
*filter_class
=
1516 container_of(iterator
->upstream_component
->class,
1517 struct bt_component_class_filter
, parent
);
1519 assert(filter_class
->methods
.iterator
.next
);
1520 next_method
= filter_class
->methods
.iterator
.next
;
1529 * Call the user's "next" method to get the next notification
1532 assert(next_method
);
1534 while (iterator
->queue
->length
== 0) {
1535 BT_LOGD_STR("Calling user's \"next\" method.");
1536 next_return
= next_method(priv_iterator
);
1537 BT_LOGD("User method returned: status=%s",
1538 bt_notification_iterator_status_string(next_return
.status
));
1539 if (next_return
.status
< 0) {
1540 BT_LOGW_STR("User method failed.");
1541 status
= next_return
.status
;
1545 switch (next_return
.status
) {
1546 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
1547 ret
= handle_end(iterator
);
1549 BT_LOGW_STR("Cannot handle end of iteration.");
1550 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1554 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
) {
1556 BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
1558 if (iterator
->queue
->length
== 0) {
1559 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
1563 BT_NOTIFICATION_ITERATOR_STATE_ENDED
;
1565 if (iterator
->queue
->length
== 0) {
1566 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
1570 BT_LOGD("Set new status: status=%s",
1571 bt_notification_iterator_status_string(status
));
1573 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
1574 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
1576 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
1577 if (!next_return
.notification
) {
1578 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
1579 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1584 * We know the notification is valid. Before we
1585 * push it to the head of the queue, push the
1586 * appropriate automatic notifications if any.
1588 ret
= enqueue_notification_and_automatic(iterator
,
1589 next_return
.notification
);
1590 BT_PUT(next_return
.notification
);
1592 BT_LOGW("Cannot enqueue notification and automatic notifications.");
1593 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
1598 /* Unknown non-error status */
1607 enum bt_notification_iterator_status
1608 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
1610 enum bt_notification_iterator_status status
;
1613 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
1614 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
1618 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
1621 * Make sure that the iterator's queue contains at least one
1624 status
= ensure_queue_has_notifications(iterator
);
1625 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
1631 * Move the notification at the tail of the queue to the
1632 * iterator's current notification.
1634 assert(iterator
->queue
->length
> 0);
1635 bt_put(iterator
->current_notification
);
1636 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
1637 assert(iterator
->current_notification
);
1643 struct bt_component
*bt_notification_iterator_get_component(
1644 struct bt_notification_iterator
*iterator
)
1646 return bt_get(iterator
->upstream_component
);
1649 struct bt_private_component
*
1650 bt_private_notification_iterator_get_private_component(
1651 struct bt_private_notification_iterator
*private_iterator
)
1653 return bt_private_component_from_component(
1654 bt_notification_iterator_get_component(
1655 bt_notification_iterator_from_private(private_iterator
)));
1658 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
1659 struct bt_notification_iterator
*iterator
,
1660 enum bt_notification_iterator_seek_origin seek_origin
,
1663 enum bt_notification_iterator_status ret
=
1664 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;