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/fields.h>
34 #include <babeltrace/ctf-ir/field-types.h>
35 #include <babeltrace/ctf-ir/field-types-internal.h>
36 #include <babeltrace/ctf-ir/event-internal.h>
37 #include <babeltrace/ctf-ir/packet-internal.h>
38 #include <babeltrace/ctf-ir/stream-internal.h>
39 #include <babeltrace/graph/connection.h>
40 #include <babeltrace/graph/connection-internal.h>
41 #include <babeltrace/graph/component.h>
42 #include <babeltrace/graph/component-source-internal.h>
43 #include <babeltrace/graph/component-class-internal.h>
44 #include <babeltrace/graph/notification.h>
45 #include <babeltrace/graph/notification-iterator.h>
46 #include <babeltrace/graph/notification-iterator-internal.h>
47 #include <babeltrace/graph/notification-internal.h>
48 #include <babeltrace/graph/notification-event.h>
49 #include <babeltrace/graph/notification-event-internal.h>
50 #include <babeltrace/graph/notification-packet.h>
51 #include <babeltrace/graph/notification-packet-internal.h>
52 #include <babeltrace/graph/notification-stream.h>
53 #include <babeltrace/graph/notification-stream-internal.h>
54 #include <babeltrace/graph/notification-discarded-elements-internal.h>
55 #include <babeltrace/graph/port.h>
56 #include <babeltrace/types.h>
61 struct discarded_elements_state
{
62 struct bt_ctf_clock_value
*cur_begin
;
67 struct bt_ctf_stream
*stream
; /* owned by this */
68 struct bt_ctf_packet
*cur_packet
; /* owned by this */
69 struct discarded_elements_state discarded_packets_state
;
70 struct discarded_elements_state discarded_events_state
;
75 ACTION_TYPE_PUSH_NOTIF
,
76 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
77 ACTION_TYPE_ADD_STREAM_STATE
,
78 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
79 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
80 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
81 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
85 enum action_type type
;
87 /* ACTION_TYPE_PUSH_NOTIF */
89 struct bt_notification
*notif
; /* owned by this */
92 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
94 struct bt_ctf_stream
*stream
; /* owned by this */
95 struct bt_component
*component
; /* owned by this */
96 struct bt_port
*port
; /* owned by this */
97 } map_port_to_comp_in_stream
;
99 /* ACTION_TYPE_ADD_STREAM_STATE */
101 struct bt_ctf_stream
*stream
; /* owned by this */
102 struct stream_state
*stream_state
; /* owned by this */
105 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
107 struct stream_state
*stream_state
; /* weak */
108 } set_stream_state_is_ended
;
110 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
112 struct stream_state
*stream_state
; /* weak */
113 struct bt_ctf_packet
*packet
; /* owned by this */
114 } set_stream_state_cur_packet
;
116 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */
117 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */
119 struct stream_state
*stream_state
; /* weak */
120 struct bt_ctf_clock_value
*cur_begin
; /* owned by this */
122 } update_stream_state_discarded_elements
;
127 void stream_destroy_listener(struct bt_ctf_stream
*stream
, void *data
)
129 struct bt_notification_iterator
*iterator
= data
;
131 /* Remove associated stream state */
132 g_hash_table_remove(iterator
->stream_states
, stream
);
136 void destroy_stream_state(struct stream_state
*stream_state
)
142 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state
);
143 BT_LOGV_STR("Putting stream state's current packet.");
144 bt_put(stream_state
->cur_packet
);
145 BT_LOGV_STR("Putting stream state's stream.");
146 bt_put(stream_state
->stream
);
147 bt_put(stream_state
->discarded_packets_state
.cur_begin
);
148 bt_put(stream_state
->discarded_events_state
.cur_begin
);
149 g_free(stream_state
);
153 void destroy_action(struct action
*action
)
157 switch (action
->type
) {
158 case ACTION_TYPE_PUSH_NOTIF
:
159 BT_PUT(action
->payload
.push_notif
.notif
);
161 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
162 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.stream
);
163 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.component
);
164 BT_PUT(action
->payload
.map_port_to_comp_in_stream
.port
);
166 case ACTION_TYPE_ADD_STREAM_STATE
:
167 BT_PUT(action
->payload
.add_stream_state
.stream
);
168 destroy_stream_state(
169 action
->payload
.add_stream_state
.stream_state
);
170 action
->payload
.add_stream_state
.stream_state
= NULL
;
172 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
173 BT_PUT(action
->payload
.set_stream_state_cur_packet
.packet
);
175 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
177 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
178 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
179 BT_PUT(action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
182 BT_LOGF("Unexpected action's type: type=%d", action
->type
);
188 void add_action(struct bt_notification_iterator
*iterator
,
189 struct action
*action
)
191 g_array_append_val(iterator
->actions
, *action
);
195 void clear_actions(struct bt_notification_iterator
*iterator
)
199 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
200 struct action
*action
= &g_array_index(iterator
->actions
,
203 destroy_action(action
);
206 g_array_set_size(iterator
->actions
, 0);
210 const char *action_type_string(enum action_type type
)
213 case ACTION_TYPE_PUSH_NOTIF
:
214 return "ACTION_TYPE_PUSH_NOTIF";
215 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
216 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
217 case ACTION_TYPE_ADD_STREAM_STATE
:
218 return "ACTION_TYPE_ADD_STREAM_STATE";
219 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
220 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
221 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
222 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
223 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
224 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS";
225 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
226 return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS";
233 void apply_actions(struct bt_notification_iterator
*iterator
)
237 BT_LOGV("Applying notification's iterator current actions: "
238 "count=%u", iterator
->actions
->len
);
240 for (i
= 0; i
< iterator
->actions
->len
; i
++) {
241 struct action
*action
= &g_array_index(iterator
->actions
,
244 BT_LOGV("Applying action: index=%zu, type=%s",
245 i
, action_type_string(action
->type
));
247 switch (action
->type
) {
248 case ACTION_TYPE_PUSH_NOTIF
:
249 /* Move notification to queue */
250 g_queue_push_head(iterator
->queue
,
251 action
->payload
.push_notif
.notif
);
252 bt_notification_freeze(
253 action
->payload
.push_notif
.notif
);
254 action
->payload
.push_notif
.notif
= NULL
;
256 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
:
257 bt_ctf_stream_map_component_to_port(
258 action
->payload
.map_port_to_comp_in_stream
.stream
,
259 action
->payload
.map_port_to_comp_in_stream
.component
,
260 action
->payload
.map_port_to_comp_in_stream
.port
);
262 case ACTION_TYPE_ADD_STREAM_STATE
:
263 /* Move stream state to hash table */
264 g_hash_table_insert(iterator
->stream_states
,
265 action
->payload
.add_stream_state
.stream
,
266 action
->payload
.add_stream_state
.stream_state
);
268 action
->payload
.add_stream_state
.stream_state
= NULL
;
270 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
:
272 * We know that this stream is ended. We need to
273 * remember this as long as the stream exists to
274 * enforce that the same stream does not end
277 * Here we add a destroy listener to the stream
278 * which we put after (becomes weak as the hash
279 * table key). If we were the last object to own
280 * this stream, the destroy listener is called
281 * when we call bt_put() which removes this
282 * stream state completely. This is important
283 * because the memory used by this stream object
284 * could be reused for another stream, and they
285 * must have different states.
287 bt_ctf_stream_add_destroy_listener(
288 action
->payload
.set_stream_state_is_ended
.stream_state
->stream
,
289 stream_destroy_listener
, iterator
);
290 action
->payload
.set_stream_state_is_ended
.stream_state
->is_ended
= BT_TRUE
;
291 BT_PUT(action
->payload
.set_stream_state_is_ended
.stream_state
->stream
);
293 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
:
294 /* Move packet to stream state's current packet */
295 BT_MOVE(action
->payload
.set_stream_state_cur_packet
.stream_state
->cur_packet
,
296 action
->payload
.set_stream_state_cur_packet
.packet
);
298 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
:
299 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
:
301 struct discarded_elements_state
*state
;
303 if (action
->type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
304 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_packets_state
;
306 state
= &action
->payload
.update_stream_state_discarded_elements
.stream_state
->discarded_events_state
;
309 BT_MOVE(state
->cur_begin
,
310 action
->payload
.update_stream_state_discarded_elements
.cur_begin
);
311 state
->cur_count
= action
->payload
.update_stream_state_discarded_elements
.cur_count
;
315 BT_LOGF("Unexpected action's type: type=%d",
321 clear_actions(iterator
);
325 struct stream_state
*create_stream_state(struct bt_ctf_stream
*stream
)
327 struct stream_state
*stream_state
= g_new0(struct stream_state
, 1);
330 BT_LOGE_STR("Failed to allocate one stream state.");
335 * The packet index is a monotonic counter which may not start
336 * at 0 at the beginning of the stream. We therefore need to
337 * have an internal object initial state of -1ULL to distinguish
338 * between initial state and having seen a packet with
341 stream_state
->discarded_packets_state
.cur_count
= -1ULL;
344 * We keep a reference to the stream until we know it's ended
345 * because we need to be able to create an automatic "stream
346 * end" notification when the user's "next" method returns
347 * BT_NOTIFICATION_ITERATOR_STATUS_END.
349 * We put this reference when the stream is marked as ended.
351 stream_state
->stream
= bt_get(stream
);
352 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
353 "stream-state-addr=%p",
354 stream
, bt_ctf_stream_get_name(stream
), stream_state
);
361 void bt_notification_iterator_destroy(struct bt_object
*obj
)
363 struct bt_notification_iterator
*iterator
;
368 * The notification iterator's reference count is 0 if we're
369 * here. Increment it to avoid a double-destroy (possibly
370 * infinitely recursive). This could happen for example if the
371 * notification iterator's finalization function does bt_get()
372 * (or anything that causes bt_get() to be called) on itself
373 * (ref. count goes from 0 to 1), and then bt_put(): the
374 * reference count would go from 1 to 0 again and this function
375 * would be called again.
377 obj
->ref_count
.count
++;
378 iterator
= container_of(obj
, struct bt_notification_iterator
, base
);
379 BT_LOGD("Destroying notification iterator object: addr=%p",
381 bt_notification_iterator_finalize(iterator
);
383 if (iterator
->queue
) {
384 struct bt_notification
*notif
;
386 BT_LOGD("Putting notifications in queue.");
388 while ((notif
= g_queue_pop_tail(iterator
->queue
))) {
392 g_queue_free(iterator
->queue
);
395 if (iterator
->stream_states
) {
397 * Remove our destroy listener from each stream which
398 * has a state in this iterator. Otherwise the destroy
399 * listener would be called with an invalid/other
400 * notification iterator object.
402 GHashTableIter ht_iter
;
403 gpointer stream_gptr
, stream_state_gptr
;
405 g_hash_table_iter_init(&ht_iter
, iterator
->stream_states
);
407 while (g_hash_table_iter_next(&ht_iter
, &stream_gptr
, &stream_state_gptr
)) {
410 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
411 bt_ctf_stream_remove_destroy_listener(
412 (void *) stream_gptr
, stream_destroy_listener
,
416 g_hash_table_destroy(iterator
->stream_states
);
419 if (iterator
->actions
) {
420 g_array_free(iterator
->actions
, TRUE
);
423 if (iterator
->connection
) {
425 * Remove ourself from the originating connection so
426 * that it does not try to finalize a dangling pointer
429 bt_connection_remove_iterator(iterator
->connection
, iterator
);
432 BT_LOGD_STR("Putting current notification.");
433 bt_put(iterator
->current_notification
);
438 void bt_notification_iterator_finalize(
439 struct bt_notification_iterator
*iterator
)
441 struct bt_component_class
*comp_class
= NULL
;
442 bt_component_class_notification_iterator_finalize_method
443 finalize_method
= NULL
;
447 switch (iterator
->state
) {
448 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
449 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
450 /* Already finalized */
451 BT_LOGD("Not finalizing notification iterator: already finalized: "
452 "addr=%p", iterator
);
458 BT_LOGD("Finalizing notification iterator: addr=%p", iterator
);
460 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_ENDED
) {
461 BT_LOGD("Updating notification iterator's state: "
462 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
463 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
;
465 BT_LOGD("Updating notification iterator's state: "
466 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
467 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
;
470 assert(iterator
->upstream_component
);
471 comp_class
= iterator
->upstream_component
->class;
473 /* Call user-defined destroy method */
474 switch (comp_class
->type
) {
475 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
477 struct bt_component_class_source
*source_class
;
479 source_class
= container_of(comp_class
, struct bt_component_class_source
, parent
);
480 finalize_method
= source_class
->methods
.iterator
.finalize
;
483 case BT_COMPONENT_CLASS_TYPE_FILTER
:
485 struct bt_component_class_filter
*filter_class
;
487 filter_class
= container_of(comp_class
, struct bt_component_class_filter
, parent
);
488 finalize_method
= filter_class
->methods
.iterator
.finalize
;
496 if (finalize_method
) {
497 BT_LOGD("Calling user's finalization method: addr=%p",
500 bt_private_notification_iterator_from_notification_iterator(iterator
));
503 iterator
->upstream_component
= NULL
;
504 iterator
->upstream_port
= NULL
;
505 BT_LOGD("Finalized notification iterator: addr=%p", iterator
);
509 void bt_notification_iterator_set_connection(
510 struct bt_notification_iterator
*iterator
,
511 struct bt_connection
*connection
)
514 iterator
->connection
= connection
;
515 BT_LOGV("Set notification iterator's connection: "
516 "iter-addr=%p, conn-addr=%p", iterator
, connection
);
520 int create_subscription_mask_from_notification_types(
521 struct bt_notification_iterator
*iterator
,
522 const enum bt_notification_type
*notif_types
)
524 const enum bt_notification_type
*notif_type
;
528 iterator
->subscription_mask
= 0;
530 for (notif_type
= notif_types
;
531 *notif_type
!= BT_NOTIFICATION_TYPE_SENTINEL
;
533 switch (*notif_type
) {
534 case BT_NOTIFICATION_TYPE_ALL
:
535 iterator
->subscription_mask
|=
536 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
|
537 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
|
538 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
|
539 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
|
540 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
|
541 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
|
542 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
|
543 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
545 case BT_NOTIFICATION_TYPE_EVENT
:
546 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
548 case BT_NOTIFICATION_TYPE_INACTIVITY
:
549 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
551 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
552 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
554 case BT_NOTIFICATION_TYPE_STREAM_END
:
555 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
557 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
558 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
560 case BT_NOTIFICATION_TYPE_PACKET_END
:
561 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
563 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
564 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
566 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
567 iterator
->subscription_mask
|= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
574 BT_LOGV("Added notification type to subscription mask: "
576 bt_notification_type_string(*notif_type
),
577 iterator
->subscription_mask
);
585 enum bt_connection_status
bt_notification_iterator_create(
586 struct bt_component
*upstream_comp
,
587 struct bt_port
*upstream_port
,
588 const enum bt_notification_type
*notification_types
,
589 struct bt_connection
*connection
,
590 struct bt_notification_iterator
**user_iterator
)
592 enum bt_connection_status status
= BT_CONNECTION_STATUS_OK
;
593 enum bt_component_class_type type
;
594 struct bt_notification_iterator
*iterator
= NULL
;
596 assert(upstream_comp
);
597 assert(upstream_port
);
598 assert(notification_types
);
599 assert(bt_port_is_connected(upstream_port
));
600 assert(user_iterator
);
601 BT_LOGD("Creating notification iterator: "
602 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
603 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
605 upstream_comp
, bt_component_get_name(upstream_comp
),
606 upstream_port
, bt_port_get_name(upstream_port
),
608 type
= bt_component_get_class_type(upstream_comp
);
609 assert(type
== BT_COMPONENT_CLASS_TYPE_SOURCE
||
610 type
== BT_COMPONENT_CLASS_TYPE_FILTER
);
611 iterator
= g_new0(struct bt_notification_iterator
, 1);
613 BT_LOGE_STR("Failed to allocate one notification iterator.");
614 status
= BT_CONNECTION_STATUS_NOMEM
;
618 bt_object_init(iterator
, bt_notification_iterator_destroy
);
620 if (create_subscription_mask_from_notification_types(iterator
,
621 notification_types
)) {
622 BT_LOGW_STR("Cannot create subscription mask from notification types.");
623 status
= BT_CONNECTION_STATUS_INVALID
;
627 iterator
->stream_states
= g_hash_table_new_full(g_direct_hash
,
628 g_direct_equal
, NULL
, (GDestroyNotify
) destroy_stream_state
);
629 if (!iterator
->stream_states
) {
630 BT_LOGE_STR("Failed to allocate a GHashTable.");
631 status
= BT_CONNECTION_STATUS_NOMEM
;
635 iterator
->queue
= g_queue_new();
636 if (!iterator
->queue
) {
637 BT_LOGE_STR("Failed to allocate a GQueue.");
638 status
= BT_CONNECTION_STATUS_NOMEM
;
642 iterator
->actions
= g_array_new(FALSE
, FALSE
, sizeof(struct action
));
643 if (!iterator
->actions
) {
644 BT_LOGE_STR("Failed to allocate a GArray.");
645 status
= BT_CONNECTION_STATUS_NOMEM
;
649 iterator
->upstream_component
= upstream_comp
;
650 iterator
->upstream_port
= upstream_port
;
651 iterator
->connection
= connection
;
652 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
;
653 BT_LOGD("Created notification iterator: "
654 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
655 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
656 "conn-addr=%p, iter-addr=%p",
657 upstream_comp
, bt_component_get_name(upstream_comp
),
658 upstream_port
, bt_port_get_name(upstream_port
),
659 connection
, iterator
);
661 /* Move reference to user */
662 *user_iterator
= iterator
;
670 void *bt_private_notification_iterator_get_user_data(
671 struct bt_private_notification_iterator
*private_iterator
)
673 struct bt_notification_iterator
*iterator
=
674 bt_notification_iterator_from_private(private_iterator
);
676 return iterator
? iterator
->user_data
: NULL
;
679 enum bt_notification_iterator_status
680 bt_private_notification_iterator_set_user_data(
681 struct bt_private_notification_iterator
*private_iterator
,
684 enum bt_notification_iterator_status ret
=
685 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
686 struct bt_notification_iterator
*iterator
=
687 bt_notification_iterator_from_private(private_iterator
);
690 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
691 ret
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
695 iterator
->user_data
= data
;
696 BT_LOGV("Set notification iterator's user data: "
697 "iter-addr=%p, user-data-addr=%p", iterator
, data
);
703 struct bt_notification
*bt_notification_iterator_get_notification(
704 struct bt_notification_iterator
*iterator
)
706 struct bt_notification
*notification
= NULL
;
709 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
713 notification
= bt_get(iterator
->current_notification
);
720 enum bt_notification_iterator_notif_type
721 bt_notification_iterator_notif_type_from_notif_type(
722 enum bt_notification_type notif_type
)
724 enum bt_notification_iterator_notif_type iter_notif_type
;
726 switch (notif_type
) {
727 case BT_NOTIFICATION_TYPE_EVENT
:
728 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT
;
730 case BT_NOTIFICATION_TYPE_INACTIVITY
:
731 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY
;
733 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
734 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN
;
736 case BT_NOTIFICATION_TYPE_STREAM_END
:
737 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END
;
739 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
740 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN
;
742 case BT_NOTIFICATION_TYPE_PACKET_END
:
743 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END
;
745 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
746 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS
;
748 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
749 iter_notif_type
= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS
;
755 return iter_notif_type
;
759 bt_bool
validate_notification(struct bt_notification_iterator
*iterator
,
760 struct bt_notification
*notif
,
761 struct bt_ctf_stream
*notif_stream
,
762 struct bt_ctf_packet
*notif_packet
)
764 bt_bool is_valid
= BT_TRUE
;
765 struct stream_state
*stream_state
;
766 struct bt_port
*stream_comp_cur_port
;
768 assert(notif_stream
);
769 stream_comp_cur_port
=
770 bt_ctf_stream_port_for_component(notif_stream
,
771 iterator
->upstream_component
);
772 if (!stream_comp_cur_port
) {
774 * This is the first time this notification iterator
775 * bumps into this stream. Add an action to map the
776 * iterator's upstream component to the iterator's
777 * upstream port in this stream.
779 struct action action
= {
780 .type
= ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM
,
781 .payload
.map_port_to_comp_in_stream
= {
782 .stream
= bt_get(notif_stream
),
783 .component
= bt_get(iterator
->upstream_component
),
784 .port
= bt_get(iterator
->upstream_port
),
788 add_action(iterator
, &action
);
790 if (stream_comp_cur_port
!= iterator
->upstream_port
) {
792 * It looks like two different ports of the same
793 * component are emitting notifications which
794 * have references to the same stream. This is
795 * bad: the API guarantees that it can never
798 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
799 "stream-addr=%p, stream-name=\"%s\", "
800 "stream-comp-cur-port-addr=%p, "
801 "stream-comp-cur-port-name=%p, "
802 "iter-upstream-port-addr=%p, "
803 "iter-upstream-port-name=%s",
805 bt_ctf_stream_get_name(notif_stream
),
806 stream_comp_cur_port
,
807 bt_port_get_name(stream_comp_cur_port
),
808 iterator
->upstream_port
,
809 bt_port_get_name(iterator
->upstream_port
));
816 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
819 BT_LOGV("Stream state already exists: "
820 "stream-addr=%p, stream-name=\"%s\", "
821 "stream-state-addr=%p",
823 bt_ctf_stream_get_name(notif_stream
), stream_state
);
825 if (stream_state
->is_ended
) {
827 * There's a new notification which has a
828 * reference to a stream which, from this
829 * iterator's point of view, is ended ("end of
830 * stream" notification was returned). This is
831 * bad: the API guarantees that it can never
834 BT_LOGW("Stream is already ended: "
835 "stream-addr=%p, stream-name=\"%s\"",
837 bt_ctf_stream_get_name(notif_stream
));
842 switch (notif
->type
) {
843 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
845 * We already have a stream state, which means
846 * we already returned a "stream begin"
847 * notification: this is an invalid duplicate.
849 BT_LOGW("Duplicate stream beginning notification: "
850 "stream-addr=%p, stream-name=\"%s\"",
852 bt_ctf_stream_get_name(notif_stream
));
855 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
856 if (notif_packet
== stream_state
->cur_packet
) {
857 /* Duplicate "packet begin" notification */
858 BT_LOGW("Duplicate stream beginning notification: "
859 "stream-addr=%p, stream-name=\"%s\", "
862 bt_ctf_stream_get_name(notif_stream
),
878 bt_bool
is_subscribed_to_notification_type(struct bt_notification_iterator
*iterator
,
879 enum bt_notification_type notif_type
)
881 uint32_t iter_notif_type
=
882 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
885 return (iter_notif_type
& iterator
->subscription_mask
) ? BT_TRUE
: BT_FALSE
;
889 void add_action_push_notif(struct bt_notification_iterator
*iterator
,
890 struct bt_notification
*notif
)
892 struct action action
= {
893 .type
= ACTION_TYPE_PUSH_NOTIF
,
898 if (!is_subscribed_to_notification_type(iterator
, notif
->type
)) {
902 action
.payload
.push_notif
.notif
= bt_get(notif
);
903 add_action(iterator
, &action
);
904 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif
);
908 int add_action_push_notif_stream_begin(
909 struct bt_notification_iterator
*iterator
,
910 struct bt_ctf_stream
*stream
)
913 struct bt_notification
*stream_begin_notif
= NULL
;
915 if (!is_subscribed_to_notification_type(iterator
,
916 BT_NOTIFICATION_TYPE_STREAM_BEGIN
)) {
917 BT_LOGV("Not adding \"push stream beginning notification\" action: "
918 "notification iterator is not subscribed: addr=%p",
924 stream_begin_notif
= bt_notification_stream_begin_create(stream
);
925 if (!stream_begin_notif
) {
926 BT_LOGE_STR("Cannot create stream beginning notification.");
930 add_action_push_notif(iterator
, stream_begin_notif
);
931 BT_LOGV("Added \"push stream beginning notification\" action: "
932 "stream-addr=%p, stream-name=\"%s\"",
933 stream
, bt_ctf_stream_get_name(stream
));
940 bt_put(stream_begin_notif
);
945 int add_action_push_notif_stream_end(
946 struct bt_notification_iterator
*iterator
,
947 struct bt_ctf_stream
*stream
)
950 struct bt_notification
*stream_end_notif
= NULL
;
952 if (!is_subscribed_to_notification_type(iterator
,
953 BT_NOTIFICATION_TYPE_STREAM_END
)) {
954 BT_LOGV("Not adding \"push stream end notification\" action: "
955 "notification iterator is not subscribed: addr=%p",
961 stream_end_notif
= bt_notification_stream_end_create(stream
);
962 if (!stream_end_notif
) {
963 BT_LOGE_STR("Cannot create stream end notification.");
967 add_action_push_notif(iterator
, stream_end_notif
);
968 BT_LOGV("Added \"push stream end notification\" action: "
969 "stream-addr=%p, stream-name=\"%s\"",
970 stream
, bt_ctf_stream_get_name(stream
));
977 bt_put(stream_end_notif
);
982 int add_action_push_notif_packet_begin(
983 struct bt_notification_iterator
*iterator
,
984 struct bt_ctf_packet
*packet
)
987 struct bt_notification
*packet_begin_notif
= NULL
;
989 if (!is_subscribed_to_notification_type(iterator
,
990 BT_NOTIFICATION_TYPE_PACKET_BEGIN
)) {
991 BT_LOGV("Not adding \"push packet beginning notification\" action: "
992 "notification iterator is not subscribed: addr=%p",
998 packet_begin_notif
= bt_notification_packet_begin_create(packet
);
999 if (!packet_begin_notif
) {
1000 BT_LOGE_STR("Cannot create packet beginning notification.");
1004 add_action_push_notif(iterator
, packet_begin_notif
);
1005 BT_LOGV("Added \"push packet beginning notification\" action: "
1006 "packet-addr=%p", packet
);
1013 bt_put(packet_begin_notif
);
1018 int add_action_push_notif_packet_end(
1019 struct bt_notification_iterator
*iterator
,
1020 struct bt_ctf_packet
*packet
)
1023 struct bt_notification
*packet_end_notif
= NULL
;
1025 if (!is_subscribed_to_notification_type(iterator
,
1026 BT_NOTIFICATION_TYPE_PACKET_END
)) {
1027 BT_LOGV("Not adding \"push packet end notification\" action: "
1028 "notification iterator is not subscribed: addr=%p",
1034 packet_end_notif
= bt_notification_packet_end_create(packet
);
1035 if (!packet_end_notif
) {
1036 BT_LOGE_STR("Cannot create packet end notification.");
1040 add_action_push_notif(iterator
, packet_end_notif
);
1041 BT_LOGV("Added \"push packet end notification\" action: "
1042 "packet-addr=%p", packet
);
1049 bt_put(packet_end_notif
);
1054 void add_action_set_stream_state_is_ended(
1055 struct bt_notification_iterator
*iterator
,
1056 struct stream_state
*stream_state
)
1058 struct action action
= {
1059 .type
= ACTION_TYPE_SET_STREAM_STATE_IS_ENDED
,
1060 .payload
.set_stream_state_is_ended
= {
1061 .stream_state
= stream_state
,
1065 assert(stream_state
);
1066 add_action(iterator
, &action
);
1067 BT_LOGV("Added \"set stream state's ended\" action: "
1068 "stream-state-addr=%p", stream_state
);
1072 void add_action_set_stream_state_cur_packet(
1073 struct bt_notification_iterator
*iterator
,
1074 struct stream_state
*stream_state
,
1075 struct bt_ctf_packet
*packet
)
1077 struct action action
= {
1078 .type
= ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET
,
1079 .payload
.set_stream_state_cur_packet
= {
1080 .stream_state
= stream_state
,
1081 .packet
= bt_get(packet
),
1085 assert(stream_state
);
1086 add_action(iterator
, &action
);
1087 BT_LOGV("Added \"set stream state's current packet\" action: "
1088 "stream-state-addr=%p, packet-addr=%p",
1089 stream_state
, packet
);
1093 void add_action_update_stream_state_discarded_elements(
1094 struct bt_notification_iterator
*iterator
,
1095 enum action_type type
,
1096 struct stream_state
*stream_state
,
1097 struct bt_ctf_clock_value
*cur_begin
,
1100 struct action action
= {
1102 .payload
.update_stream_state_discarded_elements
= {
1103 .stream_state
= stream_state
,
1104 .cur_begin
= bt_get(cur_begin
),
1105 .cur_count
= cur_count
,
1109 assert(stream_state
);
1110 assert(type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
||
1111 type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
);
1112 add_action(iterator
, &action
);
1113 if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
) {
1114 BT_LOGV("Added \"update stream state's discarded packets\" action: "
1115 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1116 stream_state
, cur_begin
, cur_count
);
1117 } else if (type
== ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
) {
1118 BT_LOGV("Added \"update stream state's discarded events\" action: "
1119 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64
,
1120 stream_state
, cur_begin
, cur_count
);
1125 int ensure_stream_state_exists(struct bt_notification_iterator
*iterator
,
1126 struct bt_notification
*stream_begin_notif
,
1127 struct bt_ctf_stream
*notif_stream
,
1128 struct stream_state
**_stream_state
)
1131 struct stream_state
*stream_state
= NULL
;
1133 if (!notif_stream
) {
1135 * The notification does not reference any stream: no
1136 * need to get or create a stream state.
1141 stream_state
= g_hash_table_lookup(iterator
->stream_states
,
1143 if (!stream_state
) {
1145 * This iterator did not bump into this stream yet:
1146 * create a stream state and a "stream begin"
1149 struct action action
= {
1150 .type
= ACTION_TYPE_ADD_STREAM_STATE
,
1151 .payload
.add_stream_state
= {
1152 .stream
= bt_get(notif_stream
),
1153 .stream_state
= NULL
,
1157 stream_state
= create_stream_state(notif_stream
);
1158 if (!stream_state
) {
1159 BT_LOGE_STR("Cannot create stream state.");
1163 action
.payload
.add_stream_state
.stream_state
= stream_state
;
1164 add_action(iterator
, &action
);
1166 if (stream_begin_notif
) {
1167 add_action_push_notif(iterator
, stream_begin_notif
);
1169 ret
= add_action_push_notif_stream_begin(iterator
,
1172 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
1180 destroy_stream_state(stream_state
);
1181 stream_state
= NULL
;
1185 *_stream_state
= stream_state
;
1190 struct bt_ctf_field
*get_struct_field_uint(struct bt_ctf_field
*struct_field
,
1191 const char *field_name
)
1193 struct bt_ctf_field
*field
= NULL
;
1194 struct bt_ctf_field_type
*ft
= NULL
;
1196 field
= bt_ctf_field_structure_get_field_by_name(struct_field
,
1199 BT_LOGV_STR("`%s` field does not exist.");
1203 if (!bt_ctf_field_is_integer(field
)) {
1204 BT_LOGV("Skipping `%s` field because its type is not an integer field type: "
1205 "field-addr=%p, ft-addr=%p, ft-id=%s", field_name
,
1206 field
, ft
, bt_ctf_field_type_id_string(
1207 bt_ctf_field_type_get_type_id(ft
)));
1212 ft
= bt_ctf_field_get_type(field
);
1215 if (bt_ctf_field_type_integer_is_signed(ft
)) {
1216 BT_LOGV("Skipping `%s` integer field because its type is signed: "
1217 "field-addr=%p, ft-addr=%p", field_name
, field
, ft
);
1228 uint64_t get_packet_context_events_discarded(struct bt_ctf_packet
*packet
)
1230 struct bt_ctf_field
*packet_context
= NULL
;
1231 struct bt_ctf_field
*field
= NULL
;
1232 uint64_t retval
= -1ULL;
1235 packet_context
= bt_ctf_packet_get_context(packet
);
1236 if (!packet_context
) {
1240 field
= get_struct_field_uint(packet_context
, "events_discarded");
1242 BT_LOGV("`events_discarded` field does not exist in packet's context field: "
1243 "packet-addr=%p, packet-context-field-addr=%p",
1244 packet
, packet_context
);
1248 assert(bt_ctf_field_is_integer(field
));
1249 ret
= bt_ctf_field_unsigned_integer_get_value(field
, &retval
);
1251 BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
1252 "packet-addr=%p, field-addr=%p",
1259 bt_put(packet_context
);
1265 uint64_t get_packet_context_packet_seq_num(struct bt_ctf_packet
*packet
)
1267 struct bt_ctf_field
*packet_context
= NULL
;
1268 struct bt_ctf_field
*field
= NULL
;
1269 uint64_t retval
= -1ULL;
1272 packet_context
= bt_ctf_packet_get_context(packet
);
1273 if (!packet_context
) {
1277 field
= get_struct_field_uint(packet_context
, "packet_seq_num");
1279 BT_LOGV("`packet_seq_num` field does not exist in packet's context field: "
1280 "packet-addr=%p, packet-context-field-addr=%p",
1281 packet
, packet_context
);
1285 assert(bt_ctf_field_is_integer(field
));
1286 ret
= bt_ctf_field_unsigned_integer_get_value(field
, &retval
);
1288 BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
1289 "packet-addr=%p, field-addr=%p",
1296 bt_put(packet_context
);
1302 int handle_discarded_packets(struct bt_notification_iterator
*iterator
,
1303 struct bt_ctf_packet
*packet
,
1304 struct bt_ctf_clock_value
*ts_begin
,
1305 struct bt_ctf_clock_value
*ts_end
,
1306 struct stream_state
*stream_state
)
1308 struct bt_notification
*notif
= NULL
;
1310 uint64_t prev_count
, next_count
;
1313 next_count
= get_packet_context_packet_seq_num(packet
);
1314 if (next_count
== -1ULL) {
1316 * Stream does not have seqnum field, skip discarded
1321 prev_count
= stream_state
->discarded_packets_state
.cur_count
;
1323 if (prev_count
!= -1ULL) {
1324 if (next_count
< prev_count
) {
1325 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is lesser than the previous value for the same stream: "
1326 "not updating the stream state's current value: "
1327 "packet-addr=%p, prev-count=%" PRIu64
", "
1328 "cur-count=%" PRIu64
,
1329 packet
, prev_count
, next_count
);
1332 if (next_count
== prev_count
) {
1333 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is equal to the previous value for the same stream: "
1334 "not updating the stream state's current value: "
1335 "packet-addr=%p, prev-count=%" PRIu64
", "
1336 "cur-count=%" PRIu64
,
1337 packet
, prev_count
, next_count
);
1341 diff
= next_count
- prev_count
;
1344 * Add a discarded packets notification. The packets
1345 * are considered to be lost between the state's last time
1346 * and the current packet's beginning time.
1347 * The counter is expected to monotonically increase of
1348 * 1 for each packet. Therefore, the number of missing
1349 * packets is 'diff - 1'.
1351 notif
= bt_notification_discarded_elements_create(
1352 BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
,
1353 stream_state
->stream
,
1354 stream_state
->discarded_packets_state
.cur_begin
,
1355 ts_begin
, diff
- 1);
1357 BT_LOGE_STR("Cannot create discarded packets notification.");
1362 add_action_push_notif(iterator
, notif
);
1366 add_action_update_stream_state_discarded_elements(iterator
,
1367 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS
,
1368 stream_state
, ts_end
, next_count
);
1376 int handle_discarded_events(struct bt_notification_iterator
*iterator
,
1377 struct bt_ctf_packet
*packet
,
1378 struct bt_ctf_clock_value
*ts_begin
,
1379 struct bt_ctf_clock_value
*ts_end
,
1380 struct stream_state
*stream_state
)
1382 struct bt_notification
*notif
= NULL
;
1384 uint64_t next_count
;
1387 next_count
= get_packet_context_events_discarded(packet
);
1388 if (next_count
== -1ULL) {
1389 next_count
= stream_state
->discarded_events_state
.cur_count
;
1393 if (next_count
< stream_state
->discarded_events_state
.cur_count
) {
1394 BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: "
1395 "not updating the stream state's current value: "
1396 "packet-addr=%p, prev-count=%" PRIu64
", "
1397 "cur-count=%" PRIu64
,
1398 packet
, stream_state
->discarded_events_state
.cur_count
,
1403 diff
= next_count
- stream_state
->discarded_events_state
.cur_count
;
1406 * Add a discarded events notification. The events are
1407 * considered to be lost betweem the state's last time
1408 * and the current packet's end time.
1410 notif
= bt_notification_discarded_elements_create(
1411 BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
,
1412 stream_state
->stream
,
1413 stream_state
->discarded_events_state
.cur_begin
,
1416 BT_LOGE_STR("Cannot create discarded events notification.");
1421 add_action_push_notif(iterator
, notif
);
1425 add_action_update_stream_state_discarded_elements(iterator
,
1426 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS
,
1427 stream_state
, ts_end
, next_count
);
1435 int get_field_clock_value(struct bt_ctf_field
*root_field
,
1436 const char *field_name
,
1437 struct bt_ctf_clock_value
**user_clock_val
)
1439 struct bt_ctf_field
*field
;
1440 struct bt_ctf_field_type
*ft
= NULL
;
1441 struct bt_ctf_clock_class
*clock_class
= NULL
;
1442 struct bt_ctf_clock_value
*clock_value
= NULL
;
1446 field
= get_struct_field_uint(root_field
, field_name
);
1448 /* Not an error: skip this */
1452 ft
= bt_ctf_field_get_type(field
);
1454 clock_class
= bt_ctf_field_type_integer_get_mapped_clock_class(ft
);
1456 BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
1462 ret
= bt_ctf_field_unsigned_integer_get_value(field
, &val
);
1464 BT_LOGW("Cannot get integer field's raw value: "
1465 "field-addr=%p", field
);
1470 clock_value
= bt_ctf_clock_value_create(clock_class
, val
);
1472 BT_LOGE_STR("Cannot create clock value from clock class.");
1477 /* Move clock value to user */
1478 *user_clock_val
= clock_value
;
1484 bt_put(clock_class
);
1485 bt_put(clock_value
);
1490 int get_ts_begin_ts_end_from_packet(struct bt_ctf_packet
*packet
,
1491 struct bt_ctf_clock_value
**user_ts_begin
,
1492 struct bt_ctf_clock_value
**user_ts_end
)
1494 struct bt_ctf_field
*packet_context
= NULL
;
1495 struct bt_ctf_clock_value
*ts_begin
= NULL
;
1496 struct bt_ctf_clock_value
*ts_end
= NULL
;
1499 packet_context
= bt_ctf_packet_get_context(packet
);
1500 if (!packet_context
) {
1504 ret
= get_field_clock_value(packet_context
, "timestamp_begin",
1507 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1508 "packet-addr=%p, packet-context-field-addr=%p",
1509 packet
, packet_context
);
1513 ret
= get_field_clock_value(packet_context
, "timestamp_end",
1516 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1517 "packet-addr=%p, packet-context-field-addr=%p",
1518 packet
, packet_context
);
1522 /* Move clock values to user */
1523 *user_ts_begin
= ts_begin
;
1525 *user_ts_end
= ts_end
;
1529 bt_put(packet_context
);
1536 int handle_discarded_elements(struct bt_notification_iterator
*iterator
,
1537 struct bt_ctf_packet
*packet
, struct stream_state
*stream_state
)
1539 struct bt_ctf_clock_value
*ts_begin
= NULL
;
1540 struct bt_ctf_clock_value
*ts_end
= NULL
;
1543 ret
= get_ts_begin_ts_end_from_packet(packet
, &ts_begin
, &ts_end
);
1545 BT_LOGW("Cannot get packet's beginning or end clock values: "
1546 "packet-addr=%p, ret=%d", packet
, ret
);
1551 ret
= handle_discarded_packets(iterator
, packet
, ts_begin
, ts_end
,
1554 BT_LOGW("Cannot handle discarded packets for packet: "
1555 "packet-addr=%p, ret=%d", packet
, ret
);
1560 ret
= handle_discarded_events(iterator
, packet
, ts_begin
, ts_end
,
1563 BT_LOGW("Cannot handle discarded events for packet: "
1564 "packet-addr=%p, ret=%d", packet
, ret
);
1576 int handle_packet_switch(struct bt_notification_iterator
*iterator
,
1577 struct bt_notification
*packet_begin_notif
,
1578 struct bt_ctf_packet
*new_packet
,
1579 struct stream_state
*stream_state
)
1583 if (stream_state
->cur_packet
== new_packet
) {
1587 BT_LOGV("Handling packet switch: "
1588 "cur-packet-addr=%p, new-packet-addr=%p",
1589 stream_state
->cur_packet
, new_packet
);
1591 if (stream_state
->cur_packet
) {
1592 /* End of the current packet */
1593 ret
= add_action_push_notif_packet_end(iterator
,
1594 stream_state
->cur_packet
);
1596 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
1602 * Check the new packet's context fields for discarded packets
1603 * and events to emit those automatic notifications.
1605 ret
= handle_discarded_elements(iterator
, new_packet
, stream_state
);
1607 BT_LOGE_STR("Cannot handle discarded elements for new packet.");
1611 /* Beginning of the new packet */
1612 if (packet_begin_notif
) {
1613 add_action_push_notif(iterator
, packet_begin_notif
);
1614 } else if (new_packet
) {
1615 ret
= add_action_push_notif_packet_begin(iterator
,
1618 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
1623 add_action_set_stream_state_cur_packet(iterator
, stream_state
,
1635 int handle_notif_stream_begin(
1636 struct bt_notification_iterator
*iterator
,
1637 struct bt_notification
*notif
,
1638 struct bt_ctf_stream
*notif_stream
)
1641 struct stream_state
*stream_state
;
1643 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_BEGIN
);
1644 assert(notif_stream
);
1645 ret
= ensure_stream_state_exists(iterator
, notif
, notif_stream
,
1648 BT_LOGE_STR("Cannot ensure that stream state exists.");
1662 int handle_notif_stream_end(
1663 struct bt_notification_iterator
*iterator
,
1664 struct bt_notification
*notif
,
1665 struct bt_ctf_stream
*notif_stream
)
1668 struct stream_state
*stream_state
;
1670 assert(notif
->type
== BT_NOTIFICATION_TYPE_STREAM_END
);
1671 assert(notif_stream
);
1672 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1675 BT_LOGE_STR("Cannot ensure that stream state exists.");
1679 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1681 BT_LOGE_STR("Cannot handle packet switch.");
1685 add_action_push_notif(iterator
, notif
);
1686 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1697 int handle_notif_discarded_elements(
1698 struct bt_notification_iterator
*iterator
,
1699 struct bt_notification
*notif
,
1700 struct bt_ctf_stream
*notif_stream
)
1703 struct stream_state
*stream_state
;
1705 assert(notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
||
1706 notif
->type
== BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
);
1707 assert(notif_stream
);
1708 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1711 BT_LOGE_STR("Cannot ensure that stream state exists.");
1715 add_action_push_notif(iterator
, notif
);
1726 int handle_notif_packet_begin(
1727 struct bt_notification_iterator
*iterator
,
1728 struct bt_notification
*notif
,
1729 struct bt_ctf_stream
*notif_stream
,
1730 struct bt_ctf_packet
*notif_packet
)
1733 struct stream_state
*stream_state
;
1735 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_BEGIN
);
1736 assert(notif_packet
);
1737 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1740 BT_LOGE_STR("Cannot ensure that stream state exists.");
1744 ret
= handle_packet_switch(iterator
, notif
, notif_packet
, stream_state
);
1746 BT_LOGE_STR("Cannot handle packet switch.");
1760 int handle_notif_packet_end(
1761 struct bt_notification_iterator
*iterator
,
1762 struct bt_notification
*notif
,
1763 struct bt_ctf_stream
*notif_stream
,
1764 struct bt_ctf_packet
*notif_packet
)
1767 struct stream_state
*stream_state
;
1769 assert(notif
->type
== BT_NOTIFICATION_TYPE_PACKET_END
);
1770 assert(notif_packet
);
1771 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1774 BT_LOGE_STR("Cannot ensure that stream state exists.");
1778 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1780 BT_LOGE_STR("Cannot handle packet switch.");
1784 /* End of the current packet */
1785 add_action_push_notif(iterator
, notif
);
1786 add_action_set_stream_state_cur_packet(iterator
, stream_state
, NULL
);
1797 int handle_notif_event(
1798 struct bt_notification_iterator
*iterator
,
1799 struct bt_notification
*notif
,
1800 struct bt_ctf_stream
*notif_stream
,
1801 struct bt_ctf_packet
*notif_packet
)
1804 struct stream_state
*stream_state
;
1806 assert(notif
->type
== BT_NOTIFICATION_TYPE_EVENT
);
1807 assert(notif_packet
);
1808 ret
= ensure_stream_state_exists(iterator
, NULL
, notif_stream
,
1811 BT_LOGE_STR("Cannot ensure that stream state exists.");
1815 ret
= handle_packet_switch(iterator
, NULL
, notif_packet
, stream_state
);
1817 BT_LOGE_STR("Cannot handle packet switch.");
1821 add_action_push_notif(iterator
, notif
);
1832 int enqueue_notification_and_automatic(
1833 struct bt_notification_iterator
*iterator
,
1834 struct bt_notification
*notif
)
1837 struct bt_ctf_event
*notif_event
= NULL
;
1838 struct bt_ctf_stream
*notif_stream
= NULL
;
1839 struct bt_ctf_packet
*notif_packet
= NULL
;
1843 BT_LOGV("Enqueuing user notification and automatic notifications: "
1844 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1846 // TODO: Skip most of this if the iterator is only subscribed
1847 // to event/inactivity notifications.
1849 /* Get the stream and packet referred by the notification */
1850 switch (notif
->type
) {
1851 case BT_NOTIFICATION_TYPE_EVENT
:
1852 notif_event
= bt_notification_event_borrow_event(notif
);
1853 assert(notif_event
);
1854 notif_packet
= bt_ctf_event_borrow_packet(notif_event
);
1855 assert(notif_packet
);
1857 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1859 bt_notification_stream_begin_borrow_stream(notif
);
1860 assert(notif_stream
);
1862 case BT_NOTIFICATION_TYPE_STREAM_END
:
1863 notif_stream
= bt_notification_stream_end_borrow_stream(notif
);
1864 assert(notif_stream
);
1866 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1868 bt_notification_packet_begin_borrow_packet(notif
);
1869 assert(notif_packet
);
1871 case BT_NOTIFICATION_TYPE_PACKET_END
:
1872 notif_packet
= bt_notification_packet_end_borrow_packet(notif
);
1873 assert(notif_packet
);
1875 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1880 * Invalid type of notification. Only the notification
1881 * types above are allowed to be returned by a user
1884 BT_LOGF("Unexpected notification type at this point: "
1885 "notif-addr=%p, notif-type=%s", notif
,
1886 bt_notification_type_string(notif
->type
));
1891 notif_stream
= bt_ctf_packet_borrow_stream(notif_packet
);
1892 assert(notif_stream
);
1895 if (!notif_stream
) {
1897 * The notification has no reference to a stream: it
1898 * cannot cause the creation of automatic notifications.
1900 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
1904 if (!validate_notification(iterator
, notif
, notif_stream
,
1906 BT_LOGW_STR("Invalid notification.");
1911 switch (notif
->type
) {
1912 case BT_NOTIFICATION_TYPE_EVENT
:
1913 ret
= handle_notif_event(iterator
, notif
, notif_stream
,
1916 case BT_NOTIFICATION_TYPE_STREAM_BEGIN
:
1917 ret
= handle_notif_stream_begin(iterator
, notif
, notif_stream
);
1919 case BT_NOTIFICATION_TYPE_STREAM_END
:
1920 ret
= handle_notif_stream_end(iterator
, notif
, notif_stream
);
1922 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
1923 ret
= handle_notif_packet_begin(iterator
, notif
, notif_stream
,
1926 case BT_NOTIFICATION_TYPE_PACKET_END
:
1927 ret
= handle_notif_packet_end(iterator
, notif
, notif_stream
,
1930 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
1931 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
1932 ret
= handle_notif_discarded_elements(iterator
, notif
,
1935 case BT_NOTIFICATION_TYPE_INACTIVITY
:
1936 add_action_push_notif(iterator
, notif
);
1943 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
1947 apply_actions(iterator
);
1948 BT_LOGV("Enqueued user notification and automatic notifications: "
1949 "iter-addr=%p, notif-addr=%p", iterator
, notif
);
1960 int handle_end(struct bt_notification_iterator
*iterator
)
1962 GHashTableIter stream_state_iter
;
1963 gpointer stream_gptr
, stream_state_gptr
;
1966 BT_LOGV("Handling end of iteration: addr=%p", iterator
);
1969 * Emit a "stream end" notification for each non-ended stream
1970 * known by this iterator and mark them as ended.
1972 g_hash_table_iter_init(&stream_state_iter
, iterator
->stream_states
);
1974 while (g_hash_table_iter_next(&stream_state_iter
, &stream_gptr
,
1975 &stream_state_gptr
)) {
1976 struct stream_state
*stream_state
= stream_state_gptr
;
1978 assert(stream_state_gptr
);
1980 if (stream_state
->is_ended
) {
1984 ret
= handle_packet_switch(iterator
, NULL
, NULL
, stream_state
);
1986 BT_LOGE_STR("Cannot handle packet switch.");
1990 ret
= add_action_push_notif_stream_end(iterator
, stream_gptr
);
1992 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
1996 add_action_set_stream_state_is_ended(iterator
, stream_state
);
1999 apply_actions(iterator
);
2000 BT_LOGV("Handled end of iteration: addr=%p", iterator
);
2011 enum bt_notification_iterator_status
ensure_queue_has_notifications(
2012 struct bt_notification_iterator
*iterator
)
2014 struct bt_private_notification_iterator
*priv_iterator
=
2015 bt_private_notification_iterator_from_notification_iterator(iterator
);
2016 bt_component_class_notification_iterator_next_method next_method
= NULL
;
2017 struct bt_notification_iterator_next_return next_return
= {
2018 .status
= BT_NOTIFICATION_ITERATOR_STATUS_OK
,
2019 .notification
= NULL
,
2021 enum bt_notification_iterator_status status
=
2022 BT_NOTIFICATION_ITERATOR_STATUS_OK
;
2026 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
2027 "iter-addr=%p, queue-size=%u, iter-state=%s",
2028 iterator
, iterator
->queue
->length
,
2029 bt_notification_iterator_state_string(iterator
->state
));
2031 if (iterator
->queue
->length
> 0) {
2033 * We already have enough. Even if this notification
2034 * iterator is finalized, its user can still flush its
2035 * current queue's content by calling its "next" method
2036 * since this content is local and has no impact on what
2037 * used to be the iterator's upstream component.
2039 BT_LOGD_STR("Queue already has at least one notification.");
2043 switch (iterator
->state
) {
2044 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
:
2045 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
:
2046 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
2047 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2049 case BT_NOTIFICATION_ITERATOR_STATE_ENDED
:
2050 BT_LOGD_STR("Notification iterator is ended.");
2051 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2057 assert(iterator
->upstream_component
);
2058 assert(iterator
->upstream_component
->class);
2060 /* Pick the appropriate "next" method */
2061 switch (iterator
->upstream_component
->class->type
) {
2062 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
2064 struct bt_component_class_source
*source_class
=
2065 container_of(iterator
->upstream_component
->class,
2066 struct bt_component_class_source
, parent
);
2068 assert(source_class
->methods
.iterator
.next
);
2069 next_method
= source_class
->methods
.iterator
.next
;
2072 case BT_COMPONENT_CLASS_TYPE_FILTER
:
2074 struct bt_component_class_filter
*filter_class
=
2075 container_of(iterator
->upstream_component
->class,
2076 struct bt_component_class_filter
, parent
);
2078 assert(filter_class
->methods
.iterator
.next
);
2079 next_method
= filter_class
->methods
.iterator
.next
;
2087 * Call the user's "next" method to get the next notification
2090 assert(next_method
);
2092 while (iterator
->queue
->length
== 0) {
2093 BT_LOGD_STR("Calling user's \"next\" method.");
2094 next_return
= next_method(priv_iterator
);
2095 BT_LOGD("User method returned: status=%s",
2096 bt_notification_iterator_status_string(next_return
.status
));
2097 if (next_return
.status
< 0) {
2098 BT_LOGW_STR("User method failed.");
2099 status
= next_return
.status
;
2103 if (iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED
||
2104 iterator
->state
== BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED
) {
2106 * The user's "next" method, somehow, cancelled
2107 * its own notification iterator. This can
2108 * happen, for example, when the user's method
2109 * removes the port on which there's the
2110 * connection from which the iterator was
2111 * created. In this case, said connection is
2112 * ended, and all its notification iterators are
2115 * Only bt_put() the returned notification if
2117 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
2118 * otherwise this field could be garbage.
2120 if (next_return
.status
==
2121 BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2122 bt_put(next_return
.notification
);
2125 status
= BT_NOTIFICATION_ITERATOR_STATUS_CANCELED
;
2129 switch (next_return
.status
) {
2130 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
2131 ret
= handle_end(iterator
);
2133 BT_LOGW_STR("Cannot handle end of iteration.");
2134 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2138 assert(iterator
->state
==
2139 BT_NOTIFICATION_ITERATOR_STATE_ACTIVE
);
2140 iterator
->state
= BT_NOTIFICATION_ITERATOR_STATE_ENDED
;
2142 if (iterator
->queue
->length
== 0) {
2143 status
= BT_NOTIFICATION_ITERATOR_STATUS_END
;
2146 BT_LOGD("Set new status: status=%s",
2147 bt_notification_iterator_status_string(status
));
2149 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
:
2150 status
= BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
;
2152 case BT_NOTIFICATION_ITERATOR_STATUS_OK
:
2153 if (!next_return
.notification
) {
2154 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
2155 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2160 * Ignore some notifications which are always
2161 * automatically generated by the notification
2162 * iterator to make sure they have valid values.
2164 switch (next_return
.notification
->type
) {
2165 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS
:
2166 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS
:
2167 BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: "
2169 bt_notification_type_string(next_return
.notification
->type
));
2170 BT_PUT(next_return
.notification
);
2177 * We know the notification is valid. Before we
2178 * push it to the head of the queue, push the
2179 * appropriate automatic notifications if any.
2181 ret
= enqueue_notification_and_automatic(iterator
,
2182 next_return
.notification
);
2183 BT_PUT(next_return
.notification
);
2185 BT_LOGW("Cannot enqueue notification and automatic notifications.");
2186 status
= BT_NOTIFICATION_ITERATOR_STATUS_ERROR
;
2191 /* Unknown non-error status */
2200 enum bt_notification_iterator_status
2201 bt_notification_iterator_next(struct bt_notification_iterator
*iterator
)
2203 enum bt_notification_iterator_status status
;
2206 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
2207 status
= BT_NOTIFICATION_ITERATOR_STATUS_INVALID
;
2211 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator
);
2214 * Make sure that the iterator's queue contains at least one
2217 status
= ensure_queue_has_notifications(iterator
);
2218 if (status
!= BT_NOTIFICATION_ITERATOR_STATUS_OK
) {
2224 * Move the notification at the tail of the queue to the
2225 * iterator's current notification.
2227 assert(iterator
->queue
->length
> 0);
2228 bt_put(iterator
->current_notification
);
2229 iterator
->current_notification
= g_queue_pop_tail(iterator
->queue
);
2230 assert(iterator
->current_notification
);
2236 struct bt_component
*bt_notification_iterator_get_component(
2237 struct bt_notification_iterator
*iterator
)
2239 return bt_get(iterator
->upstream_component
);
2242 struct bt_private_component
*
2243 bt_private_notification_iterator_get_private_component(
2244 struct bt_private_notification_iterator
*private_iterator
)
2246 return bt_private_component_from_component(
2247 bt_notification_iterator_get_component(
2248 bt_notification_iterator_from_private(private_iterator
)));
2251 enum bt_notification_iterator_status
bt_notification_iterator_seek_time(
2252 struct bt_notification_iterator
*iterator
,
2253 enum bt_notification_iterator_seek_origin seek_origin
,
2256 enum bt_notification_iterator_status ret
=
2257 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED
;