Remove notification iterator seeking API until it's supported
[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) {
088d4023
PP
448 case BT_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED:
449 /* Skip user finalization if user initialization failed */
450 BT_LOGD("Not finalizing non-initialized notification iterator: "
451 "addr=%p", iterator);
452 return;
bd14d768
PP
453 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
454 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
455 /* Already finalized */
5af447e5
PP
456 BT_LOGD("Not finalizing notification iterator: already finalized: "
457 "addr=%p", iterator);
bd14d768
PP
458 return;
459 default:
460 break;
461 }
462
5af447e5
PP
463 BT_LOGD("Finalizing notification iterator: addr=%p", iterator);
464
df14f8af 465 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_ENDED) {
5af447e5
PP
466 BT_LOGD("Updating notification iterator's state: "
467 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
df14f8af
MD
468 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
469 } else {
5af447e5
PP
470 BT_LOGD("Updating notification iterator's state: "
471 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
df14f8af
MD
472 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED;
473 }
474
bd14d768
PP
475 assert(iterator->upstream_component);
476 comp_class = iterator->upstream_component->class;
477
478 /* Call user-defined destroy method */
479 switch (comp_class->type) {
480 case BT_COMPONENT_CLASS_TYPE_SOURCE:
481 {
482 struct bt_component_class_source *source_class;
483
484 source_class = container_of(comp_class, struct bt_component_class_source, parent);
485 finalize_method = source_class->methods.iterator.finalize;
486 break;
487 }
488 case BT_COMPONENT_CLASS_TYPE_FILTER:
489 {
490 struct bt_component_class_filter *filter_class;
491
492 filter_class = container_of(comp_class, struct bt_component_class_filter, parent);
493 finalize_method = filter_class->methods.iterator.finalize;
494 break;
495 }
496 default:
497 /* Unreachable */
0fbb9a9f 498 abort();
bd14d768
PP
499 }
500
501 if (finalize_method) {
5af447e5
PP
502 BT_LOGD("Calling user's finalization method: addr=%p",
503 iterator);
bd14d768
PP
504 finalize_method(
505 bt_private_notification_iterator_from_notification_iterator(iterator));
506 }
507
bd14d768
PP
508 iterator->upstream_component = NULL;
509 iterator->upstream_port = NULL;
5af447e5 510 BT_LOGD("Finalized notification iterator: addr=%p", iterator);
bd14d768
PP
511}
512
513BT_HIDDEN
514void bt_notification_iterator_set_connection(
515 struct bt_notification_iterator *iterator,
516 struct bt_connection *connection)
517{
518 assert(iterator);
519 iterator->connection = connection;
5af447e5
PP
520 BT_LOGV("Set notification iterator's connection: "
521 "iter-addr=%p, conn-addr=%p", iterator, connection);
bd14d768
PP
522}
523
fa054faf
PP
524static
525int create_subscription_mask_from_notification_types(
526 struct bt_notification_iterator *iterator,
527 const enum bt_notification_type *notif_types)
528{
529 const enum bt_notification_type *notif_type;
530 int ret = 0;
531
532 assert(notif_types);
533 iterator->subscription_mask = 0;
534
535 for (notif_type = notif_types;
536 *notif_type != BT_NOTIFICATION_TYPE_SENTINEL;
537 notif_type++) {
538 switch (*notif_type) {
539 case BT_NOTIFICATION_TYPE_ALL:
540 iterator->subscription_mask |=
541 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT |
542 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY |
543 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN |
544 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END |
545 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN |
2ec84d26
PP
546 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END |
547 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS |
548 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
fa054faf
PP
549 break;
550 case BT_NOTIFICATION_TYPE_EVENT:
551 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
552 break;
553 case BT_NOTIFICATION_TYPE_INACTIVITY:
554 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
555 break;
556 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
557 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
558 break;
559 case BT_NOTIFICATION_TYPE_STREAM_END:
560 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
561 break;
562 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
563 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
564 break;
565 case BT_NOTIFICATION_TYPE_PACKET_END:
566 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
567 break;
2ec84d26
PP
568 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
569 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
570 break;
571 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
572 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
573 break;
fa054faf
PP
574 default:
575 ret = -1;
576 goto end;
577 }
5af447e5
PP
578
579 BT_LOGV("Added notification type to subscription mask: "
580 "type=%s, mask=%x",
581 bt_notification_type_string(*notif_type),
582 iterator->subscription_mask);
fa054faf
PP
583 }
584
585end:
586 return ret;
587}
588
47e5a032 589BT_HIDDEN
73d5c1ad 590enum bt_connection_status bt_notification_iterator_create(
3230ee6b 591 struct bt_component *upstream_comp,
fa054faf 592 struct bt_port *upstream_port,
bd14d768 593 const enum bt_notification_type *notification_types,
73d5c1ad
PP
594 struct bt_connection *connection,
595 struct bt_notification_iterator **user_iterator)
47e5a032 596{
73d5c1ad 597 enum bt_connection_status status = BT_CONNECTION_STATUS_OK;
d3e4dcd8 598 enum bt_component_class_type type;
47e5a032
JG
599 struct bt_notification_iterator *iterator = NULL;
600
3230ee6b
PP
601 assert(upstream_comp);
602 assert(upstream_port);
fa054faf 603 assert(notification_types);
3230ee6b 604 assert(bt_port_is_connected(upstream_port));
73d5c1ad 605 assert(user_iterator);
5af447e5
PP
606 BT_LOGD("Creating notification iterator: "
607 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
608 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
609 "conn-addr=%p",
610 upstream_comp, bt_component_get_name(upstream_comp),
611 upstream_port, bt_port_get_name(upstream_port),
612 connection);
3230ee6b 613 type = bt_component_get_class_type(upstream_comp);
ef2f7566
PP
614 assert(type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
615 type == BT_COMPONENT_CLASS_TYPE_FILTER);
47e5a032
JG
616 iterator = g_new0(struct bt_notification_iterator, 1);
617 if (!iterator) {
5af447e5 618 BT_LOGE_STR("Failed to allocate one notification iterator.");
73d5c1ad
PP
619 status = BT_CONNECTION_STATUS_NOMEM;
620 goto end;
47e5a032
JG
621 }
622
b8a06801 623 bt_object_init(iterator, bt_notification_iterator_destroy);
3230ee6b 624
fa054faf
PP
625 if (create_subscription_mask_from_notification_types(iterator,
626 notification_types)) {
5af447e5 627 BT_LOGW_STR("Cannot create subscription mask from notification types.");
73d5c1ad
PP
628 status = BT_CONNECTION_STATUS_INVALID;
629 goto end;
fa054faf
PP
630 }
631
3230ee6b
PP
632 iterator->stream_states = g_hash_table_new_full(g_direct_hash,
633 g_direct_equal, NULL, (GDestroyNotify) destroy_stream_state);
634 if (!iterator->stream_states) {
5af447e5 635 BT_LOGE_STR("Failed to allocate a GHashTable.");
73d5c1ad
PP
636 status = BT_CONNECTION_STATUS_NOMEM;
637 goto end;
3230ee6b
PP
638 }
639
640 iterator->queue = g_queue_new();
641 if (!iterator->queue) {
5af447e5 642 BT_LOGE_STR("Failed to allocate a GQueue.");
73d5c1ad
PP
643 status = BT_CONNECTION_STATUS_NOMEM;
644 goto end;
3230ee6b
PP
645 }
646
647 iterator->actions = g_array_new(FALSE, FALSE, sizeof(struct action));
648 if (!iterator->actions) {
5af447e5 649 BT_LOGE_STR("Failed to allocate a GArray.");
73d5c1ad
PP
650 status = BT_CONNECTION_STATUS_NOMEM;
651 goto end;
3230ee6b
PP
652 }
653
bd14d768
PP
654 iterator->upstream_component = upstream_comp;
655 iterator->upstream_port = upstream_port;
656 iterator->connection = connection;
088d4023 657 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED;
5af447e5
PP
658 BT_LOGD("Created notification iterator: "
659 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
660 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
661 "conn-addr=%p, iter-addr=%p",
662 upstream_comp, bt_component_get_name(upstream_comp),
663 upstream_port, bt_port_get_name(upstream_port),
664 connection, iterator);
1a6a376a
PP
665
666 /* Move reference to user */
667 *user_iterator = iterator;
668 iterator = NULL;
3230ee6b 669
47e5a032 670end:
73d5c1ad
PP
671 bt_put(iterator);
672 return status;
47e5a032
JG
673}
674
890882ef
PP
675void *bt_private_notification_iterator_get_user_data(
676 struct bt_private_notification_iterator *private_iterator)
ea8d3e58 677{
890882ef
PP
678 struct bt_notification_iterator *iterator =
679 bt_notification_iterator_from_private(private_iterator);
680
ea8d3e58
JG
681 return iterator ? iterator->user_data : NULL;
682}
683
684enum bt_notification_iterator_status
890882ef
PP
685bt_private_notification_iterator_set_user_data(
686 struct bt_private_notification_iterator *private_iterator,
687 void *data)
ea8d3e58
JG
688{
689 enum bt_notification_iterator_status ret =
690 BT_NOTIFICATION_ITERATOR_STATUS_OK;
890882ef
PP
691 struct bt_notification_iterator *iterator =
692 bt_notification_iterator_from_private(private_iterator);
ea8d3e58 693
d3eb6e8f 694 if (!iterator) {
5af447e5 695 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
fe8ad2b6 696 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
ea8d3e58
JG
697 goto end;
698 }
699
700 iterator->user_data = data;
5af447e5
PP
701 BT_LOGV("Set notification iterator's user data: "
702 "iter-addr=%p, user-data-addr=%p", iterator, data);
703
8738a040
JG
704end:
705 return ret;
706}
413bc2c4 707
53d45b87
JG
708struct bt_notification *bt_notification_iterator_get_notification(
709 struct bt_notification_iterator *iterator)
710{
41a2b7ae 711 struct bt_notification *notification = NULL;
d3eb6e8f 712
41a2b7ae 713 if (!iterator) {
5af447e5 714 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
41a2b7ae 715 goto end;
d3eb6e8f 716 }
d3eb6e8f 717
41a2b7ae 718 notification = bt_get(iterator->current_notification);
d3eb6e8f 719
41a2b7ae
PP
720end:
721 return notification;
53d45b87
JG
722}
723
fa054faf
PP
724static
725enum bt_notification_iterator_notif_type
726bt_notification_iterator_notif_type_from_notif_type(
727 enum bt_notification_type notif_type)
728{
729 enum bt_notification_iterator_notif_type iter_notif_type;
730
731 switch (notif_type) {
732 case BT_NOTIFICATION_TYPE_EVENT:
733 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
734 break;
735 case BT_NOTIFICATION_TYPE_INACTIVITY:
736 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
737 break;
738 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
739 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
740 break;
741 case BT_NOTIFICATION_TYPE_STREAM_END:
742 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
743 break;
744 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
745 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
746 break;
747 case BT_NOTIFICATION_TYPE_PACKET_END:
748 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
749 break;
2ec84d26
PP
750 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
751 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS;
752 break;
753 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
754 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS;
755 break;
fa054faf 756 default:
0fbb9a9f 757 abort();
fa054faf
PP
758 }
759
760 return iter_notif_type;
761}
762
3230ee6b 763static
c55a9f58 764bt_bool validate_notification(struct bt_notification_iterator *iterator,
3230ee6b
PP
765 struct bt_notification *notif,
766 struct bt_ctf_stream *notif_stream,
767 struct bt_ctf_packet *notif_packet)
768{
c55a9f58 769 bt_bool is_valid = BT_TRUE;
3230ee6b
PP
770 struct stream_state *stream_state;
771 struct bt_port *stream_comp_cur_port;
772
773 assert(notif_stream);
774 stream_comp_cur_port =
775 bt_ctf_stream_port_for_component(notif_stream,
776 iterator->upstream_component);
777 if (!stream_comp_cur_port) {
778 /*
779 * This is the first time this notification iterator
780 * bumps into this stream. Add an action to map the
781 * iterator's upstream component to the iterator's
782 * upstream port in this stream.
783 */
784 struct action action = {
785 .type = ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM,
786 .payload.map_port_to_comp_in_stream = {
787 .stream = bt_get(notif_stream),
788 .component = bt_get(iterator->upstream_component),
789 .port = bt_get(iterator->upstream_port),
790 },
791 };
792
793 add_action(iterator, &action);
794 } else {
795 if (stream_comp_cur_port != iterator->upstream_port) {
796 /*
797 * It looks like two different ports of the same
798 * component are emitting notifications which
799 * have references to the same stream. This is
800 * bad: the API guarantees that it can never
801 * happen.
802 */
5af447e5
PP
803 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
804 "stream-addr=%p, stream-name=\"%s\", "
805 "stream-comp-cur-port-addr=%p, "
806 "stream-comp-cur-port-name=%p, "
807 "iter-upstream-port-addr=%p, "
808 "iter-upstream-port-name=%s",
809 notif_stream,
810 bt_ctf_stream_get_name(notif_stream),
811 stream_comp_cur_port,
812 bt_port_get_name(stream_comp_cur_port),
813 iterator->upstream_port,
814 bt_port_get_name(iterator->upstream_port));
c55a9f58 815 is_valid = BT_FALSE;
3230ee6b
PP
816 goto end;
817 }
818
819 }
820
821 stream_state = g_hash_table_lookup(iterator->stream_states,
822 notif_stream);
823 if (stream_state) {
5af447e5
PP
824 BT_LOGV("Stream state already exists: "
825 "stream-addr=%p, stream-name=\"%s\", "
826 "stream-state-addr=%p",
827 notif_stream,
828 bt_ctf_stream_get_name(notif_stream), stream_state);
829
3230ee6b
PP
830 if (stream_state->is_ended) {
831 /*
832 * There's a new notification which has a
833 * reference to a stream which, from this
834 * iterator's point of view, is ended ("end of
835 * stream" notification was returned). This is
836 * bad: the API guarantees that it can never
837 * happen.
838 */
5af447e5
PP
839 BT_LOGW("Stream is already ended: "
840 "stream-addr=%p, stream-name=\"%s\"",
841 notif_stream,
842 bt_ctf_stream_get_name(notif_stream));
c55a9f58 843 is_valid = BT_FALSE;
3230ee6b
PP
844 goto end;
845 }
846
847 switch (notif->type) {
848 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
849 /*
850 * We already have a stream state, which means
851 * we already returned a "stream begin"
852 * notification: this is an invalid duplicate.
853 */
5af447e5
PP
854 BT_LOGW("Duplicate stream beginning notification: "
855 "stream-addr=%p, stream-name=\"%s\"",
856 notif_stream,
857 bt_ctf_stream_get_name(notif_stream));
c55a9f58 858 is_valid = BT_FALSE;
3230ee6b
PP
859 goto end;
860 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
861 if (notif_packet == stream_state->cur_packet) {
862 /* Duplicate "packet begin" notification */
5af447e5
PP
863 BT_LOGW("Duplicate stream beginning notification: "
864 "stream-addr=%p, stream-name=\"%s\", "
865 "packet-addr=%p",
866 notif_stream,
867 bt_ctf_stream_get_name(notif_stream),
868 notif_packet);
c55a9f58 869 is_valid = BT_FALSE;
3230ee6b
PP
870 goto end;
871 }
872 break;
873 default:
874 break;
875 }
876 }
877
878end:
879 return is_valid;
880}
881
fa054faf 882static
c55a9f58 883bt_bool is_subscribed_to_notification_type(struct bt_notification_iterator *iterator,
fa054faf
PP
884 enum bt_notification_type notif_type)
885{
886 uint32_t iter_notif_type =
887 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
888 notif_type);
889
c55a9f58 890 return (iter_notif_type & iterator->subscription_mask) ? BT_TRUE : BT_FALSE;
fa054faf
PP
891}
892
3230ee6b
PP
893static
894void add_action_push_notif(struct bt_notification_iterator *iterator,
895 struct bt_notification *notif)
896{
897 struct action action = {
898 .type = ACTION_TYPE_PUSH_NOTIF,
3230ee6b
PP
899 };
900
901 assert(notif);
fa054faf
PP
902
903 if (!is_subscribed_to_notification_type(iterator, notif->type)) {
904 return;
905 }
906
907 action.payload.push_notif.notif = bt_get(notif);
3230ee6b 908 add_action(iterator, &action);
5af447e5 909 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif);
3230ee6b
PP
910}
911
912static
913int add_action_push_notif_stream_begin(
914 struct bt_notification_iterator *iterator,
915 struct bt_ctf_stream *stream)
916{
917 int ret = 0;
918 struct bt_notification *stream_begin_notif = NULL;
919
fa054faf
PP
920 if (!is_subscribed_to_notification_type(iterator,
921 BT_NOTIFICATION_TYPE_STREAM_BEGIN)) {
5af447e5
PP
922 BT_LOGV("Not adding \"push stream beginning notification\" action: "
923 "notification iterator is not subscribed: addr=%p",
924 iterator);
fa054faf
PP
925 goto end;
926 }
927
3230ee6b
PP
928 assert(stream);
929 stream_begin_notif = bt_notification_stream_begin_create(stream);
930 if (!stream_begin_notif) {
5af447e5 931 BT_LOGE_STR("Cannot create stream beginning notification.");
3230ee6b
PP
932 goto error;
933 }
934
935 add_action_push_notif(iterator, stream_begin_notif);
5af447e5
PP
936 BT_LOGV("Added \"push stream beginning notification\" action: "
937 "stream-addr=%p, stream-name=\"%s\"",
938 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
939 goto end;
940
941error:
942 ret = -1;
943
944end:
945 bt_put(stream_begin_notif);
946 return ret;
947}
948
949static
950int add_action_push_notif_stream_end(
951 struct bt_notification_iterator *iterator,
952 struct bt_ctf_stream *stream)
953{
954 int ret = 0;
955 struct bt_notification *stream_end_notif = NULL;
956
fa054faf
PP
957 if (!is_subscribed_to_notification_type(iterator,
958 BT_NOTIFICATION_TYPE_STREAM_END)) {
5af447e5
PP
959 BT_LOGV("Not adding \"push stream end notification\" action: "
960 "notification iterator is not subscribed: addr=%p",
961 iterator);
fa054faf
PP
962 goto end;
963 }
964
3230ee6b
PP
965 assert(stream);
966 stream_end_notif = bt_notification_stream_end_create(stream);
967 if (!stream_end_notif) {
5af447e5 968 BT_LOGE_STR("Cannot create stream end notification.");
3230ee6b
PP
969 goto error;
970 }
971
972 add_action_push_notif(iterator, stream_end_notif);
5af447e5
PP
973 BT_LOGV("Added \"push stream end notification\" action: "
974 "stream-addr=%p, stream-name=\"%s\"",
975 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
976 goto end;
977
978error:
979 ret = -1;
980
981end:
982 bt_put(stream_end_notif);
983 return ret;
984}
985
986static
987int add_action_push_notif_packet_begin(
988 struct bt_notification_iterator *iterator,
989 struct bt_ctf_packet *packet)
990{
991 int ret = 0;
992 struct bt_notification *packet_begin_notif = NULL;
993
fa054faf
PP
994 if (!is_subscribed_to_notification_type(iterator,
995 BT_NOTIFICATION_TYPE_PACKET_BEGIN)) {
5af447e5
PP
996 BT_LOGV("Not adding \"push packet beginning notification\" action: "
997 "notification iterator is not subscribed: addr=%p",
998 iterator);
fa054faf
PP
999 goto end;
1000 }
1001
3230ee6b
PP
1002 assert(packet);
1003 packet_begin_notif = bt_notification_packet_begin_create(packet);
1004 if (!packet_begin_notif) {
5af447e5 1005 BT_LOGE_STR("Cannot create packet beginning notification.");
3230ee6b
PP
1006 goto error;
1007 }
1008
1009 add_action_push_notif(iterator, packet_begin_notif);
5af447e5
PP
1010 BT_LOGV("Added \"push packet beginning notification\" action: "
1011 "packet-addr=%p", packet);
3230ee6b
PP
1012 goto end;
1013
1014error:
1015 ret = -1;
1016
1017end:
1018 bt_put(packet_begin_notif);
1019 return ret;
1020}
1021
1022static
1023int add_action_push_notif_packet_end(
1024 struct bt_notification_iterator *iterator,
1025 struct bt_ctf_packet *packet)
1026{
1027 int ret = 0;
1028 struct bt_notification *packet_end_notif = NULL;
1029
fa054faf
PP
1030 if (!is_subscribed_to_notification_type(iterator,
1031 BT_NOTIFICATION_TYPE_PACKET_END)) {
5af447e5
PP
1032 BT_LOGV("Not adding \"push packet end notification\" action: "
1033 "notification iterator is not subscribed: addr=%p",
1034 iterator);
fa054faf
PP
1035 goto end;
1036 }
1037
3230ee6b
PP
1038 assert(packet);
1039 packet_end_notif = bt_notification_packet_end_create(packet);
1040 if (!packet_end_notif) {
5af447e5 1041 BT_LOGE_STR("Cannot create packet end notification.");
3230ee6b
PP
1042 goto error;
1043 }
1044
1045 add_action_push_notif(iterator, packet_end_notif);
5af447e5
PP
1046 BT_LOGV("Added \"push packet end notification\" action: "
1047 "packet-addr=%p", packet);
3230ee6b
PP
1048 goto end;
1049
1050error:
1051 ret = -1;
1052
1053end:
1054 bt_put(packet_end_notif);
1055 return ret;
1056}
1057
1058static
1059void add_action_set_stream_state_is_ended(
1060 struct bt_notification_iterator *iterator,
1061 struct stream_state *stream_state)
1062{
1063 struct action action = {
1064 .type = ACTION_TYPE_SET_STREAM_STATE_IS_ENDED,
1065 .payload.set_stream_state_is_ended = {
1066 .stream_state = stream_state,
1067 },
1068 };
1069
1070 assert(stream_state);
1071 add_action(iterator, &action);
5af447e5
PP
1072 BT_LOGV("Added \"set stream state's ended\" action: "
1073 "stream-state-addr=%p", stream_state);
3230ee6b
PP
1074}
1075
1076static
1077void add_action_set_stream_state_cur_packet(
1078 struct bt_notification_iterator *iterator,
1079 struct stream_state *stream_state,
1080 struct bt_ctf_packet *packet)
1081{
1082 struct action action = {
1083 .type = ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET,
1084 .payload.set_stream_state_cur_packet = {
1085 .stream_state = stream_state,
1086 .packet = bt_get(packet),
1087 },
1088 };
1089
1090 assert(stream_state);
1091 add_action(iterator, &action);
5af447e5
PP
1092 BT_LOGV("Added \"set stream state's current packet\" action: "
1093 "stream-state-addr=%p, packet-addr=%p",
1094 stream_state, packet);
3230ee6b
PP
1095}
1096
2ec84d26
PP
1097static
1098void add_action_update_stream_state_discarded_elements(
1099 struct bt_notification_iterator *iterator,
1100 enum action_type type,
1101 struct stream_state *stream_state,
1102 struct bt_ctf_clock_value *cur_begin,
1103 uint64_t cur_count)
1104{
1105 struct action action = {
1106 .type = type,
1107 .payload.update_stream_state_discarded_elements = {
1108 .stream_state = stream_state,
1109 .cur_begin = bt_get(cur_begin),
1110 .cur_count = cur_count,
1111 },
1112 };
1113
1114 assert(stream_state);
1115 assert(type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS ||
1116 type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS);
1117 add_action(iterator, &action);
1118 if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS) {
1119 BT_LOGV("Added \"update stream state's discarded packets\" action: "
1120 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64,
1121 stream_state, cur_begin, cur_count);
1122 } else if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS) {
1123 BT_LOGV("Added \"update stream state's discarded events\" action: "
1124 "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64,
1125 stream_state, cur_begin, cur_count);
1126 }
1127}
1128
3230ee6b
PP
1129static
1130int ensure_stream_state_exists(struct bt_notification_iterator *iterator,
1131 struct bt_notification *stream_begin_notif,
1132 struct bt_ctf_stream *notif_stream,
2c212c05 1133 struct stream_state **_stream_state)
3230ee6b
PP
1134{
1135 int ret = 0;
2c212c05 1136 struct stream_state *stream_state = NULL;
3230ee6b
PP
1137
1138 if (!notif_stream) {
1139 /*
1140 * The notification does not reference any stream: no
1141 * need to get or create a stream state.
1142 */
1143 goto end;
1144 }
1145
2c212c05 1146 stream_state = g_hash_table_lookup(iterator->stream_states,
3230ee6b 1147 notif_stream);
2c212c05 1148 if (!stream_state) {
3230ee6b
PP
1149 /*
1150 * This iterator did not bump into this stream yet:
1151 * create a stream state and a "stream begin"
1152 * notification.
1153 */
1154 struct action action = {
1155 .type = ACTION_TYPE_ADD_STREAM_STATE,
1156 .payload.add_stream_state = {
1157 .stream = bt_get(notif_stream),
1158 .stream_state = NULL,
1159 },
1160 };
1161
2c212c05 1162 stream_state = create_stream_state(notif_stream);
3230ee6b 1163 if (!stream_state) {
5af447e5 1164 BT_LOGE_STR("Cannot create stream state.");
3230ee6b
PP
1165 goto error;
1166 }
1167
2c212c05 1168 action.payload.add_stream_state.stream_state = stream_state;
3230ee6b
PP
1169 add_action(iterator, &action);
1170
1171 if (stream_begin_notif) {
1172 add_action_push_notif(iterator, stream_begin_notif);
1173 } else {
1174 ret = add_action_push_notif_stream_begin(iterator,
1175 notif_stream);
1176 if (ret) {
5af447e5 1177 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
3230ee6b
PP
1178 goto error;
1179 }
1180 }
1181 }
3230ee6b
PP
1182 goto end;
1183
1184error:
2c212c05
MD
1185 destroy_stream_state(stream_state);
1186 stream_state = NULL;
3230ee6b
PP
1187 ret = -1;
1188
1189end:
2c212c05 1190 *_stream_state = stream_state;
3230ee6b
PP
1191 return ret;
1192}
1193
2ec84d26
PP
1194static
1195struct bt_ctf_field *get_struct_field_uint(struct bt_ctf_field *struct_field,
1196 const char *field_name)
1197{
1198 struct bt_ctf_field *field = NULL;
1199 struct bt_ctf_field_type *ft = NULL;
1200
1201 field = bt_ctf_field_structure_get_field_by_name(struct_field,
1202 field_name);
1203 if (!field) {
1204 BT_LOGV_STR("`%s` field does not exist.");
1205 goto end;
1206 }
1207
1208 if (!bt_ctf_field_is_integer(field)) {
1209 BT_LOGV("Skipping `%s` field because its type is not an integer field type: "
1210 "field-addr=%p, ft-addr=%p, ft-id=%s", field_name,
1211 field, ft, bt_ctf_field_type_id_string(
1212 bt_ctf_field_type_get_type_id(ft)));
1213 BT_PUT(field);
1214 goto end;
1215 }
1216
1217 ft = bt_ctf_field_get_type(field);
1218 assert(ft);
1219
1220 if (bt_ctf_field_type_integer_is_signed(ft)) {
1221 BT_LOGV("Skipping `%s` integer field because its type is signed: "
1222 "field-addr=%p, ft-addr=%p", field_name, field, ft);
1223 BT_PUT(field);
1224 goto end;
1225 }
1226
1227end:
1228 bt_put(ft);
1229 return field;
1230}
1231
1232static
1233uint64_t get_packet_context_events_discarded(struct bt_ctf_packet *packet)
1234{
1235 struct bt_ctf_field *packet_context = NULL;
1236 struct bt_ctf_field *field = NULL;
1237 uint64_t retval = -1ULL;
1238 int ret;
1239
1240 packet_context = bt_ctf_packet_get_context(packet);
1241 if (!packet_context) {
1242 goto end;
1243 }
1244
1245 field = get_struct_field_uint(packet_context, "events_discarded");
1246 if (!field) {
1247 BT_LOGV("`events_discarded` field does not exist in packet's context field: "
1248 "packet-addr=%p, packet-context-field-addr=%p",
1249 packet, packet_context);
1250 goto end;
1251 }
1252
1253 assert(bt_ctf_field_is_integer(field));
1254 ret = bt_ctf_field_unsigned_integer_get_value(field, &retval);
1255 if (ret) {
1256 BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: "
1257 "packet-addr=%p, field-addr=%p",
1258 packet, field);
1259 retval = -1ULL;
1260 goto end;
1261 }
1262
1263end:
1264 bt_put(packet_context);
1265 bt_put(field);
1266 return retval;
1267}
1268
1269static
126215b4 1270uint64_t get_packet_context_packet_seq_num(struct bt_ctf_packet *packet)
2ec84d26 1271{
126215b4 1272 struct bt_ctf_field *packet_context = NULL;
2ec84d26
PP
1273 struct bt_ctf_field *field = NULL;
1274 uint64_t retval = -1ULL;
1275 int ret;
1276
126215b4
MD
1277 packet_context = bt_ctf_packet_get_context(packet);
1278 if (!packet_context) {
2ec84d26
PP
1279 goto end;
1280 }
1281
126215b4 1282 field = get_struct_field_uint(packet_context, "packet_seq_num");
2ec84d26 1283 if (!field) {
126215b4
MD
1284 BT_LOGV("`packet_seq_num` field does not exist in packet's context field: "
1285 "packet-addr=%p, packet-context-field-addr=%p",
1286 packet, packet_context);
2ec84d26
PP
1287 goto end;
1288 }
1289
1290 assert(bt_ctf_field_is_integer(field));
1291 ret = bt_ctf_field_unsigned_integer_get_value(field, &retval);
1292 if (ret) {
126215b4 1293 BT_LOGV("Cannot get raw value of packet's context field's `packet_seq_num` integer field: "
2ec84d26
PP
1294 "packet-addr=%p, field-addr=%p",
1295 packet, field);
1296 retval = -1ULL;
1297 goto end;
1298 }
1299
1300end:
126215b4 1301 bt_put(packet_context);
2ec84d26
PP
1302 bt_put(field);
1303 return retval;
1304}
1305
1306static
1307int handle_discarded_packets(struct bt_notification_iterator *iterator,
1308 struct bt_ctf_packet *packet,
1309 struct bt_ctf_clock_value *ts_begin,
1310 struct bt_ctf_clock_value *ts_end,
1311 struct stream_state *stream_state)
1312{
1313 struct bt_notification *notif = NULL;
1314 uint64_t diff;
126215b4 1315 uint64_t prev_count, next_count;
2ec84d26
PP
1316 int ret = 0;
1317
126215b4 1318 next_count = get_packet_context_packet_seq_num(packet);
2ec84d26 1319 if (next_count == -1ULL) {
126215b4
MD
1320 /*
1321 * Stream does not have seqnum field, skip discarded
1322 * packets feature.
1323 */
2ec84d26
PP
1324 goto end;
1325 }
126215b4 1326 prev_count = stream_state->discarded_packets_state.cur_count;
2ec84d26 1327
126215b4
MD
1328 if (prev_count != -1ULL) {
1329 if (next_count < prev_count) {
1330 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is lesser than the previous value for the same stream: "
1331 "not updating the stream state's current value: "
1332 "packet-addr=%p, prev-count=%" PRIu64 ", "
1333 "cur-count=%" PRIu64,
1334 packet, prev_count, next_count);
1335 goto end;
1336 }
1337 if (next_count == prev_count) {
1338 BT_LOGW("Current value of packet's context field's `packet_seq_num` field is equal to the previous value for the same stream: "
1339 "not updating the stream state's current value: "
1340 "packet-addr=%p, prev-count=%" PRIu64 ", "
1341 "cur-count=%" PRIu64,
1342 packet, prev_count, next_count);
2ec84d26
PP
1343 goto end;
1344 }
1345
126215b4
MD
1346 diff = next_count - prev_count;
1347 if (diff > 1) {
1348 /*
1349 * Add a discarded packets notification. The packets
1350 * are considered to be lost between the state's last time
1351 * and the current packet's beginning time.
1352 * The counter is expected to monotonically increase of
1353 * 1 for each packet. Therefore, the number of missing
1354 * packets is 'diff - 1'.
1355 */
1356 notif = bt_notification_discarded_elements_create(
1357 BT_NOTIFICATION_TYPE_DISCARDED_PACKETS,
1358 stream_state->stream,
1359 stream_state->discarded_packets_state.cur_begin,
1360 ts_begin, diff - 1);
1361 if (!notif) {
1362 BT_LOGE_STR("Cannot create discarded packets notification.");
1363 ret = -1;
1364 goto end;
1365 }
1366
1367 add_action_push_notif(iterator, notif);
1368 }
2ec84d26
PP
1369 }
1370
2ec84d26
PP
1371 add_action_update_stream_state_discarded_elements(iterator,
1372 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS,
1373 stream_state, ts_end, next_count);
1374
1375end:
1376 bt_put(notif);
1377 return ret;
1378}
1379
1380static
1381int handle_discarded_events(struct bt_notification_iterator *iterator,
1382 struct bt_ctf_packet *packet,
1383 struct bt_ctf_clock_value *ts_begin,
1384 struct bt_ctf_clock_value *ts_end,
1385 struct stream_state *stream_state)
1386{
1387 struct bt_notification *notif = NULL;
1388 uint64_t diff;
1389 uint64_t next_count;
1390 int ret = 0;
1391
1392 next_count = get_packet_context_events_discarded(packet);
1393 if (next_count == -1ULL) {
1394 next_count = stream_state->discarded_events_state.cur_count;
1395 goto update_state;
1396 }
1397
1398 if (next_count < stream_state->discarded_events_state.cur_count) {
1399 BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: "
1400 "not updating the stream state's current value: "
1401 "packet-addr=%p, prev-count=%" PRIu64 ", "
1402 "cur-count=%" PRIu64,
1403 packet, stream_state->discarded_events_state.cur_count,
1404 next_count);
1405 goto end;
1406 }
1407
1408 diff = next_count - stream_state->discarded_events_state.cur_count;
1409 if (diff > 0) {
1410 /*
1411 * Add a discarded events notification. The events are
1412 * considered to be lost betweem the state's last time
1413 * and the current packet's end time.
1414 */
1415 notif = bt_notification_discarded_elements_create(
1416 BT_NOTIFICATION_TYPE_DISCARDED_EVENTS,
1417 stream_state->stream,
1418 stream_state->discarded_events_state.cur_begin,
1419 ts_end, diff);
1420 if (!notif) {
1421 BT_LOGE_STR("Cannot create discarded events notification.");
1422 ret = -1;
1423 goto end;
1424 }
1425
1426 add_action_push_notif(iterator, notif);
1427 }
1428
1429update_state:
1430 add_action_update_stream_state_discarded_elements(iterator,
1431 ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS,
1432 stream_state, ts_end, next_count);
1433
1434end:
1435 bt_put(notif);
1436 return ret;
1437}
1438
1439static
1440int get_field_clock_value(struct bt_ctf_field *root_field,
1441 const char *field_name,
1442 struct bt_ctf_clock_value **user_clock_val)
1443{
1444 struct bt_ctf_field *field;
1445 struct bt_ctf_field_type *ft = NULL;
1446 struct bt_ctf_clock_class *clock_class = NULL;
1447 struct bt_ctf_clock_value *clock_value = NULL;
1448 uint64_t val;
1449 int ret = 0;
1450
1451 field = get_struct_field_uint(root_field, field_name);
1452 if (!field) {
1453 /* Not an error: skip this */
1454 goto end;
1455 }
1456
1457 ft = bt_ctf_field_get_type(field);
1458 assert(ft);
1459 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(ft);
1460 if (!clock_class) {
1461 BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: "
1462 "ft-addr=%p", ft);
1463 ret = -1;
1464 goto end;
1465 }
1466
1467 ret = bt_ctf_field_unsigned_integer_get_value(field, &val);
1468 if (ret) {
1469 BT_LOGW("Cannot get integer field's raw value: "
1470 "field-addr=%p", field);
1471 ret = -1;
1472 goto end;
1473 }
1474
1475 clock_value = bt_ctf_clock_value_create(clock_class, val);
1476 if (!clock_value) {
1477 BT_LOGE_STR("Cannot create clock value from clock class.");
1478 ret = -1;
1479 goto end;
1480 }
1481
1482 /* Move clock value to user */
1483 *user_clock_val = clock_value;
1484 clock_value = NULL;
1485
1486end:
1487 bt_put(field);
1488 bt_put(ft);
1489 bt_put(clock_class);
1490 bt_put(clock_value);
1491 return ret;
1492}
1493
1494static
1495int get_ts_begin_ts_end_from_packet(struct bt_ctf_packet *packet,
1496 struct bt_ctf_clock_value **user_ts_begin,
1497 struct bt_ctf_clock_value **user_ts_end)
1498{
1499 struct bt_ctf_field *packet_context = NULL;
1500 struct bt_ctf_clock_value *ts_begin = NULL;
1501 struct bt_ctf_clock_value *ts_end = NULL;
1502 int ret = 0;
1503
1504 packet_context = bt_ctf_packet_get_context(packet);
1505 if (!packet_context) {
1506 goto end;
1507 }
1508
1509 ret = get_field_clock_value(packet_context, "timestamp_begin",
1510 &ts_begin);
1511 if (ret) {
1512 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1513 "packet-addr=%p, packet-context-field-addr=%p",
1514 packet, packet_context);
1515 goto end;
1516 }
1517
1518 ret = get_field_clock_value(packet_context, "timestamp_end",
1519 &ts_end);
1520 if (ret) {
1521 BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: "
1522 "packet-addr=%p, packet-context-field-addr=%p",
1523 packet, packet_context);
1524 goto end;
1525 }
1526
1527 /* Move clock values to user */
1528 *user_ts_begin = ts_begin;
1529 ts_begin = NULL;
1530 *user_ts_end = ts_end;
1531 ts_end = NULL;
1532
1533end:
1534 bt_put(packet_context);
1535 bt_put(ts_begin);
1536 bt_put(ts_end);
1537 return ret;
1538}
1539
1540static
1541int handle_discarded_elements(struct bt_notification_iterator *iterator,
1542 struct bt_ctf_packet *packet, struct stream_state *stream_state)
1543{
1544 struct bt_ctf_clock_value *ts_begin = NULL;
1545 struct bt_ctf_clock_value *ts_end = NULL;
1546 int ret;
1547
1548 ret = get_ts_begin_ts_end_from_packet(packet, &ts_begin, &ts_end);
1549 if (ret) {
1550 BT_LOGW("Cannot get packet's beginning or end clock values: "
1551 "packet-addr=%p, ret=%d", packet, ret);
1552 ret = -1;
1553 goto end;
1554 }
1555
1556 ret = handle_discarded_packets(iterator, packet, ts_begin, ts_end,
1557 stream_state);
1558 if (ret) {
1559 BT_LOGW("Cannot handle discarded packets for packet: "
1560 "packet-addr=%p, ret=%d", packet, ret);
1561 ret = -1;
1562 goto end;
1563 }
1564
1565 ret = handle_discarded_events(iterator, packet, ts_begin, ts_end,
1566 stream_state);
1567 if (ret) {
1568 BT_LOGW("Cannot handle discarded events for packet: "
1569 "packet-addr=%p, ret=%d", packet, ret);
1570 ret = -1;
1571 goto end;
1572 }
1573
1574end:
1575 bt_put(ts_begin);
1576 bt_put(ts_end);
1577 return ret;
1578}
1579
3230ee6b
PP
1580static
1581int handle_packet_switch(struct bt_notification_iterator *iterator,
1582 struct bt_notification *packet_begin_notif,
1583 struct bt_ctf_packet *new_packet,
1584 struct stream_state *stream_state)
1585{
1586 int ret = 0;
1587
1588 if (stream_state->cur_packet == new_packet) {
1589 goto end;
1590 }
1591
5af447e5
PP
1592 BT_LOGV("Handling packet switch: "
1593 "cur-packet-addr=%p, new-packet-addr=%p",
1594 stream_state->cur_packet, new_packet);
1595
3230ee6b
PP
1596 if (stream_state->cur_packet) {
1597 /* End of the current packet */
1598 ret = add_action_push_notif_packet_end(iterator,
1599 stream_state->cur_packet);
1600 if (ret) {
5af447e5 1601 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
3230ee6b
PP
1602 goto error;
1603 }
1604 }
1605
2ec84d26 1606 /*
126215b4
MD
1607 * Check the new packet's context fields for discarded packets
1608 * and events to emit those automatic notifications.
2ec84d26
PP
1609 */
1610 ret = handle_discarded_elements(iterator, new_packet, stream_state);
1611 if (ret) {
1612 BT_LOGE_STR("Cannot handle discarded elements for new packet.");
1613 goto error;
1614 }
1615
3230ee6b
PP
1616 /* Beginning of the new packet */
1617 if (packet_begin_notif) {
1618 add_action_push_notif(iterator, packet_begin_notif);
1619 } else if (new_packet) {
1620 ret = add_action_push_notif_packet_begin(iterator,
1621 new_packet);
1622 if (ret) {
5af447e5 1623 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
3230ee6b
PP
1624 goto error;
1625 }
1626 }
1627
1628 add_action_set_stream_state_cur_packet(iterator, stream_state,
1629 new_packet);
1630 goto end;
1631
1632error:
1633 ret = -1;
1634
1635end:
1636 return ret;
1637}
1638
1639static
1640int handle_notif_stream_begin(
1641 struct bt_notification_iterator *iterator,
1642 struct bt_notification *notif,
1643 struct bt_ctf_stream *notif_stream)
1644{
1645 int ret = 0;
1646 struct stream_state *stream_state;
1647
1648 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_BEGIN);
1649 assert(notif_stream);
1650 ret = ensure_stream_state_exists(iterator, notif, notif_stream,
1651 &stream_state);
1652 if (ret) {
5af447e5 1653 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1654 goto error;
1655 }
1656
1657 goto end;
1658
1659error:
1660 ret = -1;
1661
1662end:
1663 return ret;
1664}
1665
1666static
1667int handle_notif_stream_end(
1668 struct bt_notification_iterator *iterator,
1669 struct bt_notification *notif,
1670 struct bt_ctf_stream *notif_stream)
1671{
1672 int ret = 0;
1673 struct stream_state *stream_state;
1674
1675 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_END);
1676 assert(notif_stream);
1677 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1678 &stream_state);
1679 if (ret) {
5af447e5 1680 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1681 goto error;
1682 }
1683
1684 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1685 if (ret) {
5af447e5 1686 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1687 goto error;
1688 }
1689
1690 add_action_push_notif(iterator, notif);
1691 add_action_set_stream_state_is_ended(iterator, stream_state);
1692 goto end;
1693
1694error:
1695 ret = -1;
1696
1697end:
1698 return ret;
1699}
1700
2ec84d26
PP
1701static
1702int handle_notif_discarded_elements(
1703 struct bt_notification_iterator *iterator,
1704 struct bt_notification *notif,
1705 struct bt_ctf_stream *notif_stream)
1706{
1707 int ret = 0;
1708 struct stream_state *stream_state;
1709
1710 assert(notif->type == BT_NOTIFICATION_TYPE_DISCARDED_EVENTS ||
1711 notif->type == BT_NOTIFICATION_TYPE_DISCARDED_PACKETS);
1712 assert(notif_stream);
1713 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1714 &stream_state);
1715 if (ret) {
1716 BT_LOGE_STR("Cannot ensure that stream state exists.");
1717 goto error;
1718 }
1719
1720 add_action_push_notif(iterator, notif);
1721 goto end;
1722
1723error:
1724 ret = -1;
1725
1726end:
1727 return ret;
1728}
1729
3230ee6b
PP
1730static
1731int handle_notif_packet_begin(
1732 struct bt_notification_iterator *iterator,
1733 struct bt_notification *notif,
1734 struct bt_ctf_stream *notif_stream,
1735 struct bt_ctf_packet *notif_packet)
1736{
1737 int ret = 0;
1738 struct stream_state *stream_state;
1739
1740 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_BEGIN);
1741 assert(notif_packet);
1742 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1743 &stream_state);
1744 if (ret) {
5af447e5 1745 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1746 goto error;
1747 }
1748
1749 ret = handle_packet_switch(iterator, notif, notif_packet, stream_state);
1750 if (ret) {
5af447e5 1751 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1752 goto error;
1753 }
1754
1755 goto end;
1756
1757error:
1758 ret = -1;
1759
1760end:
1761 return ret;
1762}
1763
1764static
1765int handle_notif_packet_end(
1766 struct bt_notification_iterator *iterator,
1767 struct bt_notification *notif,
1768 struct bt_ctf_stream *notif_stream,
1769 struct bt_ctf_packet *notif_packet)
1770{
1771 int ret = 0;
1772 struct stream_state *stream_state;
1773
1774 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_END);
1775 assert(notif_packet);
1776 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1777 &stream_state);
1778 if (ret) {
5af447e5 1779 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1780 goto error;
1781 }
1782
1783 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1784 if (ret) {
5af447e5 1785 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1786 goto error;
1787 }
1788
1789 /* End of the current packet */
1790 add_action_push_notif(iterator, notif);
1791 add_action_set_stream_state_cur_packet(iterator, stream_state, NULL);
1792 goto end;
1793
1794error:
1795 ret = -1;
1796
1797end:
1798 return ret;
1799}
1800
1801static
1802int handle_notif_event(
1803 struct bt_notification_iterator *iterator,
1804 struct bt_notification *notif,
1805 struct bt_ctf_stream *notif_stream,
1806 struct bt_ctf_packet *notif_packet)
1807{
1808 int ret = 0;
1809 struct stream_state *stream_state;
1810
1811 assert(notif->type == BT_NOTIFICATION_TYPE_EVENT);
1812 assert(notif_packet);
1813 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1814 &stream_state);
1815 if (ret) {
5af447e5 1816 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1817 goto error;
1818 }
1819
1820 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1821 if (ret) {
5af447e5 1822 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1823 goto error;
1824 }
1825
1826 add_action_push_notif(iterator, notif);
1827 goto end;
1828
1829error:
1830 ret = -1;
1831
1832end:
1833 return ret;
1834}
1835
1836static
1837int enqueue_notification_and_automatic(
1838 struct bt_notification_iterator *iterator,
1839 struct bt_notification *notif)
1840{
1841 int ret = 0;
1842 struct bt_ctf_event *notif_event = NULL;
1843 struct bt_ctf_stream *notif_stream = NULL;
1844 struct bt_ctf_packet *notif_packet = NULL;
1845
1846 assert(notif);
1847
5af447e5
PP
1848 BT_LOGV("Enqueuing user notification and automatic notifications: "
1849 "iter-addr=%p, notif-addr=%p", iterator, notif);
1850
fa054faf
PP
1851 // TODO: Skip most of this if the iterator is only subscribed
1852 // to event/inactivity notifications.
1853
3230ee6b
PP
1854 /* Get the stream and packet referred by the notification */
1855 switch (notif->type) {
1856 case BT_NOTIFICATION_TYPE_EVENT:
1857 notif_event = bt_notification_event_borrow_event(notif);
1858 assert(notif_event);
1859 notif_packet = bt_ctf_event_borrow_packet(notif_event);
1860 assert(notif_packet);
1861 break;
1862 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1863 notif_stream =
1864 bt_notification_stream_begin_borrow_stream(notif);
1865 assert(notif_stream);
1866 break;
1867 case BT_NOTIFICATION_TYPE_STREAM_END:
1868 notif_stream = bt_notification_stream_end_borrow_stream(notif);
1869 assert(notif_stream);
1870 break;
1871 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1872 notif_packet =
1873 bt_notification_packet_begin_borrow_packet(notif);
1874 assert(notif_packet);
1875 break;
1876 case BT_NOTIFICATION_TYPE_PACKET_END:
1877 notif_packet = bt_notification_packet_end_borrow_packet(notif);
1878 assert(notif_packet);
1879 break;
1880 case BT_NOTIFICATION_TYPE_INACTIVITY:
1881 /* Always valid */
7cdc2bab 1882 goto handle_notif;
3230ee6b
PP
1883 default:
1884 /*
1885 * Invalid type of notification. Only the notification
1886 * types above are allowed to be returned by a user
1887 * component.
1888 */
2ec84d26
PP
1889 BT_LOGF("Unexpected notification type at this point: "
1890 "notif-addr=%p, notif-type=%s", notif,
1891 bt_notification_type_string(notif->type));
1892 abort();
3230ee6b
PP
1893 }
1894
1895 if (notif_packet) {
1896 notif_stream = bt_ctf_packet_borrow_stream(notif_packet);
1897 assert(notif_stream);
1898 }
1899
1900 if (!notif_stream) {
1901 /*
1902 * The notification has no reference to a stream: it
1903 * cannot cause the creation of automatic notifications.
1904 */
5af447e5 1905 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
3230ee6b
PP
1906 goto end;
1907 }
1908
1909 if (!validate_notification(iterator, notif, notif_stream,
1910 notif_packet)) {
5af447e5 1911 BT_LOGW_STR("Invalid notification.");
3230ee6b
PP
1912 goto error;
1913 }
1914
7cdc2bab 1915handle_notif:
3230ee6b
PP
1916 switch (notif->type) {
1917 case BT_NOTIFICATION_TYPE_EVENT:
1918 ret = handle_notif_event(iterator, notif, notif_stream,
1919 notif_packet);
1920 break;
1921 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1922 ret = handle_notif_stream_begin(iterator, notif, notif_stream);
1923 break;
1924 case BT_NOTIFICATION_TYPE_STREAM_END:
1925 ret = handle_notif_stream_end(iterator, notif, notif_stream);
1926 break;
1927 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1928 ret = handle_notif_packet_begin(iterator, notif, notif_stream,
1929 notif_packet);
1930 break;
1931 case BT_NOTIFICATION_TYPE_PACKET_END:
1932 ret = handle_notif_packet_end(iterator, notif, notif_stream,
1933 notif_packet);
1934 break;
2ec84d26
PP
1935 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
1936 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
1937 ret = handle_notif_discarded_elements(iterator, notif,
1938 notif_stream);
1939 break;
7cdc2bab
MD
1940 case BT_NOTIFICATION_TYPE_INACTIVITY:
1941 add_action_push_notif(iterator, notif);
1942 break;
3230ee6b
PP
1943 default:
1944 break;
1945 }
1946
1947 if (ret) {
5af447e5 1948 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
3230ee6b
PP
1949 goto error;
1950 }
1951
1952 apply_actions(iterator);
5af447e5
PP
1953 BT_LOGV("Enqueued user notification and automatic notifications: "
1954 "iter-addr=%p, notif-addr=%p", iterator, notif);
3230ee6b
PP
1955 goto end;
1956
1957error:
1958 ret = -1;
1959
1960end:
1961 return ret;
1962}
1963
1964static
1965int handle_end(struct bt_notification_iterator *iterator)
1966{
1967 GHashTableIter stream_state_iter;
1968 gpointer stream_gptr, stream_state_gptr;
1969 int ret = 0;
1970
5af447e5
PP
1971 BT_LOGV("Handling end of iteration: addr=%p", iterator);
1972
3230ee6b
PP
1973 /*
1974 * Emit a "stream end" notification for each non-ended stream
1975 * known by this iterator and mark them as ended.
1976 */
1977 g_hash_table_iter_init(&stream_state_iter, iterator->stream_states);
1978
1979 while (g_hash_table_iter_next(&stream_state_iter, &stream_gptr,
1980 &stream_state_gptr)) {
1981 struct stream_state *stream_state = stream_state_gptr;
1982
1983 assert(stream_state_gptr);
1984
1985 if (stream_state->is_ended) {
1986 continue;
1987 }
1988
1989 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1990 if (ret) {
5af447e5 1991 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1992 goto error;
1993 }
1994
1995 ret = add_action_push_notif_stream_end(iterator, stream_gptr);
1996 if (ret) {
5af447e5 1997 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
3230ee6b
PP
1998 goto error;
1999 }
2000
2001 add_action_set_stream_state_is_ended(iterator, stream_state);
2002 }
2003
2004 apply_actions(iterator);
5af447e5 2005 BT_LOGV("Handled end of iteration: addr=%p", iterator);
3230ee6b
PP
2006 goto end;
2007
2008error:
2009 ret = -1;
2010
2011end:
2012 return ret;
2013}
2014
2015static
2016enum bt_notification_iterator_status ensure_queue_has_notifications(
2017 struct bt_notification_iterator *iterator)
53d45b87 2018{
890882ef
PP
2019 struct bt_private_notification_iterator *priv_iterator =
2020 bt_private_notification_iterator_from_notification_iterator(iterator);
d3eb6e8f 2021 bt_component_class_notification_iterator_next_method next_method = NULL;
fe8ad2b6
PP
2022 struct bt_notification_iterator_next_return next_return = {
2023 .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
2024 .notification = NULL,
2025 };
3230ee6b
PP
2026 enum bt_notification_iterator_status status =
2027 BT_NOTIFICATION_ITERATOR_STATUS_OK;
2028 int ret;
41a2b7ae 2029
3230ee6b 2030 assert(iterator);
5af447e5 2031 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
8f9d7550
PP
2032 "iter-addr=%p, queue-size=%u, iter-state=%s",
2033 iterator, iterator->queue->length,
2034 bt_notification_iterator_state_string(iterator->state));
3230ee6b
PP
2035
2036 if (iterator->queue->length > 0) {
8f9d7550
PP
2037 /*
2038 * We already have enough. Even if this notification
2039 * iterator is finalized, its user can still flush its
2040 * current queue's content by calling its "next" method
2041 * since this content is local and has no impact on what
2042 * used to be the iterator's upstream component.
2043 */
5af447e5 2044 BT_LOGD_STR("Queue already has at least one notification.");
3230ee6b
PP
2045 goto end;
2046 }
2047
bd14d768
PP
2048 switch (iterator->state) {
2049 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
8f9d7550 2050 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
5af447e5 2051 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
bd14d768
PP
2052 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
2053 goto end;
2054 case BT_NOTIFICATION_ITERATOR_STATE_ENDED:
5af447e5 2055 BT_LOGD_STR("Notification iterator is ended.");
3230ee6b 2056 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
41a2b7ae 2057 goto end;
bd14d768
PP
2058 default:
2059 break;
41a2b7ae 2060 }
d3eb6e8f 2061
3230ee6b
PP
2062 assert(iterator->upstream_component);
2063 assert(iterator->upstream_component->class);
d3eb6e8f 2064
3230ee6b
PP
2065 /* Pick the appropriate "next" method */
2066 switch (iterator->upstream_component->class->type) {
d3eb6e8f
PP
2067 case BT_COMPONENT_CLASS_TYPE_SOURCE:
2068 {
2069 struct bt_component_class_source *source_class =
3230ee6b 2070 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
2071 struct bt_component_class_source, parent);
2072
2073 assert(source_class->methods.iterator.next);
2074 next_method = source_class->methods.iterator.next;
2075 break;
2076 }
2077 case BT_COMPONENT_CLASS_TYPE_FILTER:
2078 {
2079 struct bt_component_class_filter *filter_class =
3230ee6b 2080 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
2081 struct bt_component_class_filter, parent);
2082
2083 assert(filter_class->methods.iterator.next);
2084 next_method = filter_class->methods.iterator.next;
2085 break;
2086 }
2087 default:
0fbb9a9f 2088 abort();
d3eb6e8f
PP
2089 }
2090
3230ee6b
PP
2091 /*
2092 * Call the user's "next" method to get the next notification
fa054faf 2093 * and status.
3230ee6b 2094 */
d3eb6e8f 2095 assert(next_method);
3230ee6b 2096
fa054faf 2097 while (iterator->queue->length == 0) {
5af447e5 2098 BT_LOGD_STR("Calling user's \"next\" method.");
fa054faf 2099 next_return = next_method(priv_iterator);
5af447e5
PP
2100 BT_LOGD("User method returned: status=%s",
2101 bt_notification_iterator_status_string(next_return.status));
fa054faf 2102 if (next_return.status < 0) {
5af447e5 2103 BT_LOGW_STR("User method failed.");
fa054faf 2104 status = next_return.status;
3230ee6b
PP
2105 goto end;
2106 }
2107
8cf27cc5
PP
2108 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
2109 iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED) {
2110 /*
2111 * The user's "next" method, somehow, cancelled
2112 * its own notification iterator. This can
2113 * happen, for example, when the user's method
2114 * removes the port on which there's the
2115 * connection from which the iterator was
2116 * created. In this case, said connection is
2117 * ended, and all its notification iterators are
2118 * finalized.
2119 *
2120 * Only bt_put() the returned notification if
2121 * the status is
2122 * BT_NOTIFICATION_ITERATOR_STATUS_OK because
2123 * otherwise this field could be garbage.
2124 */
2125 if (next_return.status ==
2126 BT_NOTIFICATION_ITERATOR_STATUS_OK) {
2127 bt_put(next_return.notification);
2128 }
2129
2130 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
2131 goto end;
2132 }
2133
fa054faf
PP
2134 switch (next_return.status) {
2135 case BT_NOTIFICATION_ITERATOR_STATUS_END:
2136 ret = handle_end(iterator);
2137 if (ret) {
5af447e5 2138 BT_LOGW_STR("Cannot handle end of iteration.");
fa054faf
PP
2139 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2140 goto end;
2141 }
3230ee6b 2142
8f9d7550
PP
2143 assert(iterator->state ==
2144 BT_NOTIFICATION_ITERATOR_STATE_ACTIVE);
2145 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ENDED;
bd14d768 2146
8f9d7550
PP
2147 if (iterator->queue->length == 0) {
2148 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
bd14d768 2149 }
5af447e5
PP
2150
2151 BT_LOGD("Set new status: status=%s",
2152 bt_notification_iterator_status_string(status));
3230ee6b 2153 goto end;
fa054faf
PP
2154 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
2155 status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
2156 goto end;
2157 case BT_NOTIFICATION_ITERATOR_STATUS_OK:
2158 if (!next_return.notification) {
5af447e5 2159 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
fa054faf
PP
2160 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2161 goto end;
2162 }
2163
2ec84d26
PP
2164 /*
2165 * Ignore some notifications which are always
2166 * automatically generated by the notification
2167 * iterator to make sure they have valid values.
2168 */
2169 switch (next_return.notification->type) {
2170 case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS:
2171 case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS:
2172 BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: "
2173 "notif-type=%s",
2174 bt_notification_type_string(next_return.notification->type));
2175 BT_PUT(next_return.notification);
2176 continue;
2177 default:
2178 break;
2179 }
2180
fa054faf
PP
2181 /*
2182 * We know the notification is valid. Before we
2183 * push it to the head of the queue, push the
2184 * appropriate automatic notifications if any.
2185 */
2186 ret = enqueue_notification_and_automatic(iterator,
2187 next_return.notification);
2188 BT_PUT(next_return.notification);
2189 if (ret) {
5af447e5 2190 BT_LOGW("Cannot enqueue notification and automatic notifications.");
fa054faf
PP
2191 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
2192 goto end;
2193 }
2194 break;
2195 default:
2196 /* Unknown non-error status */
0fbb9a9f 2197 abort();
3230ee6b 2198 }
41a2b7ae
PP
2199 }
2200
2201end:
3230ee6b
PP
2202 return status;
2203}
2204
2205enum bt_notification_iterator_status
2206bt_notification_iterator_next(struct bt_notification_iterator *iterator)
2207{
2208 enum bt_notification_iterator_status status;
2209
2210 if (!iterator) {
5af447e5 2211 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
3230ee6b
PP
2212 status = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
2213 goto end;
2214 }
2215
5af447e5
PP
2216 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator);
2217
3230ee6b
PP
2218 /*
2219 * Make sure that the iterator's queue contains at least one
2220 * notification.
2221 */
2222 status = ensure_queue_has_notifications(iterator);
2223 if (status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
5af447e5 2224 /* Not an error */
3230ee6b
PP
2225 goto end;
2226 }
2227
2228 /*
2229 * Move the notification at the tail of the queue to the
2230 * iterator's current notification.
2231 */
2232 assert(iterator->queue->length > 0);
2233 bt_put(iterator->current_notification);
2234 iterator->current_notification = g_queue_pop_tail(iterator->queue);
2235 assert(iterator->current_notification);
2236
2237end:
2238 return status;
53d45b87
JG
2239}
2240
413bc2c4
JG
2241struct bt_component *bt_notification_iterator_get_component(
2242 struct bt_notification_iterator *iterator)
2243{
3230ee6b 2244 return bt_get(iterator->upstream_component);
413bc2c4
JG
2245}
2246
91457551
PP
2247struct bt_private_component *
2248bt_private_notification_iterator_get_private_component(
2249 struct bt_private_notification_iterator *private_iterator)
2250{
2251 return bt_private_component_from_component(
2252 bt_notification_iterator_get_component(
2253 bt_notification_iterator_from_private(private_iterator)));
2254}
This page took 0.130911 seconds and 4 git commands to generate.