Fix: cli: Coverity issue: no need to check `status`
[babeltrace.git] / lib / graph / iterator.c
CommitLineData
47e5a032
JG
1/*
2 * iterator.c
3 *
4 * Babeltrace Notification Iterator
5 *
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3230ee6b 7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
47e5a032
JG
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
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
25 * SOFTWARE.
26 */
27
5af447e5
PP
28#define BT_LOG_TAG "NOTIF-ITER"
29#include <babeltrace/lib-logging-internal.h>
30
3d9990ac 31#include <babeltrace/compiler-internal.h>
b8a06801 32#include <babeltrace/ref.h>
2ec84d26
PP
33#include <babeltrace/ctf-ir/fields.h>
34#include <babeltrace/ctf-ir/field-types.h>
35#include <babeltrace/ctf-ir/field-types-internal.h>
3230ee6b
PP
36#include <babeltrace/ctf-ir/event-internal.h>
37#include <babeltrace/ctf-ir/packet-internal.h>
38#include <babeltrace/ctf-ir/stream-internal.h>
73d5c1ad 39#include <babeltrace/graph/connection.h>
bd14d768 40#include <babeltrace/graph/connection-internal.h>
b2e0c907
PP
41#include <babeltrace/graph/component.h>
42#include <babeltrace/graph/component-source-internal.h>
43#include <babeltrace/graph/component-class-internal.h>
fa054faf 44#include <babeltrace/graph/notification.h>
b2e0c907
PP
45#include <babeltrace/graph/notification-iterator.h>
46#include <babeltrace/graph/notification-iterator-internal.h>
e7fa96c3 47#include <babeltrace/graph/notification-internal.h>
3230ee6b
PP
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>
2ec84d26 54#include <babeltrace/graph/notification-discarded-elements-internal.h>
3230ee6b 55#include <babeltrace/graph/port.h>
c55a9f58 56#include <babeltrace/types.h>
fa054faf 57#include <stdint.h>
2ec84d26 58#include <inttypes.h>
0fbb9a9f 59#include <stdlib.h>
3230ee6b 60
2ec84d26
PP
61struct discarded_elements_state {
62 struct bt_ctf_clock_value *cur_begin;
63 uint64_t cur_count;
64};
65
3230ee6b
PP
66struct stream_state {
67 struct bt_ctf_stream *stream; /* owned by this */
68 struct bt_ctf_packet *cur_packet; /* owned by this */
2ec84d26
PP
69 struct discarded_elements_state discarded_packets_state;
70 struct discarded_elements_state discarded_events_state;
c55a9f58 71 bt_bool is_ended;
3230ee6b
PP
72};
73
74enum action_type {
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,
2ec84d26
PP
80 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS,
81 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS,
3230ee6b
PP
82};
83
84struct action {
85 enum action_type type;
86 union {
87 /* ACTION_TYPE_PUSH_NOTIF */
88 struct {
89 struct bt_notification *notif; /* owned by this */
90 } push_notif;
91
92 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
93 struct {
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;
98
99 /* ACTION_TYPE_ADD_STREAM_STATE */
100 struct {
101 struct bt_ctf_stream *stream; /* owned by this */
102 struct stream_state *stream_state; /* owned by this */
103 } add_stream_state;
104
105 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
106 struct {
107 struct stream_state *stream_state; /* weak */
108 } set_stream_state_is_ended;
109
110 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
111 struct {
112 struct stream_state *stream_state; /* weak */
113 struct bt_ctf_packet *packet; /* owned by this */
114 } set_stream_state_cur_packet;
2ec84d26
PP
115
116 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */
117 /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */
118 struct {
119 struct stream_state *stream_state; /* weak */
120 struct bt_ctf_clock_value *cur_begin; /* owned by this */
121 uint64_t cur_count;
122 } update_stream_state_discarded_elements;
3230ee6b
PP
123 } payload;
124};
125
126static
127void stream_destroy_listener(struct bt_ctf_stream *stream, void *data)
128{
129 struct bt_notification_iterator *iterator = data;
130
131 /* Remove associated stream state */
132 g_hash_table_remove(iterator->stream_states, stream);
133}
134
135static
136void destroy_stream_state(struct stream_state *stream_state)
137{
138 if (!stream_state) {
139 return;
140 }
141
5af447e5
PP
142 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state);
143 BT_LOGV_STR("Putting stream state's current packet.");
3230ee6b 144 bt_put(stream_state->cur_packet);
5af447e5 145 BT_LOGV_STR("Putting stream state's stream.");
3230ee6b 146 bt_put(stream_state->stream);
2ec84d26
PP
147 bt_put(stream_state->discarded_packets_state.cur_begin);
148 bt_put(stream_state->discarded_events_state.cur_begin);
3230ee6b
PP
149 g_free(stream_state);
150}
151
152static
153void destroy_action(struct action *action)
154{
155 assert(action);
156
157 switch (action->type) {
158 case ACTION_TYPE_PUSH_NOTIF:
159 BT_PUT(action->payload.push_notif.notif);
160 break;
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);
165 break;
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;
171 break;
172 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
173 BT_PUT(action->payload.set_stream_state_cur_packet.packet);
174 break;
175 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
176 break;
2ec84d26
PP
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);
180 break;
3230ee6b 181 default:
2ec84d26 182 BT_LOGF("Unexpected action's type: type=%d", action->type);
0fbb9a9f 183 abort();
3230ee6b
PP
184 }
185}
186
187static
188void add_action(struct bt_notification_iterator *iterator,
189 struct action *action)
190{
191 g_array_append_val(iterator->actions, *action);
192}
193
194static
195void clear_actions(struct bt_notification_iterator *iterator)
196{
197 size_t i;
198
199 for (i = 0; i < iterator->actions->len; i++) {
200 struct action *action = &g_array_index(iterator->actions,
201 struct action, i);
202
203 destroy_action(action);
204 }
205
206 g_array_set_size(iterator->actions, 0);
207}
208
5af447e5
PP
209static inline
210const char *action_type_string(enum action_type type)
211{
212 switch (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";
2ec84d26
PP
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";
5af447e5
PP
227 default:
228 return "(unknown)";
229 }
230}
231
3230ee6b
PP
232static
233void apply_actions(struct bt_notification_iterator *iterator)
234{
235 size_t i;
236
5af447e5
PP
237 BT_LOGV("Applying notification's iterator current actions: "
238 "count=%u", iterator->actions->len);
239
3230ee6b
PP
240 for (i = 0; i < iterator->actions->len; i++) {
241 struct action *action = &g_array_index(iterator->actions,
242 struct action, i);
243
5af447e5
PP
244 BT_LOGV("Applying action: index=%zu, type=%s",
245 i, action_type_string(action->type));
246
3230ee6b
PP
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;
255 break;
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);
261 break;
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);
267
268 action->payload.add_stream_state.stream_state = NULL;
269 break;
270 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
271 /*
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
275 * twice.
276 *
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.
286 */
287 bt_ctf_stream_add_destroy_listener(
288 action->payload.set_stream_state_is_ended.stream_state->stream,
289 stream_destroy_listener, iterator);
c55a9f58 290 action->payload.set_stream_state_is_ended.stream_state->is_ended = BT_TRUE;
3230ee6b
PP
291 BT_PUT(action->payload.set_stream_state_is_ended.stream_state->stream);
292 break;
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);
297 break;
2ec84d26
PP
298 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS:
299 case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS:
300 {
301 struct discarded_elements_state *state;
302
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;
305 } else {
306 state = &action->payload.update_stream_state_discarded_elements.stream_state->discarded_events_state;
307 }
308
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;
312 break;
313 }
3230ee6b 314 default:
2ec84d26
PP
315 BT_LOGF("Unexpected action's type: type=%d",
316 action->type);
0fbb9a9f 317 abort();
3230ee6b
PP
318 }
319 }
320
321 clear_actions(iterator);
322}
323
324static
325struct stream_state *create_stream_state(struct bt_ctf_stream *stream)
326{
327 struct stream_state *stream_state = g_new0(struct stream_state, 1);
328
329 if (!stream_state) {
5af447e5 330 BT_LOGE_STR("Failed to allocate one stream state.");
3230ee6b
PP
331 goto end;
332 }
333
126215b4
MD
334 /*
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
339 * seqnum = 0.
340 */
341 stream_state->discarded_packets_state.cur_count = -1ULL;
342
3230ee6b
PP
343 /*
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.
348 *
349 * We put this reference when the stream is marked as ended.
350 */
351 stream_state->stream = bt_get(stream);
5af447e5
PP
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);
3230ee6b
PP
355
356end:
357 return stream_state;
358}
47e5a032
JG
359
360static
b8a06801 361void bt_notification_iterator_destroy(struct bt_object *obj)
47e5a032 362{
8738a040
JG
363 struct bt_notification_iterator *iterator;
364
b8a06801 365 assert(obj);
d3eb6e8f 366
bd14d768
PP
367 /*
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.
376 */
377 obj->ref_count.count++;
378 iterator = container_of(obj, struct bt_notification_iterator, base);
5af447e5
PP
379 BT_LOGD("Destroying notification iterator object: addr=%p",
380 iterator);
bd14d768 381 bt_notification_iterator_finalize(iterator);
d3eb6e8f 382
3230ee6b
PP
383 if (iterator->queue) {
384 struct bt_notification *notif;
385
5af447e5
PP
386 BT_LOGD("Putting notifications in queue.");
387
3230ee6b
PP
388 while ((notif = g_queue_pop_tail(iterator->queue))) {
389 bt_put(notif);
390 }
391
392 g_queue_free(iterator->queue);
393 }
394
395 if (iterator->stream_states) {
396 /*
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.
401 */
402 GHashTableIter ht_iter;
403 gpointer stream_gptr, stream_state_gptr;
404
405 g_hash_table_iter_init(&ht_iter, iterator->stream_states);
406
407 while (g_hash_table_iter_next(&ht_iter, &stream_gptr, &stream_state_gptr)) {
408 assert(stream_gptr);
5af447e5
PP
409
410 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
3230ee6b
PP
411 bt_ctf_stream_remove_destroy_listener(
412 (void *) stream_gptr, stream_destroy_listener,
413 iterator);
414 }
415
416 g_hash_table_destroy(iterator->stream_states);
417 }
418
419 if (iterator->actions) {
420 g_array_free(iterator->actions, TRUE);
421 }
422
bd14d768
PP
423 if (iterator->connection) {
424 /*
425 * Remove ourself from the originating connection so
426 * that it does not try to finalize a dangling pointer
427 * later.
428 */
429 bt_connection_remove_iterator(iterator->connection, iterator);
430 }
431
5af447e5 432 BT_LOGD_STR("Putting current notification.");
3230ee6b 433 bt_put(iterator->current_notification);
8738a040 434 g_free(iterator);
47e5a032
JG
435}
436
bd14d768
PP
437BT_HIDDEN
438void bt_notification_iterator_finalize(
439 struct bt_notification_iterator *iterator)
440{
441 struct bt_component_class *comp_class = NULL;
442 bt_component_class_notification_iterator_finalize_method
443 finalize_method = NULL;
444
445 assert(iterator);
446
447 switch (iterator->state) {
448 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
449 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
450 /* Already finalized */
5af447e5
PP
451 BT_LOGD("Not finalizing notification iterator: already finalized: "
452 "addr=%p", iterator);
bd14d768
PP
453 return;
454 default:
455 break;
456 }
457
5af447e5
PP
458 BT_LOGD("Finalizing notification iterator: addr=%p", iterator);
459
df14f8af 460 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_ENDED) {
5af447e5
PP
461 BT_LOGD("Updating notification iterator's state: "
462 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
df14f8af
MD
463 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
464 } else {
5af447e5
PP
465 BT_LOGD("Updating notification iterator's state: "
466 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
df14f8af
MD
467 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED;
468 }
469
bd14d768
PP
470 assert(iterator->upstream_component);
471 comp_class = iterator->upstream_component->class;
472
473 /* Call user-defined destroy method */
474 switch (comp_class->type) {
475 case BT_COMPONENT_CLASS_TYPE_SOURCE:
476 {
477 struct bt_component_class_source *source_class;
478
479 source_class = container_of(comp_class, struct bt_component_class_source, parent);
480 finalize_method = source_class->methods.iterator.finalize;
481 break;
482 }
483 case BT_COMPONENT_CLASS_TYPE_FILTER:
484 {
485 struct bt_component_class_filter *filter_class;
486
487 filter_class = container_of(comp_class, struct bt_component_class_filter, parent);
488 finalize_method = filter_class->methods.iterator.finalize;
489 break;
490 }
491 default:
492 /* Unreachable */
0fbb9a9f 493 abort();
bd14d768
PP
494 }
495
496 if (finalize_method) {
5af447e5
PP
497 BT_LOGD("Calling user's finalization method: addr=%p",
498 iterator);
bd14d768
PP
499 finalize_method(
500 bt_private_notification_iterator_from_notification_iterator(iterator));
501 }
502
bd14d768
PP
503 iterator->upstream_component = NULL;
504 iterator->upstream_port = NULL;
5af447e5 505 BT_LOGD("Finalized notification iterator: addr=%p", iterator);
bd14d768
PP
506}
507
508BT_HIDDEN
509void bt_notification_iterator_set_connection(
510 struct bt_notification_iterator *iterator,
511 struct bt_connection *connection)
512{
513 assert(iterator);
514 iterator->connection = connection;
5af447e5
PP
515 BT_LOGV("Set notification iterator's connection: "
516 "iter-addr=%p, conn-addr=%p", iterator, connection);
bd14d768
PP
517}
518
fa054faf
PP
519static
520int create_subscription_mask_from_notification_types(
521 struct bt_notification_iterator *iterator,
522 const enum bt_notification_type *notif_types)
523{
524 const enum bt_notification_type *notif_type;
525 int ret = 0;
526
527 assert(notif_types);
528 iterator->subscription_mask = 0;
529
530 for (notif_type = notif_types;
531 *notif_type != BT_NOTIFICATION_TYPE_SENTINEL;
532 notif_type++) {
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 |
2ec84d26
PP
541 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END |
542 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS |
543 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
fa054faf
PP
544 break;
545 case BT_NOTIFICATION_TYPE_EVENT:
546 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
547 break;
548 case BT_NOTIFICATION_TYPE_INACTIVITY:
549 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
550 break;
551 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
552 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
553 break;
554 case BT_NOTIFICATION_TYPE_STREAM_END:
555 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
556 break;
557 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
558 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
559 break;
560 case BT_NOTIFICATION_TYPE_PACKET_END:
561 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
562 break;
2ec84d26
PP
563 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
564 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
565 break;
566 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
567 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
568 break;
fa054faf
PP
569 default:
570 ret = -1;
571 goto end;
572 }
5af447e5
PP
573
574 BT_LOGV("Added notification type to subscription mask: "
575 "type=%s, mask=%x",
576 bt_notification_type_string(*notif_type),
577 iterator->subscription_mask);
fa054faf
PP
578 }
579
580end:
581 return ret;
582}
583
47e5a032 584BT_HIDDEN
73d5c1ad 585enum bt_connection_status bt_notification_iterator_create(
3230ee6b 586 struct bt_component *upstream_comp,
fa054faf 587 struct bt_port *upstream_port,
bd14d768 588 const enum bt_notification_type *notification_types,
73d5c1ad
PP
589 struct bt_connection *connection,
590 struct bt_notification_iterator **user_iterator)
47e5a032 591{
73d5c1ad 592 enum bt_connection_status status = BT_CONNECTION_STATUS_OK;
d3e4dcd8 593 enum bt_component_class_type type;
47e5a032
JG
594 struct bt_notification_iterator *iterator = NULL;
595
3230ee6b
PP
596 assert(upstream_comp);
597 assert(upstream_port);
fa054faf 598 assert(notification_types);
3230ee6b 599 assert(bt_port_is_connected(upstream_port));
73d5c1ad 600 assert(user_iterator);
5af447e5
PP
601 BT_LOGD("Creating notification iterator: "
602 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
603 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
604 "conn-addr=%p",
605 upstream_comp, bt_component_get_name(upstream_comp),
606 upstream_port, bt_port_get_name(upstream_port),
607 connection);
3230ee6b 608 type = bt_component_get_class_type(upstream_comp);
ef2f7566
PP
609 assert(type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
610 type == BT_COMPONENT_CLASS_TYPE_FILTER);
47e5a032
JG
611 iterator = g_new0(struct bt_notification_iterator, 1);
612 if (!iterator) {
5af447e5 613 BT_LOGE_STR("Failed to allocate one notification iterator.");
73d5c1ad
PP
614 status = BT_CONNECTION_STATUS_NOMEM;
615 goto end;
47e5a032
JG
616 }
617
b8a06801 618 bt_object_init(iterator, bt_notification_iterator_destroy);
3230ee6b 619
fa054faf
PP
620 if (create_subscription_mask_from_notification_types(iterator,
621 notification_types)) {
5af447e5 622 BT_LOGW_STR("Cannot create subscription mask from notification types.");
73d5c1ad
PP
623 status = BT_CONNECTION_STATUS_INVALID;
624 goto end;
fa054faf
PP
625 }
626
3230ee6b
PP
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) {
5af447e5 630 BT_LOGE_STR("Failed to allocate a GHashTable.");
73d5c1ad
PP
631 status = BT_CONNECTION_STATUS_NOMEM;
632 goto end;
3230ee6b
PP
633 }
634
635 iterator->queue = g_queue_new();
636 if (!iterator->queue) {
5af447e5 637 BT_LOGE_STR("Failed to allocate a GQueue.");
73d5c1ad
PP
638 status = BT_CONNECTION_STATUS_NOMEM;
639 goto end;
3230ee6b
PP
640 }
641
642 iterator->actions = g_array_new(FALSE, FALSE, sizeof(struct action));
643 if (!iterator->actions) {
5af447e5 644 BT_LOGE_STR("Failed to allocate a GArray.");
73d5c1ad
PP
645 status = BT_CONNECTION_STATUS_NOMEM;
646 goto end;
3230ee6b
PP
647 }
648
bd14d768
PP
649 iterator->upstream_component = upstream_comp;
650 iterator->upstream_port = upstream_port;
651 iterator->connection = connection;
652 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ACTIVE;
5af447e5
PP
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);
1a6a376a
PP
660
661 /* Move reference to user */
662 *user_iterator = iterator;
663 iterator = NULL;
3230ee6b 664
47e5a032 665end:
73d5c1ad
PP
666 bt_put(iterator);
667 return status;
47e5a032
JG
668}
669
890882ef
PP
670void *bt_private_notification_iterator_get_user_data(
671 struct bt_private_notification_iterator *private_iterator)
ea8d3e58 672{
890882ef
PP
673 struct bt_notification_iterator *iterator =
674 bt_notification_iterator_from_private(private_iterator);
675
ea8d3e58
JG
676 return iterator ? iterator->user_data : NULL;
677}
678
679enum bt_notification_iterator_status
890882ef
PP
680bt_private_notification_iterator_set_user_data(
681 struct bt_private_notification_iterator *private_iterator,
682 void *data)
ea8d3e58
JG
683{
684 enum bt_notification_iterator_status ret =
685 BT_NOTIFICATION_ITERATOR_STATUS_OK;
890882ef
PP
686 struct bt_notification_iterator *iterator =
687 bt_notification_iterator_from_private(private_iterator);
ea8d3e58 688
d3eb6e8f 689 if (!iterator) {
5af447e5 690 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
fe8ad2b6 691 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
ea8d3e58
JG
692 goto end;
693 }
694
695 iterator->user_data = data;
5af447e5
PP
696 BT_LOGV("Set notification iterator's user data: "
697 "iter-addr=%p, user-data-addr=%p", iterator, data);
698
8738a040
JG
699end:
700 return ret;
701}
413bc2c4 702
53d45b87
JG
703struct bt_notification *bt_notification_iterator_get_notification(
704 struct bt_notification_iterator *iterator)
705{
41a2b7ae 706 struct bt_notification *notification = NULL;
d3eb6e8f 707
41a2b7ae 708 if (!iterator) {
5af447e5 709 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
41a2b7ae 710 goto end;
d3eb6e8f 711 }
d3eb6e8f 712
41a2b7ae 713 notification = bt_get(iterator->current_notification);
d3eb6e8f 714
41a2b7ae
PP
715end:
716 return notification;
53d45b87
JG
717}
718
fa054faf
PP
719static
720enum bt_notification_iterator_notif_type
721bt_notification_iterator_notif_type_from_notif_type(
722 enum bt_notification_type notif_type)
723{
724 enum bt_notification_iterator_notif_type iter_notif_type;
725
726 switch (notif_type) {
727 case BT_NOTIFICATION_TYPE_EVENT:
728 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
729 break;
730 case BT_NOTIFICATION_TYPE_INACTIVITY:
731 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
732 break;
733 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
734 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
735 break;
736 case BT_NOTIFICATION_TYPE_STREAM_END:
737 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
738 break;
739 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
740 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
741 break;
742 case BT_NOTIFICATION_TYPE_PACKET_END:
743 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
744 break;
2ec84d26
PP
745 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
746 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
747 break;
748 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
749 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
750 break;
fa054faf 751 default:
0fbb9a9f 752 abort();
fa054faf
PP
753 }
754
755 return iter_notif_type;
756}
757
3230ee6b 758static
c55a9f58 759bt_bool validate_notification(struct bt_notification_iterator *iterator,
3230ee6b
PP
760 struct bt_notification *notif,
761 struct bt_ctf_stream *notif_stream,
762 struct bt_ctf_packet *notif_packet)
763{
c55a9f58 764 bt_bool is_valid = BT_TRUE;
3230ee6b
PP
765 struct stream_state *stream_state;
766 struct bt_port *stream_comp_cur_port;
767
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) {
773 /*
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.
778 */
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),
785 },
786 };
787
788 add_action(iterator, &action);
789 } else {
790 if (stream_comp_cur_port != iterator->upstream_port) {
791 /*
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
796 * happen.
797 */
5af447e5
PP
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",
804 notif_stream,
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));
c55a9f58 810 is_valid = BT_FALSE;
3230ee6b
PP
811 goto end;
812 }
813
814 }
815
816 stream_state = g_hash_table_lookup(iterator->stream_states,
817 notif_stream);
818 if (stream_state) {
5af447e5
PP
819 BT_LOGV("Stream state already exists: "
820 "stream-addr=%p, stream-name=\"%s\", "
821 "stream-state-addr=%p",
822 notif_stream,
823 bt_ctf_stream_get_name(notif_stream), stream_state);
824
3230ee6b
PP
825 if (stream_state->is_ended) {
826 /*
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
832 * happen.
833 */
5af447e5
PP
834 BT_LOGW("Stream is already ended: "
835 "stream-addr=%p, stream-name=\"%s\"",
836 notif_stream,
837 bt_ctf_stream_get_name(notif_stream));
c55a9f58 838 is_valid = BT_FALSE;
3230ee6b
PP
839 goto end;
840 }
841
842 switch (notif->type) {
843 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
844 /*
845 * We already have a stream state, which means
846 * we already returned a "stream begin"
847 * notification: this is an invalid duplicate.
848 */
5af447e5
PP
849 BT_LOGW("Duplicate stream beginning notification: "
850 "stream-addr=%p, stream-name=\"%s\"",
851 notif_stream,
852 bt_ctf_stream_get_name(notif_stream));
c55a9f58 853 is_valid = BT_FALSE;
3230ee6b
PP
854 goto end;
855 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
856 if (notif_packet == stream_state->cur_packet) {
857 /* Duplicate "packet begin" notification */
5af447e5
PP
858 BT_LOGW("Duplicate stream beginning notification: "
859 "stream-addr=%p, stream-name=\"%s\", "
860 "packet-addr=%p",
861 notif_stream,
862 bt_ctf_stream_get_name(notif_stream),
863 notif_packet);
c55a9f58 864 is_valid = BT_FALSE;
3230ee6b
PP
865 goto end;
866 }
867 break;
868 default:
869 break;
870 }
871 }
872
873end:
874 return is_valid;
875}
876
fa054faf 877static
c55a9f58 878bt_bool is_subscribed_to_notification_type(struct bt_notification_iterator *iterator,
fa054faf
PP
879 enum bt_notification_type notif_type)
880{
881 uint32_t iter_notif_type =
882 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
883 notif_type);
884
c55a9f58 885 return (iter_notif_type & iterator->subscription_mask) ? BT_TRUE : BT_FALSE;
fa054faf
PP
886}
887
3230ee6b
PP
888static
889void add_action_push_notif(struct bt_notification_iterator *iterator,
890 struct bt_notification *notif)
891{
892 struct action action = {
893 .type = ACTION_TYPE_PUSH_NOTIF,
3230ee6b
PP
894 };
895
896 assert(notif);
fa054faf
PP
897
898 if (!is_subscribed_to_notification_type(iterator, notif->type)) {
899 return;
900 }
901
902 action.payload.push_notif.notif = bt_get(notif);
3230ee6b 903 add_action(iterator, &action);
5af447e5 904 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif);
3230ee6b
PP
905}
906
907static
908int add_action_push_notif_stream_begin(
909 struct bt_notification_iterator *iterator,
910 struct bt_ctf_stream *stream)
911{
912 int ret = 0;
913 struct bt_notification *stream_begin_notif = NULL;
914
fa054faf
PP
915 if (!is_subscribed_to_notification_type(iterator,
916 BT_NOTIFICATION_TYPE_STREAM_BEGIN)) {
5af447e5
PP
917 BT_LOGV("Not adding \"push stream beginning notification\" action: "
918 "notification iterator is not subscribed: addr=%p",
919 iterator);
fa054faf
PP
920 goto end;
921 }
922
3230ee6b
PP
923 assert(stream);
924 stream_begin_notif = bt_notification_stream_begin_create(stream);
925 if (!stream_begin_notif) {
5af447e5 926 BT_LOGE_STR("Cannot create stream beginning notification.");
3230ee6b
PP
927 goto error;
928 }
929
930 add_action_push_notif(iterator, stream_begin_notif);
5af447e5
PP
931 BT_LOGV("Added \"push stream beginning notification\" action: "
932 "stream-addr=%p, stream-name=\"%s\"",
933 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
934 goto end;
935
936error:
937 ret = -1;
938
939end:
940 bt_put(stream_begin_notif);
941 return ret;
942}
943
944static
945int add_action_push_notif_stream_end(
946 struct bt_notification_iterator *iterator,
947 struct bt_ctf_stream *stream)
948{
949 int ret = 0;
950 struct bt_notification *stream_end_notif = NULL;
951
fa054faf
PP
952 if (!is_subscribed_to_notification_type(iterator,
953 BT_NOTIFICATION_TYPE_STREAM_END)) {
5af447e5
PP
954 BT_LOGV("Not adding \"push stream end notification\" action: "
955 "notification iterator is not subscribed: addr=%p",
956 iterator);
fa054faf
PP
957 goto end;
958 }
959
3230ee6b
PP
960 assert(stream);
961 stream_end_notif = bt_notification_stream_end_create(stream);
962 if (!stream_end_notif) {
5af447e5 963 BT_LOGE_STR("Cannot create stream end notification.");
3230ee6b
PP
964 goto error;
965 }
966
967 add_action_push_notif(iterator, stream_end_notif);
5af447e5
PP
968 BT_LOGV("Added \"push stream end notification\" action: "
969 "stream-addr=%p, stream-name=\"%s\"",
970 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
971 goto end;
972
973error:
974 ret = -1;
975
976end:
977 bt_put(stream_end_notif);
978 return ret;
979}
980
981static
982int add_action_push_notif_packet_begin(
983 struct bt_notification_iterator *iterator,
984 struct bt_ctf_packet *packet)
985{
986 int ret = 0;
987 struct bt_notification *packet_begin_notif = NULL;
988
fa054faf
PP
989 if (!is_subscribed_to_notification_type(iterator,
990 BT_NOTIFICATION_TYPE_PACKET_BEGIN)) {
5af447e5
PP
991 BT_LOGV("Not adding \"push packet beginning notification\" action: "
992 "notification iterator is not subscribed: addr=%p",
993 iterator);
fa054faf
PP
994 goto end;
995 }
996
3230ee6b
PP
997 assert(packet);
998 packet_begin_notif = bt_notification_packet_begin_create(packet);
999 if (!packet_begin_notif) {
5af447e5 1000 BT_LOGE_STR("Cannot create packet beginning notification.");
3230ee6b
PP
1001 goto error;
1002 }
1003
1004 add_action_push_notif(iterator, packet_begin_notif);
5af447e5
PP
1005 BT_LOGV("Added \"push packet beginning notification\" action: "
1006 "packet-addr=%p", packet);
3230ee6b
PP
1007 goto end;
1008
1009error:
1010 ret = -1;
1011
1012end:
1013 bt_put(packet_begin_notif);
1014 return ret;
1015}
1016
1017static
1018int add_action_push_notif_packet_end(
1019 struct bt_notification_iterator *iterator,
1020 struct bt_ctf_packet *packet)
1021{
1022 int ret = 0;
1023 struct bt_notification *packet_end_notif = NULL;
1024
fa054faf
PP
1025 if (!is_subscribed_to_notification_type(iterator,
1026 BT_NOTIFICATION_TYPE_PACKET_END)) {
5af447e5
PP
1027 BT_LOGV("Not adding \"push packet end notification\" action: "
1028 "notification iterator is not subscribed: addr=%p",
1029 iterator);
fa054faf
PP
1030 goto end;
1031 }
1032
3230ee6b
PP
1033 assert(packet);
1034 packet_end_notif = bt_notification_packet_end_create(packet);
1035 if (!packet_end_notif) {
5af447e5 1036 BT_LOGE_STR("Cannot create packet end notification.");
3230ee6b
PP
1037 goto error;
1038 }
1039
1040 add_action_push_notif(iterator, packet_end_notif);
5af447e5
PP
1041 BT_LOGV("Added \"push packet end notification\" action: "
1042 "packet-addr=%p", packet);
3230ee6b
PP
1043 goto end;
1044
1045error:
1046 ret = -1;
1047
1048end:
1049 bt_put(packet_end_notif);
1050 return ret;
1051}
1052
1053static
1054void add_action_set_stream_state_is_ended(
1055 struct bt_notification_iterator *iterator,
1056 struct stream_state *stream_state)
1057{
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,
1062 },
1063 };
1064
1065 assert(stream_state);
1066 add_action(iterator, &action);
5af447e5
PP
1067 BT_LOGV("Added \"set stream state's ended\" action: "
1068 "stream-state-addr=%p", stream_state);
3230ee6b
PP
1069}
1070
1071static
1072void 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)
1076{
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),
1082 },
1083 };
1084
1085 assert(stream_state);
1086 add_action(iterator, &action);
5af447e5
PP
1087 BT_LOGV("Added \"set stream state's current packet\" action: "
1088 "stream-state-addr=%p, packet-addr=%p",
1089 stream_state, packet);
3230ee6b
PP
1090}
1091
2ec84d26
PP
1092static
1093void 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,
1098 uint64_t cur_count)
1099{
1100 struct action action = {
1101 .type = type,
1102 .payload.update_stream_state_discarded_elements = {
1103 .stream_state = stream_state,
1104 .cur_begin = bt_get(cur_begin),
1105 .cur_count = cur_count,
1106 },
1107 };
1108
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);
1121 }
1122}
1123
3230ee6b
PP
1124static
1125int ensure_stream_state_exists(struct bt_notification_iterator *iterator,
1126 struct bt_notification *stream_begin_notif,
1127 struct bt_ctf_stream *notif_stream,
2c212c05 1128 struct stream_state **_stream_state)
3230ee6b
PP
1129{
1130 int ret = 0;
2c212c05 1131 struct stream_state *stream_state = NULL;
3230ee6b
PP
1132
1133 if (!notif_stream) {
1134 /*
1135 * The notification does not reference any stream: no
1136 * need to get or create a stream state.
1137 */
1138 goto end;
1139 }
1140
2c212c05 1141 stream_state = g_hash_table_lookup(iterator->stream_states,
3230ee6b 1142 notif_stream);
2c212c05 1143 if (!stream_state) {
3230ee6b
PP
1144 /*
1145 * This iterator did not bump into this stream yet:
1146 * create a stream state and a "stream begin"
1147 * notification.
1148 */
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,
1154 },
1155 };
1156
2c212c05 1157 stream_state = create_stream_state(notif_stream);
3230ee6b 1158 if (!stream_state) {
5af447e5 1159 BT_LOGE_STR("Cannot create stream state.");
3230ee6b
PP
1160 goto error;
1161 }
1162
2c212c05 1163 action.payload.add_stream_state.stream_state = stream_state;
3230ee6b
PP
1164 add_action(iterator, &action);
1165
1166 if (stream_begin_notif) {
1167 add_action_push_notif(iterator, stream_begin_notif);
1168 } else {
1169 ret = add_action_push_notif_stream_begin(iterator,
1170 notif_stream);
1171 if (ret) {
5af447e5 1172 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
3230ee6b
PP
1173 goto error;
1174 }
1175 }
1176 }
3230ee6b
PP
1177 goto end;
1178
1179error:
2c212c05
MD
1180 destroy_stream_state(stream_state);
1181 stream_state = NULL;
3230ee6b
PP
1182 ret = -1;
1183
1184end:
2c212c05 1185 *_stream_state = stream_state;
3230ee6b
PP
1186 return ret;
1187}
1188
2ec84d26
PP
1189static
1190struct bt_ctf_field *get_struct_field_uint(struct bt_ctf_field *struct_field,
1191 const char *field_name)
1192{
1193 struct bt_ctf_field *field = NULL;
1194 struct bt_ctf_field_type *ft = NULL;
1195
1196 field = bt_ctf_field_structure_get_field_by_name(struct_field,
1197 field_name);
1198 if (!field) {
1199 BT_LOGV_STR("`%s` field does not exist.");
1200 goto end;
1201 }
1202
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)));
1208 BT_PUT(field);
1209 goto end;
1210 }
1211
1212 ft = bt_ctf_field_get_type(field);
1213 assert(ft);
1214
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);
1218 BT_PUT(field);
1219 goto end;
1220 }
1221
1222end:
1223 bt_put(ft);
1224 return field;
1225}
1226
1227static
1228uint64_t get_packet_context_events_discarded(struct bt_ctf_packet *packet)
1229{
1230 struct bt_ctf_field *packet_context = NULL;
1231 struct bt_ctf_field *field = NULL;
1232 uint64_t retval = -1ULL;
1233 int ret;
1234
1235 packet_context = bt_ctf_packet_get_context(packet);
1236 if (!packet_context) {
1237 goto end;
1238 }
1239
1240 field = get_struct_field_uint(packet_context, "events_discarded");
1241 if (!field) {
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);
1245 goto end;
1246 }
1247
1248 assert(bt_ctf_field_is_integer(field));
1249 ret = bt_ctf_field_unsigned_integer_get_value(field, &retval);
1250 if (ret) {
1251 BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
1252 "packet-addr=%p, field-addr=%p",
1253 packet, field);
1254 retval = -1ULL;
1255 goto end;
1256 }
1257
1258end:
1259 bt_put(packet_context);
1260 bt_put(field);
1261 return retval;
1262}
1263
1264static
126215b4 1265uint64_t get_packet_context_packet_seq_num(struct bt_ctf_packet *packet)
2ec84d26 1266{
126215b4 1267 struct bt_ctf_field *packet_context = NULL;
2ec84d26
PP
1268 struct bt_ctf_field *field = NULL;
1269 uint64_t retval = -1ULL;
1270 int ret;
1271
126215b4
MD
1272 packet_context = bt_ctf_packet_get_context(packet);
1273 if (!packet_context) {
2ec84d26
PP
1274 goto end;
1275 }
1276
126215b4 1277 field = get_struct_field_uint(packet_context, "packet_seq_num");
2ec84d26 1278 if (!field) {
126215b4
MD
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);
2ec84d26
PP
1282 goto end;
1283 }
1284
1285 assert(bt_ctf_field_is_integer(field));
1286 ret = bt_ctf_field_unsigned_integer_get_value(field, &retval);
1287 if (ret) {
126215b4 1288 BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
2ec84d26
PP
1289 "packet-addr=%p, field-addr=%p",
1290 packet, field);
1291 retval = -1ULL;
1292 goto end;
1293 }
1294
1295end:
126215b4 1296 bt_put(packet_context);
2ec84d26
PP
1297 bt_put(field);
1298 return retval;
1299}
1300
1301static
1302int 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)
1307{
1308 struct bt_notification *notif = NULL;
1309 uint64_t diff;
126215b4 1310 uint64_t prev_count, next_count;
2ec84d26
PP
1311 int ret = 0;
1312
126215b4 1313 next_count = get_packet_context_packet_seq_num(packet);
2ec84d26 1314 if (next_count == -1ULL) {
126215b4
MD
1315 /*
1316 * Stream does not have seqnum field, skip discarded
1317 * packets feature.
1318 */
2ec84d26
PP
1319 goto end;
1320 }
126215b4 1321 prev_count = stream_state->discarded_packets_state.cur_count;
2ec84d26 1322
126215b4
MD
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);
1330 goto end;
1331 }
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);
2ec84d26
PP
1338 goto end;
1339 }
1340
126215b4
MD
1341 diff = next_count - prev_count;
1342 if (diff > 1) {
1343 /*
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'.
1350 */
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);
1356 if (!notif) {
1357 BT_LOGE_STR("Cannot create discarded packets notification.");
1358 ret = -1;
1359 goto end;
1360 }
1361
1362 add_action_push_notif(iterator, notif);
1363 }
2ec84d26
PP
1364 }
1365
2ec84d26
PP
1366 add_action_update_stream_state_discarded_elements(iterator,
1367 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS,
1368 stream_state, ts_end, next_count);
1369
1370end:
1371 bt_put(notif);
1372 return ret;
1373}
1374
1375static
1376int 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)
1381{
1382 struct bt_notification *notif = NULL;
1383 uint64_t diff;
1384 uint64_t next_count;
1385 int ret = 0;
1386
1387 next_count = get_packet_context_events_discarded(packet);
1388 if (next_count == -1ULL) {
1389 next_count = stream_state->discarded_events_state.cur_count;
1390 goto update_state;
1391 }
1392
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,
1399 next_count);
1400 goto end;
1401 }
1402
1403 diff = next_count - stream_state->discarded_events_state.cur_count;
1404 if (diff > 0) {
1405 /*
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.
1409 */
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,
1414 ts_end, diff);
1415 if (!notif) {
1416 BT_LOGE_STR("Cannot create discarded events notification.");
1417 ret = -1;
1418 goto end;
1419 }
1420
1421 add_action_push_notif(iterator, notif);
1422 }
1423
1424update_state:
1425 add_action_update_stream_state_discarded_elements(iterator,
1426 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS,
1427 stream_state, ts_end, next_count);
1428
1429end:
1430 bt_put(notif);
1431 return ret;
1432}
1433
1434static
1435int get_field_clock_value(struct bt_ctf_field *root_field,
1436 const char *field_name,
1437 struct bt_ctf_clock_value **user_clock_val)
1438{
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;
1443 uint64_t val;
1444 int ret = 0;
1445
1446 field = get_struct_field_uint(root_field, field_name);
1447 if (!field) {
1448 /* Not an error: skip this */
1449 goto end;
1450 }
1451
1452 ft = bt_ctf_field_get_type(field);
1453 assert(ft);
1454 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(ft);
1455 if (!clock_class) {
1456 BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
1457 "ft-addr=%p", ft);
1458 ret = -1;
1459 goto end;
1460 }
1461
1462 ret = bt_ctf_field_unsigned_integer_get_value(field, &val);
1463 if (ret) {
1464 BT_LOGW("Cannot get integer field's raw value: "
1465 "field-addr=%p", field);
1466 ret = -1;
1467 goto end;
1468 }
1469
1470 clock_value = bt_ctf_clock_value_create(clock_class, val);
1471 if (!clock_value) {
1472 BT_LOGE_STR("Cannot create clock value from clock class.");
1473 ret = -1;
1474 goto end;
1475 }
1476
1477 /* Move clock value to user */
1478 *user_clock_val = clock_value;
1479 clock_value = NULL;
1480
1481end:
1482 bt_put(field);
1483 bt_put(ft);
1484 bt_put(clock_class);
1485 bt_put(clock_value);
1486 return ret;
1487}
1488
1489static
1490int 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)
1493{
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;
1497 int ret = 0;
1498
1499 packet_context = bt_ctf_packet_get_context(packet);
1500 if (!packet_context) {
1501 goto end;
1502 }
1503
1504 ret = get_field_clock_value(packet_context, "timestamp_begin",
1505 &ts_begin);
1506 if (ret) {
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);
1510 goto end;
1511 }
1512
1513 ret = get_field_clock_value(packet_context, "timestamp_end",
1514 &ts_end);
1515 if (ret) {
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);
1519 goto end;
1520 }
1521
1522 /* Move clock values to user */
1523 *user_ts_begin = ts_begin;
1524 ts_begin = NULL;
1525 *user_ts_end = ts_end;
1526 ts_end = NULL;
1527
1528end:
1529 bt_put(packet_context);
1530 bt_put(ts_begin);
1531 bt_put(ts_end);
1532 return ret;
1533}
1534
1535static
1536int handle_discarded_elements(struct bt_notification_iterator *iterator,
1537 struct bt_ctf_packet *packet, struct stream_state *stream_state)
1538{
1539 struct bt_ctf_clock_value *ts_begin = NULL;
1540 struct bt_ctf_clock_value *ts_end = NULL;
1541 int ret;
1542
1543 ret = get_ts_begin_ts_end_from_packet(packet, &ts_begin, &ts_end);
1544 if (ret) {
1545 BT_LOGW("Cannot get packet's beginning or end clock values: "
1546 "packet-addr=%p, ret=%d", packet, ret);
1547 ret = -1;
1548 goto end;
1549 }
1550
1551 ret = handle_discarded_packets(iterator, packet, ts_begin, ts_end,
1552 stream_state);
1553 if (ret) {
1554 BT_LOGW("Cannot handle discarded packets for packet: "
1555 "packet-addr=%p, ret=%d", packet, ret);
1556 ret = -1;
1557 goto end;
1558 }
1559
1560 ret = handle_discarded_events(iterator, packet, ts_begin, ts_end,
1561 stream_state);
1562 if (ret) {
1563 BT_LOGW("Cannot handle discarded events for packet: "
1564 "packet-addr=%p, ret=%d", packet, ret);
1565 ret = -1;
1566 goto end;
1567 }
1568
1569end:
1570 bt_put(ts_begin);
1571 bt_put(ts_end);
1572 return ret;
1573}
1574
3230ee6b
PP
1575static
1576int 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)
1580{
1581 int ret = 0;
1582
1583 if (stream_state->cur_packet == new_packet) {
1584 goto end;
1585 }
1586
5af447e5
PP
1587 BT_LOGV("Handling packet switch: "
1588 "cur-packet-addr=%p, new-packet-addr=%p",
1589 stream_state->cur_packet, new_packet);
1590
3230ee6b
PP
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);
1595 if (ret) {
5af447e5 1596 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
3230ee6b
PP
1597 goto error;
1598 }
1599 }
1600
2ec84d26 1601 /*
126215b4
MD
1602 * Check the new packet's context fields for discarded packets
1603 * and events to emit those automatic notifications.
2ec84d26
PP
1604 */
1605 ret = handle_discarded_elements(iterator, new_packet, stream_state);
1606 if (ret) {
1607 BT_LOGE_STR("Cannot handle discarded elements for new packet.");
1608 goto error;
1609 }
1610
3230ee6b
PP
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,
1616 new_packet);
1617 if (ret) {
5af447e5 1618 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
3230ee6b
PP
1619 goto error;
1620 }
1621 }
1622
1623 add_action_set_stream_state_cur_packet(iterator, stream_state,
1624 new_packet);
1625 goto end;
1626
1627error:
1628 ret = -1;
1629
1630end:
1631 return ret;
1632}
1633
1634static
1635int handle_notif_stream_begin(
1636 struct bt_notification_iterator *iterator,
1637 struct bt_notification *notif,
1638 struct bt_ctf_stream *notif_stream)
1639{
1640 int ret = 0;
1641 struct stream_state *stream_state;
1642
1643 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_BEGIN);
1644 assert(notif_stream);
1645 ret = ensure_stream_state_exists(iterator, notif, notif_stream,
1646 &stream_state);
1647 if (ret) {
5af447e5 1648 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1649 goto error;
1650 }
1651
1652 goto end;
1653
1654error:
1655 ret = -1;
1656
1657end:
1658 return ret;
1659}
1660
1661static
1662int handle_notif_stream_end(
1663 struct bt_notification_iterator *iterator,
1664 struct bt_notification *notif,
1665 struct bt_ctf_stream *notif_stream)
1666{
1667 int ret = 0;
1668 struct stream_state *stream_state;
1669
1670 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_END);
1671 assert(notif_stream);
1672 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1673 &stream_state);
1674 if (ret) {
5af447e5 1675 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1676 goto error;
1677 }
1678
1679 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1680 if (ret) {
5af447e5 1681 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1682 goto error;
1683 }
1684
1685 add_action_push_notif(iterator, notif);
1686 add_action_set_stream_state_is_ended(iterator, stream_state);
1687 goto end;
1688
1689error:
1690 ret = -1;
1691
1692end:
1693 return ret;
1694}
1695
2ec84d26
PP
1696static
1697int handle_notif_discarded_elements(
1698 struct bt_notification_iterator *iterator,
1699 struct bt_notification *notif,
1700 struct bt_ctf_stream *notif_stream)
1701{
1702 int ret = 0;
1703 struct stream_state *stream_state;
1704
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,
1709 &stream_state);
1710 if (ret) {
1711 BT_LOGE_STR("Cannot ensure that stream state exists.");
1712 goto error;
1713 }
1714
1715 add_action_push_notif(iterator, notif);
1716 goto end;
1717
1718error:
1719 ret = -1;
1720
1721end:
1722 return ret;
1723}
1724
3230ee6b
PP
1725static
1726int 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)
1731{
1732 int ret = 0;
1733 struct stream_state *stream_state;
1734
1735 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_BEGIN);
1736 assert(notif_packet);
1737 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1738 &stream_state);
1739 if (ret) {
5af447e5 1740 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1741 goto error;
1742 }
1743
1744 ret = handle_packet_switch(iterator, notif, notif_packet, stream_state);
1745 if (ret) {
5af447e5 1746 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1747 goto error;
1748 }
1749
1750 goto end;
1751
1752error:
1753 ret = -1;
1754
1755end:
1756 return ret;
1757}
1758
1759static
1760int 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)
1765{
1766 int ret = 0;
1767 struct stream_state *stream_state;
1768
1769 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_END);
1770 assert(notif_packet);
1771 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1772 &stream_state);
1773 if (ret) {
5af447e5 1774 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1775 goto error;
1776 }
1777
1778 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1779 if (ret) {
5af447e5 1780 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1781 goto error;
1782 }
1783
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);
1787 goto end;
1788
1789error:
1790 ret = -1;
1791
1792end:
1793 return ret;
1794}
1795
1796static
1797int 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)
1802{
1803 int ret = 0;
1804 struct stream_state *stream_state;
1805
1806 assert(notif->type == BT_NOTIFICATION_TYPE_EVENT);
1807 assert(notif_packet);
1808 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1809 &stream_state);
1810 if (ret) {
5af447e5 1811 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1812 goto error;
1813 }
1814
1815 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1816 if (ret) {
5af447e5 1817 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1818 goto error;
1819 }
1820
1821 add_action_push_notif(iterator, notif);
1822 goto end;
1823
1824error:
1825 ret = -1;
1826
1827end:
1828 return ret;
1829}
1830
1831static
1832int enqueue_notification_and_automatic(
1833 struct bt_notification_iterator *iterator,
1834 struct bt_notification *notif)
1835{
1836 int ret = 0;
1837 struct bt_ctf_event *notif_event = NULL;
1838 struct bt_ctf_stream *notif_stream = NULL;
1839 struct bt_ctf_packet *notif_packet = NULL;
1840
1841 assert(notif);
1842
5af447e5
PP
1843 BT_LOGV("Enqueuing user notification and automatic notifications: "
1844 "iter-addr=%p, notif-addr=%p", iterator, notif);
1845
fa054faf
PP
1846 // TODO: Skip most of this if the iterator is only subscribed
1847 // to event/inactivity notifications.
1848
3230ee6b
PP
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);
1856 break;
1857 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1858 notif_stream =
1859 bt_notification_stream_begin_borrow_stream(notif);
1860 assert(notif_stream);
1861 break;
1862 case BT_NOTIFICATION_TYPE_STREAM_END:
1863 notif_stream = bt_notification_stream_end_borrow_stream(notif);
1864 assert(notif_stream);
1865 break;
1866 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1867 notif_packet =
1868 bt_notification_packet_begin_borrow_packet(notif);
1869 assert(notif_packet);
1870 break;
1871 case BT_NOTIFICATION_TYPE_PACKET_END:
1872 notif_packet = bt_notification_packet_end_borrow_packet(notif);
1873 assert(notif_packet);
1874 break;
1875 case BT_NOTIFICATION_TYPE_INACTIVITY:
1876 /* Always valid */
7cdc2bab 1877 goto handle_notif;
3230ee6b
PP
1878 default:
1879 /*
1880 * Invalid type of notification. Only the notification
1881 * types above are allowed to be returned by a user
1882 * component.
1883 */
2ec84d26
PP
1884 BT_LOGF("Unexpected notification type at this point: "
1885 "notif-addr=%p, notif-type=%s", notif,
1886 bt_notification_type_string(notif->type));
1887 abort();
3230ee6b
PP
1888 }
1889
1890 if (notif_packet) {
1891 notif_stream = bt_ctf_packet_borrow_stream(notif_packet);
1892 assert(notif_stream);
1893 }
1894
1895 if (!notif_stream) {
1896 /*
1897 * The notification has no reference to a stream: it
1898 * cannot cause the creation of automatic notifications.
1899 */
5af447e5 1900 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
3230ee6b
PP
1901 goto end;
1902 }
1903
1904 if (!validate_notification(iterator, notif, notif_stream,
1905 notif_packet)) {
5af447e5 1906 BT_LOGW_STR("Invalid notification.");
3230ee6b
PP
1907 goto error;
1908 }
1909
7cdc2bab 1910handle_notif:
3230ee6b
PP
1911 switch (notif->type) {
1912 case BT_NOTIFICATION_TYPE_EVENT:
1913 ret = handle_notif_event(iterator, notif, notif_stream,
1914 notif_packet);
1915 break;
1916 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1917 ret = handle_notif_stream_begin(iterator, notif, notif_stream);
1918 break;
1919 case BT_NOTIFICATION_TYPE_STREAM_END:
1920 ret = handle_notif_stream_end(iterator, notif, notif_stream);
1921 break;
1922 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1923 ret = handle_notif_packet_begin(iterator, notif, notif_stream,
1924 notif_packet);
1925 break;
1926 case BT_NOTIFICATION_TYPE_PACKET_END:
1927 ret = handle_notif_packet_end(iterator, notif, notif_stream,
1928 notif_packet);
1929 break;
2ec84d26
PP
1930 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
1931 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
1932 ret = handle_notif_discarded_elements(iterator, notif,
1933 notif_stream);
1934 break;
7cdc2bab
MD
1935 case BT_NOTIFICATION_TYPE_INACTIVITY:
1936 add_action_push_notif(iterator, notif);
1937 break;
3230ee6b
PP
1938 default:
1939 break;
1940 }
1941
1942 if (ret) {
5af447e5 1943 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
3230ee6b
PP
1944 goto error;
1945 }
1946
1947 apply_actions(iterator);
5af447e5
PP
1948 BT_LOGV("Enqueued user notification and automatic notifications: "
1949 "iter-addr=%p, notif-addr=%p", iterator, notif);
3230ee6b
PP
1950 goto end;
1951
1952error:
1953 ret = -1;
1954
1955end:
1956 return ret;
1957}
1958
1959static
1960int handle_end(struct bt_notification_iterator *iterator)
1961{
1962 GHashTableIter stream_state_iter;
1963 gpointer stream_gptr, stream_state_gptr;
1964 int ret = 0;
1965
5af447e5
PP
1966 BT_LOGV("Handling end of iteration: addr=%p", iterator);
1967
3230ee6b
PP
1968 /*
1969 * Emit a "stream end" notification for each non-ended stream
1970 * known by this iterator and mark them as ended.
1971 */
1972 g_hash_table_iter_init(&stream_state_iter, iterator->stream_states);
1973
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;
1977
1978 assert(stream_state_gptr);
1979
1980 if (stream_state->is_ended) {
1981 continue;
1982 }
1983
1984 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1985 if (ret) {
5af447e5 1986 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1987 goto error;
1988 }
1989
1990 ret = add_action_push_notif_stream_end(iterator, stream_gptr);
1991 if (ret) {
5af447e5 1992 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
3230ee6b
PP
1993 goto error;
1994 }
1995
1996 add_action_set_stream_state_is_ended(iterator, stream_state);
1997 }
1998
1999 apply_actions(iterator);
5af447e5 2000 BT_LOGV("Handled end of iteration: addr=%p", iterator);
3230ee6b
PP
2001 goto end;
2002
2003error:
2004 ret = -1;
2005
2006end:
2007 return ret;
2008}
2009
2010static
2011enum bt_notification_iterator_status ensure_queue_has_notifications(
2012 struct bt_notification_iterator *iterator)
53d45b87 2013{
890882ef
PP
2014 struct bt_private_notification_iterator *priv_iterator =
2015 bt_private_notification_iterator_from_notification_iterator(iterator);
d3eb6e8f 2016 bt_component_class_notification_iterator_next_method next_method = NULL;
fe8ad2b6
PP
2017 struct bt_notification_iterator_next_return next_return = {
2018 .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
2019 .notification = NULL,
2020 };
3230ee6b
PP
2021 enum bt_notification_iterator_status status =
2022 BT_NOTIFICATION_ITERATOR_STATUS_OK;
2023 int ret;
41a2b7ae 2024
3230ee6b 2025 assert(iterator);
5af447e5 2026 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
8f9d7550
PP
2027 "iter-addr=%p, queue-size=%u, iter-state=%s",
2028 iterator, iterator->queue->length,
2029 bt_notification_iterator_state_string(iterator->state));
3230ee6b
PP
2030
2031 if (iterator->queue->length > 0) {
8f9d7550
PP
2032 /*
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.
2038 */
5af447e5 2039 BT_LOGD_STR("Queue already has at least one notification.");
3230ee6b
PP
2040 goto end;
2041 }
2042
bd14d768
PP
2043 switch (iterator->state) {
2044 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
8f9d7550 2045 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
5af447e5 2046 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
bd14d768
PP
2047 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
2048 goto end;
2049 case BT_NOTIFICATION_ITERATOR_STATE_ENDED:
5af447e5 2050 BT_LOGD_STR("Notification iterator is ended.");
3230ee6b 2051 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
41a2b7ae 2052 goto end;
bd14d768
PP
2053 default:
2054 break;
41a2b7ae 2055 }
d3eb6e8f 2056
3230ee6b
PP
2057 assert(iterator->upstream_component);
2058 assert(iterator->upstream_component->class);
d3eb6e8f 2059
3230ee6b
PP
2060 /* Pick the appropriate "next" method */
2061 switch (iterator->upstream_component->class->type) {
d3eb6e8f
PP
2062 case BT_COMPONENT_CLASS_TYPE_SOURCE:
2063 {
2064 struct bt_component_class_source *source_class =
3230ee6b 2065 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
2066 struct bt_component_class_source, parent);
2067
2068 assert(source_class->methods.iterator.next);
2069 next_method = source_class->methods.iterator.next;
2070 break;
2071 }
2072 case BT_COMPONENT_CLASS_TYPE_FILTER:
2073 {
2074 struct bt_component_class_filter *filter_class =
3230ee6b 2075 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
2076 struct bt_component_class_filter, parent);
2077
2078 assert(filter_class->methods.iterator.next);
2079 next_method = filter_class->methods.iterator.next;
2080 break;
2081 }
2082 default:
0fbb9a9f 2083 abort();
d3eb6e8f
PP
2084 }
2085
3230ee6b
PP
2086 /*
2087 * Call the user's "next" method to get the next notification
fa054faf 2088 * and status.
3230ee6b 2089 */
d3eb6e8f 2090 assert(next_method);
3230ee6b 2091
fa054faf 2092 while (iterator->queue->length == 0) {
5af447e5 2093 BT_LOGD_STR("Calling user's \"next\" method.");
fa054faf 2094 next_return = next_method(priv_iterator);
5af447e5
PP
2095 BT_LOGD("User method returned: status=%s",
2096 bt_notification_iterator_status_string(next_return.status));
fa054faf 2097 if (next_return.status < 0) {
5af447e5 2098 BT_LOGW_STR("User method failed.");
fa054faf 2099 status = next_return.status;
3230ee6b
PP
2100 goto end;
2101 }
2102
8cf27cc5
PP
2103 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
2104 iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED) {
2105 /*
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
2113 * finalized.
2114 *
2115 * Only bt_put() the returned notification if
2116 * the status is
2117 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
2118 * otherwise this field could be garbage.
2119 */
2120 if (next_return.status ==
2121 BT_NOTIFICATION_ITERATOR_STATUS_OK) {
2122 bt_put(next_return.notification);
2123 }
2124
2125 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
2126 goto end;
2127 }
2128
fa054faf
PP
2129 switch (next_return.status) {
2130 case BT_NOTIFICATION_ITERATOR_STATUS_END:
2131 ret = handle_end(iterator);
2132 if (ret) {
5af447e5 2133 BT_LOGW_STR("Cannot handle end of iteration.");
fa054faf
PP
2134 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2135 goto end;
2136 }
3230ee6b 2137
8f9d7550
PP
2138 assert(iterator->state ==
2139 BT_NOTIFICATION_ITERATOR_STATE_ACTIVE);
2140 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ENDED;
bd14d768 2141
8f9d7550
PP
2142 if (iterator->queue->length == 0) {
2143 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
bd14d768 2144 }
5af447e5
PP
2145
2146 BT_LOGD("Set new status: status=%s",
2147 bt_notification_iterator_status_string(status));
3230ee6b 2148 goto end;
fa054faf
PP
2149 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
2150 status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
2151 goto end;
2152 case BT_NOTIFICATION_ITERATOR_STATUS_OK:
2153 if (!next_return.notification) {
5af447e5 2154 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
fa054faf
PP
2155 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2156 goto end;
2157 }
2158
2ec84d26
PP
2159 /*
2160 * Ignore some notifications which are always
2161 * automatically generated by the notification
2162 * iterator to make sure they have valid values.
2163 */
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: "
2168 "notif-type=%s",
2169 bt_notification_type_string(next_return.notification->type));
2170 BT_PUT(next_return.notification);
2171 continue;
2172 default:
2173 break;
2174 }
2175
fa054faf
PP
2176 /*
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.
2180 */
2181 ret = enqueue_notification_and_automatic(iterator,
2182 next_return.notification);
2183 BT_PUT(next_return.notification);
2184 if (ret) {
5af447e5 2185 BT_LOGW("Cannot enqueue notification and automatic notifications.");
fa054faf
PP
2186 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2187 goto end;
2188 }
2189 break;
2190 default:
2191 /* Unknown non-error status */
0fbb9a9f 2192 abort();
3230ee6b 2193 }
41a2b7ae
PP
2194 }
2195
2196end:
3230ee6b
PP
2197 return status;
2198}
2199
2200enum bt_notification_iterator_status
2201bt_notification_iterator_next(struct bt_notification_iterator *iterator)
2202{
2203 enum bt_notification_iterator_status status;
2204
2205 if (!iterator) {
5af447e5 2206 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
3230ee6b
PP
2207 status = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
2208 goto end;
2209 }
2210
5af447e5
PP
2211 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator);
2212
3230ee6b
PP
2213 /*
2214 * Make sure that the iterator's queue contains at least one
2215 * notification.
2216 */
2217 status = ensure_queue_has_notifications(iterator);
2218 if (status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
5af447e5 2219 /* Not an error */
3230ee6b
PP
2220 goto end;
2221 }
2222
2223 /*
2224 * Move the notification at the tail of the queue to the
2225 * iterator's current notification.
2226 */
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);
2231
2232end:
2233 return status;
53d45b87
JG
2234}
2235
413bc2c4
JG
2236struct bt_component *bt_notification_iterator_get_component(
2237 struct bt_notification_iterator *iterator)
2238{
3230ee6b 2239 return bt_get(iterator->upstream_component);
413bc2c4
JG
2240}
2241
91457551
PP
2242struct bt_private_component *
2243bt_private_notification_iterator_get_private_component(
2244 struct bt_private_notification_iterator *private_iterator)
2245{
2246 return bt_private_component_from_component(
2247 bt_notification_iterator_get_component(
2248 bt_notification_iterator_from_private(private_iterator)));
2249}
2250
9531634f
JG
2251enum bt_notification_iterator_status bt_notification_iterator_seek_time(
2252 struct bt_notification_iterator *iterator,
2253 enum bt_notification_iterator_seek_origin seek_origin,
2254 int64_t time)
2255{
b7726e32
MD
2256 enum bt_notification_iterator_status ret =
2257 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED;
9531634f
JG
2258 return ret;
2259}
This page took 0.12981 seconds and 4 git commands to generate.