lib/graph/iterator.c: add logging
[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>
3230ee6b
PP
33#include <babeltrace/ctf-ir/event-internal.h>
34#include <babeltrace/ctf-ir/packet-internal.h>
35#include <babeltrace/ctf-ir/stream-internal.h>
bd14d768 36#include <babeltrace/graph/connection-internal.h>
b2e0c907
PP
37#include <babeltrace/graph/component.h>
38#include <babeltrace/graph/component-source-internal.h>
39#include <babeltrace/graph/component-class-internal.h>
fa054faf 40#include <babeltrace/graph/notification.h>
b2e0c907
PP
41#include <babeltrace/graph/notification-iterator.h>
42#include <babeltrace/graph/notification-iterator-internal.h>
e7fa96c3 43#include <babeltrace/graph/notification-internal.h>
3230ee6b
PP
44#include <babeltrace/graph/notification-event.h>
45#include <babeltrace/graph/notification-event-internal.h>
46#include <babeltrace/graph/notification-packet.h>
47#include <babeltrace/graph/notification-packet-internal.h>
48#include <babeltrace/graph/notification-stream.h>
49#include <babeltrace/graph/notification-stream-internal.h>
50#include <babeltrace/graph/port.h>
c55a9f58 51#include <babeltrace/types.h>
fa054faf 52#include <stdint.h>
3230ee6b
PP
53
54struct stream_state {
55 struct bt_ctf_stream *stream; /* owned by this */
56 struct bt_ctf_packet *cur_packet; /* owned by this */
c55a9f58 57 bt_bool is_ended;
3230ee6b
PP
58};
59
60enum action_type {
61 ACTION_TYPE_PUSH_NOTIF,
62 ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM,
63 ACTION_TYPE_ADD_STREAM_STATE,
64 ACTION_TYPE_SET_STREAM_STATE_IS_ENDED,
65 ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET,
66};
67
68struct action {
69 enum action_type type;
70 union {
71 /* ACTION_TYPE_PUSH_NOTIF */
72 struct {
73 struct bt_notification *notif; /* owned by this */
74 } push_notif;
75
76 /* ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM */
77 struct {
78 struct bt_ctf_stream *stream; /* owned by this */
79 struct bt_component *component; /* owned by this */
80 struct bt_port *port; /* owned by this */
81 } map_port_to_comp_in_stream;
82
83 /* ACTION_TYPE_ADD_STREAM_STATE */
84 struct {
85 struct bt_ctf_stream *stream; /* owned by this */
86 struct stream_state *stream_state; /* owned by this */
87 } add_stream_state;
88
89 /* ACTION_TYPE_SET_STREAM_STATE_IS_ENDED */
90 struct {
91 struct stream_state *stream_state; /* weak */
92 } set_stream_state_is_ended;
93
94 /* ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET */
95 struct {
96 struct stream_state *stream_state; /* weak */
97 struct bt_ctf_packet *packet; /* owned by this */
98 } set_stream_state_cur_packet;
99 } payload;
100};
101
102static
103void stream_destroy_listener(struct bt_ctf_stream *stream, void *data)
104{
105 struct bt_notification_iterator *iterator = data;
106
107 /* Remove associated stream state */
108 g_hash_table_remove(iterator->stream_states, stream);
109}
110
111static
112void destroy_stream_state(struct stream_state *stream_state)
113{
114 if (!stream_state) {
115 return;
116 }
117
5af447e5
PP
118 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state);
119 BT_LOGV_STR("Putting stream state's current packet.");
3230ee6b 120 bt_put(stream_state->cur_packet);
5af447e5 121 BT_LOGV_STR("Putting stream state's stream.");
3230ee6b
PP
122 bt_put(stream_state->stream);
123 g_free(stream_state);
124}
125
126static
127void destroy_action(struct action *action)
128{
129 assert(action);
130
131 switch (action->type) {
132 case ACTION_TYPE_PUSH_NOTIF:
133 BT_PUT(action->payload.push_notif.notif);
134 break;
135 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
136 BT_PUT(action->payload.map_port_to_comp_in_stream.stream);
137 BT_PUT(action->payload.map_port_to_comp_in_stream.component);
138 BT_PUT(action->payload.map_port_to_comp_in_stream.port);
139 break;
140 case ACTION_TYPE_ADD_STREAM_STATE:
141 BT_PUT(action->payload.add_stream_state.stream);
142 destroy_stream_state(
143 action->payload.add_stream_state.stream_state);
144 action->payload.add_stream_state.stream_state = NULL;
145 break;
146 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
147 BT_PUT(action->payload.set_stream_state_cur_packet.packet);
148 break;
149 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
150 break;
151 default:
c55a9f58 152 assert(BT_FALSE);
3230ee6b
PP
153 }
154}
155
156static
157void add_action(struct bt_notification_iterator *iterator,
158 struct action *action)
159{
160 g_array_append_val(iterator->actions, *action);
161}
162
163static
164void clear_actions(struct bt_notification_iterator *iterator)
165{
166 size_t i;
167
168 for (i = 0; i < iterator->actions->len; i++) {
169 struct action *action = &g_array_index(iterator->actions,
170 struct action, i);
171
172 destroy_action(action);
173 }
174
175 g_array_set_size(iterator->actions, 0);
176}
177
5af447e5
PP
178static inline
179const char *action_type_string(enum action_type type)
180{
181 switch (type) {
182 case ACTION_TYPE_PUSH_NOTIF:
183 return "ACTION_TYPE_PUSH_NOTIF";
184 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
185 return "ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM";
186 case ACTION_TYPE_ADD_STREAM_STATE:
187 return "ACTION_TYPE_ADD_STREAM_STATE";
188 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
189 return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED";
190 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
191 return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET";
192 default:
193 return "(unknown)";
194 }
195}
196
3230ee6b
PP
197static
198void apply_actions(struct bt_notification_iterator *iterator)
199{
200 size_t i;
201
5af447e5
PP
202 BT_LOGV("Applying notification's iterator current actions: "
203 "count=%u", iterator->actions->len);
204
3230ee6b
PP
205 for (i = 0; i < iterator->actions->len; i++) {
206 struct action *action = &g_array_index(iterator->actions,
207 struct action, i);
208
5af447e5
PP
209 BT_LOGV("Applying action: index=%zu, type=%s",
210 i, action_type_string(action->type));
211
3230ee6b
PP
212 switch (action->type) {
213 case ACTION_TYPE_PUSH_NOTIF:
214 /* Move notification to queue */
215 g_queue_push_head(iterator->queue,
216 action->payload.push_notif.notif);
217 bt_notification_freeze(
218 action->payload.push_notif.notif);
219 action->payload.push_notif.notif = NULL;
220 break;
221 case ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM:
222 bt_ctf_stream_map_component_to_port(
223 action->payload.map_port_to_comp_in_stream.stream,
224 action->payload.map_port_to_comp_in_stream.component,
225 action->payload.map_port_to_comp_in_stream.port);
226 break;
227 case ACTION_TYPE_ADD_STREAM_STATE:
228 /* Move stream state to hash table */
229 g_hash_table_insert(iterator->stream_states,
230 action->payload.add_stream_state.stream,
231 action->payload.add_stream_state.stream_state);
232
233 action->payload.add_stream_state.stream_state = NULL;
234 break;
235 case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED:
236 /*
237 * We know that this stream is ended. We need to
238 * remember this as long as the stream exists to
239 * enforce that the same stream does not end
240 * twice.
241 *
242 * Here we add a destroy listener to the stream
243 * which we put after (becomes weak as the hash
244 * table key). If we were the last object to own
245 * this stream, the destroy listener is called
246 * when we call bt_put() which removes this
247 * stream state completely. This is important
248 * because the memory used by this stream object
249 * could be reused for another stream, and they
250 * must have different states.
251 */
252 bt_ctf_stream_add_destroy_listener(
253 action->payload.set_stream_state_is_ended.stream_state->stream,
254 stream_destroy_listener, iterator);
c55a9f58 255 action->payload.set_stream_state_is_ended.stream_state->is_ended = BT_TRUE;
3230ee6b
PP
256 BT_PUT(action->payload.set_stream_state_is_ended.stream_state->stream);
257 break;
258 case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET:
259 /* Move packet to stream state's current packet */
260 BT_MOVE(action->payload.set_stream_state_cur_packet.stream_state->cur_packet,
261 action->payload.set_stream_state_cur_packet.packet);
262 break;
263 default:
c55a9f58 264 assert(BT_FALSE);
3230ee6b
PP
265 }
266 }
267
268 clear_actions(iterator);
269}
270
271static
272struct stream_state *create_stream_state(struct bt_ctf_stream *stream)
273{
274 struct stream_state *stream_state = g_new0(struct stream_state, 1);
275
276 if (!stream_state) {
5af447e5 277 BT_LOGE_STR("Failed to allocate one stream state.");
3230ee6b
PP
278 goto end;
279 }
280
281 /*
282 * We keep a reference to the stream until we know it's ended
283 * because we need to be able to create an automatic "stream
284 * end" notification when the user's "next" method returns
285 * BT_NOTIFICATION_ITERATOR_STATUS_END.
286 *
287 * We put this reference when the stream is marked as ended.
288 */
289 stream_state->stream = bt_get(stream);
5af447e5
PP
290 BT_LOGV("Created stream state: stream-addr=%p, stream-name=\"%s\", "
291 "stream-state-addr=%p",
292 stream, bt_ctf_stream_get_name(stream), stream_state);
3230ee6b
PP
293
294end:
295 return stream_state;
296}
47e5a032
JG
297
298static
b8a06801 299void bt_notification_iterator_destroy(struct bt_object *obj)
47e5a032 300{
8738a040
JG
301 struct bt_notification_iterator *iterator;
302
b8a06801 303 assert(obj);
d3eb6e8f 304
bd14d768
PP
305 /*
306 * The notification iterator's reference count is 0 if we're
307 * here. Increment it to avoid a double-destroy (possibly
308 * infinitely recursive). This could happen for example if the
309 * notification iterator's finalization function does bt_get()
310 * (or anything that causes bt_get() to be called) on itself
311 * (ref. count goes from 0 to 1), and then bt_put(): the
312 * reference count would go from 1 to 0 again and this function
313 * would be called again.
314 */
315 obj->ref_count.count++;
316 iterator = container_of(obj, struct bt_notification_iterator, base);
5af447e5
PP
317 BT_LOGD("Destroying notification iterator object: addr=%p",
318 iterator);
bd14d768 319 bt_notification_iterator_finalize(iterator);
d3eb6e8f 320
3230ee6b
PP
321 if (iterator->queue) {
322 struct bt_notification *notif;
323
5af447e5
PP
324 BT_LOGD("Putting notifications in queue.");
325
3230ee6b
PP
326 while ((notif = g_queue_pop_tail(iterator->queue))) {
327 bt_put(notif);
328 }
329
330 g_queue_free(iterator->queue);
331 }
332
333 if (iterator->stream_states) {
334 /*
335 * Remove our destroy listener from each stream which
336 * has a state in this iterator. Otherwise the destroy
337 * listener would be called with an invalid/other
338 * notification iterator object.
339 */
340 GHashTableIter ht_iter;
341 gpointer stream_gptr, stream_state_gptr;
342
343 g_hash_table_iter_init(&ht_iter, iterator->stream_states);
344
345 while (g_hash_table_iter_next(&ht_iter, &stream_gptr, &stream_state_gptr)) {
346 assert(stream_gptr);
5af447e5
PP
347
348 BT_LOGD_STR("Removing stream's destroy listener for notification iterator.");
3230ee6b
PP
349 bt_ctf_stream_remove_destroy_listener(
350 (void *) stream_gptr, stream_destroy_listener,
351 iterator);
352 }
353
354 g_hash_table_destroy(iterator->stream_states);
355 }
356
357 if (iterator->actions) {
358 g_array_free(iterator->actions, TRUE);
359 }
360
bd14d768
PP
361 if (iterator->connection) {
362 /*
363 * Remove ourself from the originating connection so
364 * that it does not try to finalize a dangling pointer
365 * later.
366 */
367 bt_connection_remove_iterator(iterator->connection, iterator);
368 }
369
5af447e5 370 BT_LOGD_STR("Putting current notification.");
3230ee6b 371 bt_put(iterator->current_notification);
8738a040 372 g_free(iterator);
47e5a032
JG
373}
374
bd14d768
PP
375BT_HIDDEN
376void bt_notification_iterator_finalize(
377 struct bt_notification_iterator *iterator)
378{
379 struct bt_component_class *comp_class = NULL;
380 bt_component_class_notification_iterator_finalize_method
381 finalize_method = NULL;
382
383 assert(iterator);
384
385 switch (iterator->state) {
386 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
387 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
388 /* Already finalized */
5af447e5
PP
389 BT_LOGD("Not finalizing notification iterator: already finalized: "
390 "addr=%p", iterator);
bd14d768
PP
391 return;
392 default:
393 break;
394 }
395
5af447e5
PP
396 BT_LOGD("Finalizing notification iterator: addr=%p", iterator);
397
df14f8af 398 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_ENDED) {
5af447e5
PP
399 BT_LOGD("Updating notification iterator's state: "
400 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
df14f8af
MD
401 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
402 } else {
5af447e5
PP
403 BT_LOGD("Updating notification iterator's state: "
404 "new-state=BT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
df14f8af
MD
405 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_FINALIZED;
406 }
407
bd14d768
PP
408 assert(iterator->upstream_component);
409 comp_class = iterator->upstream_component->class;
410
411 /* Call user-defined destroy method */
412 switch (comp_class->type) {
413 case BT_COMPONENT_CLASS_TYPE_SOURCE:
414 {
415 struct bt_component_class_source *source_class;
416
417 source_class = container_of(comp_class, struct bt_component_class_source, parent);
418 finalize_method = source_class->methods.iterator.finalize;
419 break;
420 }
421 case BT_COMPONENT_CLASS_TYPE_FILTER:
422 {
423 struct bt_component_class_filter *filter_class;
424
425 filter_class = container_of(comp_class, struct bt_component_class_filter, parent);
426 finalize_method = filter_class->methods.iterator.finalize;
427 break;
428 }
429 default:
430 /* Unreachable */
431 assert(0);
432 }
433
434 if (finalize_method) {
5af447e5
PP
435 BT_LOGD("Calling user's finalization method: addr=%p",
436 iterator);
bd14d768
PP
437 finalize_method(
438 bt_private_notification_iterator_from_notification_iterator(iterator));
439 }
440
bd14d768
PP
441 iterator->upstream_component = NULL;
442 iterator->upstream_port = NULL;
5af447e5 443 BT_LOGD("Finalized notification iterator: addr=%p", iterator);
bd14d768
PP
444}
445
446BT_HIDDEN
447void bt_notification_iterator_set_connection(
448 struct bt_notification_iterator *iterator,
449 struct bt_connection *connection)
450{
451 assert(iterator);
452 iterator->connection = connection;
5af447e5
PP
453 BT_LOGV("Set notification iterator's connection: "
454 "iter-addr=%p, conn-addr=%p", iterator, connection);
bd14d768
PP
455}
456
fa054faf
PP
457static
458int create_subscription_mask_from_notification_types(
459 struct bt_notification_iterator *iterator,
460 const enum bt_notification_type *notif_types)
461{
462 const enum bt_notification_type *notif_type;
463 int ret = 0;
464
465 assert(notif_types);
466 iterator->subscription_mask = 0;
467
468 for (notif_type = notif_types;
469 *notif_type != BT_NOTIFICATION_TYPE_SENTINEL;
470 notif_type++) {
471 switch (*notif_type) {
472 case BT_NOTIFICATION_TYPE_ALL:
473 iterator->subscription_mask |=
474 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT |
475 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY |
476 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN |
477 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END |
478 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN |
479 BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
480 break;
481 case BT_NOTIFICATION_TYPE_EVENT:
482 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
483 break;
484 case BT_NOTIFICATION_TYPE_INACTIVITY:
485 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
486 break;
487 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
488 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
489 break;
490 case BT_NOTIFICATION_TYPE_STREAM_END:
491 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
492 break;
493 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
494 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
495 break;
496 case BT_NOTIFICATION_TYPE_PACKET_END:
497 iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
498 break;
499 default:
500 ret = -1;
501 goto end;
502 }
5af447e5
PP
503
504 BT_LOGV("Added notification type to subscription mask: "
505 "type=%s, mask=%x",
506 bt_notification_type_string(*notif_type),
507 iterator->subscription_mask);
fa054faf
PP
508 }
509
510end:
511 return ret;
512}
513
47e5a032
JG
514BT_HIDDEN
515struct bt_notification_iterator *bt_notification_iterator_create(
3230ee6b 516 struct bt_component *upstream_comp,
fa054faf 517 struct bt_port *upstream_port,
bd14d768
PP
518 const enum bt_notification_type *notification_types,
519 struct bt_connection *connection)
47e5a032 520{
d3e4dcd8 521 enum bt_component_class_type type;
47e5a032
JG
522 struct bt_notification_iterator *iterator = NULL;
523
3230ee6b
PP
524 assert(upstream_comp);
525 assert(upstream_port);
fa054faf 526 assert(notification_types);
3230ee6b 527 assert(bt_port_is_connected(upstream_port));
5af447e5
PP
528 BT_LOGD("Creating notification iterator: "
529 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
530 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
531 "conn-addr=%p",
532 upstream_comp, bt_component_get_name(upstream_comp),
533 upstream_port, bt_port_get_name(upstream_port),
534 connection);
3230ee6b 535 type = bt_component_get_class_type(upstream_comp);
ef2f7566
PP
536 assert(type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
537 type == BT_COMPONENT_CLASS_TYPE_FILTER);
47e5a032
JG
538 iterator = g_new0(struct bt_notification_iterator, 1);
539 if (!iterator) {
5af447e5 540 BT_LOGE_STR("Failed to allocate one notification iterator.");
3230ee6b 541 goto error;
47e5a032
JG
542 }
543
b8a06801 544 bt_object_init(iterator, bt_notification_iterator_destroy);
3230ee6b 545
fa054faf
PP
546 if (create_subscription_mask_from_notification_types(iterator,
547 notification_types)) {
5af447e5 548 BT_LOGW_STR("Cannot create subscription mask from notification types.");
fa054faf
PP
549 goto error;
550 }
551
3230ee6b
PP
552 iterator->stream_states = g_hash_table_new_full(g_direct_hash,
553 g_direct_equal, NULL, (GDestroyNotify) destroy_stream_state);
554 if (!iterator->stream_states) {
5af447e5 555 BT_LOGE_STR("Failed to allocate a GHashTable.");
3230ee6b
PP
556 goto error;
557 }
558
559 iterator->queue = g_queue_new();
560 if (!iterator->queue) {
5af447e5 561 BT_LOGE_STR("Failed to allocate a GQueue.");
3230ee6b
PP
562 goto error;
563 }
564
565 iterator->actions = g_array_new(FALSE, FALSE, sizeof(struct action));
566 if (!iterator->actions) {
5af447e5 567 BT_LOGE_STR("Failed to allocate a GArray.");
3230ee6b
PP
568 goto error;
569 }
570
bd14d768
PP
571 iterator->upstream_component = upstream_comp;
572 iterator->upstream_port = upstream_port;
573 iterator->connection = connection;
574 iterator->state = BT_NOTIFICATION_ITERATOR_STATE_ACTIVE;
5af447e5
PP
575 BT_LOGD("Created notification iterator: "
576 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
577 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
578 "conn-addr=%p, iter-addr=%p",
579 upstream_comp, bt_component_get_name(upstream_comp),
580 upstream_port, bt_port_get_name(upstream_port),
581 connection, iterator);
3230ee6b
PP
582 goto end;
583
584error:
585 BT_PUT(iterator);
586
47e5a032
JG
587end:
588 return iterator;
589}
590
890882ef
PP
591void *bt_private_notification_iterator_get_user_data(
592 struct bt_private_notification_iterator *private_iterator)
ea8d3e58 593{
890882ef
PP
594 struct bt_notification_iterator *iterator =
595 bt_notification_iterator_from_private(private_iterator);
596
ea8d3e58
JG
597 return iterator ? iterator->user_data : NULL;
598}
599
600enum bt_notification_iterator_status
890882ef
PP
601bt_private_notification_iterator_set_user_data(
602 struct bt_private_notification_iterator *private_iterator,
603 void *data)
ea8d3e58
JG
604{
605 enum bt_notification_iterator_status ret =
606 BT_NOTIFICATION_ITERATOR_STATUS_OK;
890882ef
PP
607 struct bt_notification_iterator *iterator =
608 bt_notification_iterator_from_private(private_iterator);
ea8d3e58 609
d3eb6e8f 610 if (!iterator) {
5af447e5 611 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
fe8ad2b6 612 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
ea8d3e58
JG
613 goto end;
614 }
615
616 iterator->user_data = data;
5af447e5
PP
617 BT_LOGV("Set notification iterator's user data: "
618 "iter-addr=%p, user-data-addr=%p", iterator, data);
619
8738a040
JG
620end:
621 return ret;
622}
413bc2c4 623
53d45b87
JG
624struct bt_notification *bt_notification_iterator_get_notification(
625 struct bt_notification_iterator *iterator)
626{
41a2b7ae 627 struct bt_notification *notification = NULL;
d3eb6e8f 628
41a2b7ae 629 if (!iterator) {
5af447e5 630 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
41a2b7ae 631 goto end;
d3eb6e8f 632 }
d3eb6e8f 633
41a2b7ae 634 notification = bt_get(iterator->current_notification);
d3eb6e8f 635
41a2b7ae
PP
636end:
637 return notification;
53d45b87
JG
638}
639
fa054faf
PP
640static
641enum bt_notification_iterator_notif_type
642bt_notification_iterator_notif_type_from_notif_type(
643 enum bt_notification_type notif_type)
644{
645 enum bt_notification_iterator_notif_type iter_notif_type;
646
647 switch (notif_type) {
648 case BT_NOTIFICATION_TYPE_EVENT:
649 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT;
650 break;
651 case BT_NOTIFICATION_TYPE_INACTIVITY:
652 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_INACTIVITY;
653 break;
654 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
655 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN;
656 break;
657 case BT_NOTIFICATION_TYPE_STREAM_END:
658 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END;
659 break;
660 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
661 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN;
662 break;
663 case BT_NOTIFICATION_TYPE_PACKET_END:
664 iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END;
665 break;
666 default:
c55a9f58 667 assert(BT_FALSE);
fa054faf
PP
668 }
669
670 return iter_notif_type;
671}
672
3230ee6b 673static
c55a9f58 674bt_bool validate_notification(struct bt_notification_iterator *iterator,
3230ee6b
PP
675 struct bt_notification *notif,
676 struct bt_ctf_stream *notif_stream,
677 struct bt_ctf_packet *notif_packet)
678{
c55a9f58 679 bt_bool is_valid = BT_TRUE;
3230ee6b
PP
680 struct stream_state *stream_state;
681 struct bt_port *stream_comp_cur_port;
682
683 assert(notif_stream);
684 stream_comp_cur_port =
685 bt_ctf_stream_port_for_component(notif_stream,
686 iterator->upstream_component);
687 if (!stream_comp_cur_port) {
688 /*
689 * This is the first time this notification iterator
690 * bumps into this stream. Add an action to map the
691 * iterator's upstream component to the iterator's
692 * upstream port in this stream.
693 */
694 struct action action = {
695 .type = ACTION_TYPE_MAP_PORT_TO_COMP_IN_STREAM,
696 .payload.map_port_to_comp_in_stream = {
697 .stream = bt_get(notif_stream),
698 .component = bt_get(iterator->upstream_component),
699 .port = bt_get(iterator->upstream_port),
700 },
701 };
702
703 add_action(iterator, &action);
704 } else {
705 if (stream_comp_cur_port != iterator->upstream_port) {
706 /*
707 * It looks like two different ports of the same
708 * component are emitting notifications which
709 * have references to the same stream. This is
710 * bad: the API guarantees that it can never
711 * happen.
712 */
5af447e5
PP
713 BT_LOGW("Two different ports of the same component are emitting notifications which refer to the same stream: "
714 "stream-addr=%p, stream-name=\"%s\", "
715 "stream-comp-cur-port-addr=%p, "
716 "stream-comp-cur-port-name=%p, "
717 "iter-upstream-port-addr=%p, "
718 "iter-upstream-port-name=%s",
719 notif_stream,
720 bt_ctf_stream_get_name(notif_stream),
721 stream_comp_cur_port,
722 bt_port_get_name(stream_comp_cur_port),
723 iterator->upstream_port,
724 bt_port_get_name(iterator->upstream_port));
c55a9f58 725 is_valid = BT_FALSE;
3230ee6b
PP
726 goto end;
727 }
728
729 }
730
731 stream_state = g_hash_table_lookup(iterator->stream_states,
732 notif_stream);
733 if (stream_state) {
5af447e5
PP
734 BT_LOGV("Stream state already exists: "
735 "stream-addr=%p, stream-name=\"%s\", "
736 "stream-state-addr=%p",
737 notif_stream,
738 bt_ctf_stream_get_name(notif_stream), stream_state);
739
3230ee6b
PP
740 if (stream_state->is_ended) {
741 /*
742 * There's a new notification which has a
743 * reference to a stream which, from this
744 * iterator's point of view, is ended ("end of
745 * stream" notification was returned). This is
746 * bad: the API guarantees that it can never
747 * happen.
748 */
5af447e5
PP
749 BT_LOGW("Stream is already ended: "
750 "stream-addr=%p, stream-name=\"%s\"",
751 notif_stream,
752 bt_ctf_stream_get_name(notif_stream));
c55a9f58 753 is_valid = BT_FALSE;
3230ee6b
PP
754 goto end;
755 }
756
757 switch (notif->type) {
758 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
759 /*
760 * We already have a stream state, which means
761 * we already returned a "stream begin"
762 * notification: this is an invalid duplicate.
763 */
5af447e5
PP
764 BT_LOGW("Duplicate stream beginning notification: "
765 "stream-addr=%p, stream-name=\"%s\"",
766 notif_stream,
767 bt_ctf_stream_get_name(notif_stream));
c55a9f58 768 is_valid = BT_FALSE;
3230ee6b
PP
769 goto end;
770 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
771 if (notif_packet == stream_state->cur_packet) {
772 /* Duplicate "packet begin" notification */
5af447e5
PP
773 BT_LOGW("Duplicate stream beginning notification: "
774 "stream-addr=%p, stream-name=\"%s\", "
775 "packet-addr=%p",
776 notif_stream,
777 bt_ctf_stream_get_name(notif_stream),
778 notif_packet);
c55a9f58 779 is_valid = BT_FALSE;
3230ee6b
PP
780 goto end;
781 }
782 break;
783 default:
784 break;
785 }
786 }
787
788end:
789 return is_valid;
790}
791
fa054faf 792static
c55a9f58 793bt_bool is_subscribed_to_notification_type(struct bt_notification_iterator *iterator,
fa054faf
PP
794 enum bt_notification_type notif_type)
795{
796 uint32_t iter_notif_type =
797 (uint32_t) bt_notification_iterator_notif_type_from_notif_type(
798 notif_type);
799
c55a9f58 800 return (iter_notif_type & iterator->subscription_mask) ? BT_TRUE : BT_FALSE;
fa054faf
PP
801}
802
3230ee6b
PP
803static
804void add_action_push_notif(struct bt_notification_iterator *iterator,
805 struct bt_notification *notif)
806{
807 struct action action = {
808 .type = ACTION_TYPE_PUSH_NOTIF,
3230ee6b
PP
809 };
810
811 assert(notif);
fa054faf
PP
812
813 if (!is_subscribed_to_notification_type(iterator, notif->type)) {
814 return;
815 }
816
817 action.payload.push_notif.notif = bt_get(notif);
3230ee6b 818 add_action(iterator, &action);
5af447e5 819 BT_LOGV("Added \"push notification\" action: notif-addr=%p", notif);
3230ee6b
PP
820}
821
822static
823int add_action_push_notif_stream_begin(
824 struct bt_notification_iterator *iterator,
825 struct bt_ctf_stream *stream)
826{
827 int ret = 0;
828 struct bt_notification *stream_begin_notif = NULL;
829
fa054faf
PP
830 if (!is_subscribed_to_notification_type(iterator,
831 BT_NOTIFICATION_TYPE_STREAM_BEGIN)) {
5af447e5
PP
832 BT_LOGV("Not adding \"push stream beginning notification\" action: "
833 "notification iterator is not subscribed: addr=%p",
834 iterator);
fa054faf
PP
835 goto end;
836 }
837
3230ee6b
PP
838 assert(stream);
839 stream_begin_notif = bt_notification_stream_begin_create(stream);
840 if (!stream_begin_notif) {
5af447e5 841 BT_LOGE_STR("Cannot create stream beginning notification.");
3230ee6b
PP
842 goto error;
843 }
844
845 add_action_push_notif(iterator, stream_begin_notif);
5af447e5
PP
846 BT_LOGV("Added \"push stream beginning notification\" action: "
847 "stream-addr=%p, stream-name=\"%s\"",
848 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
849 goto end;
850
851error:
852 ret = -1;
853
854end:
855 bt_put(stream_begin_notif);
856 return ret;
857}
858
859static
860int add_action_push_notif_stream_end(
861 struct bt_notification_iterator *iterator,
862 struct bt_ctf_stream *stream)
863{
864 int ret = 0;
865 struct bt_notification *stream_end_notif = NULL;
866
fa054faf
PP
867 if (!is_subscribed_to_notification_type(iterator,
868 BT_NOTIFICATION_TYPE_STREAM_END)) {
5af447e5
PP
869 BT_LOGV("Not adding \"push stream end notification\" action: "
870 "notification iterator is not subscribed: addr=%p",
871 iterator);
fa054faf
PP
872 goto end;
873 }
874
3230ee6b
PP
875 assert(stream);
876 stream_end_notif = bt_notification_stream_end_create(stream);
877 if (!stream_end_notif) {
5af447e5 878 BT_LOGE_STR("Cannot create stream end notification.");
3230ee6b
PP
879 goto error;
880 }
881
882 add_action_push_notif(iterator, stream_end_notif);
5af447e5
PP
883 BT_LOGV("Added \"push stream end notification\" action: "
884 "stream-addr=%p, stream-name=\"%s\"",
885 stream, bt_ctf_stream_get_name(stream));
3230ee6b
PP
886 goto end;
887
888error:
889 ret = -1;
890
891end:
892 bt_put(stream_end_notif);
893 return ret;
894}
895
896static
897int add_action_push_notif_packet_begin(
898 struct bt_notification_iterator *iterator,
899 struct bt_ctf_packet *packet)
900{
901 int ret = 0;
902 struct bt_notification *packet_begin_notif = NULL;
903
fa054faf
PP
904 if (!is_subscribed_to_notification_type(iterator,
905 BT_NOTIFICATION_TYPE_PACKET_BEGIN)) {
5af447e5
PP
906 BT_LOGV("Not adding \"push packet beginning notification\" action: "
907 "notification iterator is not subscribed: addr=%p",
908 iterator);
fa054faf
PP
909 goto end;
910 }
911
3230ee6b
PP
912 assert(packet);
913 packet_begin_notif = bt_notification_packet_begin_create(packet);
914 if (!packet_begin_notif) {
5af447e5 915 BT_LOGE_STR("Cannot create packet beginning notification.");
3230ee6b
PP
916 goto error;
917 }
918
919 add_action_push_notif(iterator, packet_begin_notif);
5af447e5
PP
920 BT_LOGV("Added \"push packet beginning notification\" action: "
921 "packet-addr=%p", packet);
3230ee6b
PP
922 goto end;
923
924error:
925 ret = -1;
926
927end:
928 bt_put(packet_begin_notif);
929 return ret;
930}
931
932static
933int add_action_push_notif_packet_end(
934 struct bt_notification_iterator *iterator,
935 struct bt_ctf_packet *packet)
936{
937 int ret = 0;
938 struct bt_notification *packet_end_notif = NULL;
939
fa054faf
PP
940 if (!is_subscribed_to_notification_type(iterator,
941 BT_NOTIFICATION_TYPE_PACKET_END)) {
5af447e5
PP
942 BT_LOGV("Not adding \"push packet end notification\" action: "
943 "notification iterator is not subscribed: addr=%p",
944 iterator);
fa054faf
PP
945 goto end;
946 }
947
3230ee6b
PP
948 assert(packet);
949 packet_end_notif = bt_notification_packet_end_create(packet);
950 if (!packet_end_notif) {
5af447e5 951 BT_LOGE_STR("Cannot create packet end notification.");
3230ee6b
PP
952 goto error;
953 }
954
955 add_action_push_notif(iterator, packet_end_notif);
5af447e5
PP
956 BT_LOGV("Added \"push packet end notification\" action: "
957 "packet-addr=%p", packet);
3230ee6b
PP
958 goto end;
959
960error:
961 ret = -1;
962
963end:
964 bt_put(packet_end_notif);
965 return ret;
966}
967
968static
969void add_action_set_stream_state_is_ended(
970 struct bt_notification_iterator *iterator,
971 struct stream_state *stream_state)
972{
973 struct action action = {
974 .type = ACTION_TYPE_SET_STREAM_STATE_IS_ENDED,
975 .payload.set_stream_state_is_ended = {
976 .stream_state = stream_state,
977 },
978 };
979
980 assert(stream_state);
981 add_action(iterator, &action);
5af447e5
PP
982 BT_LOGV("Added \"set stream state's ended\" action: "
983 "stream-state-addr=%p", stream_state);
3230ee6b
PP
984}
985
986static
987void add_action_set_stream_state_cur_packet(
988 struct bt_notification_iterator *iterator,
989 struct stream_state *stream_state,
990 struct bt_ctf_packet *packet)
991{
992 struct action action = {
993 .type = ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET,
994 .payload.set_stream_state_cur_packet = {
995 .stream_state = stream_state,
996 .packet = bt_get(packet),
997 },
998 };
999
1000 assert(stream_state);
1001 add_action(iterator, &action);
5af447e5
PP
1002 BT_LOGV("Added \"set stream state's current packet\" action: "
1003 "stream-state-addr=%p, packet-addr=%p",
1004 stream_state, packet);
3230ee6b
PP
1005}
1006
1007static
1008int ensure_stream_state_exists(struct bt_notification_iterator *iterator,
1009 struct bt_notification *stream_begin_notif,
1010 struct bt_ctf_stream *notif_stream,
1011 struct stream_state **stream_state)
1012{
1013 int ret = 0;
1014
1015 if (!notif_stream) {
1016 /*
1017 * The notification does not reference any stream: no
1018 * need to get or create a stream state.
1019 */
1020 goto end;
1021 }
1022
1023 *stream_state = g_hash_table_lookup(iterator->stream_states,
1024 notif_stream);
1025 if (!*stream_state) {
1026 /*
1027 * This iterator did not bump into this stream yet:
1028 * create a stream state and a "stream begin"
1029 * notification.
1030 */
1031 struct action action = {
1032 .type = ACTION_TYPE_ADD_STREAM_STATE,
1033 .payload.add_stream_state = {
1034 .stream = bt_get(notif_stream),
1035 .stream_state = NULL,
1036 },
1037 };
1038
1039 *stream_state = create_stream_state(notif_stream);
1040 if (!stream_state) {
5af447e5 1041 BT_LOGE_STR("Cannot create stream state.");
3230ee6b
PP
1042 goto error;
1043 }
1044
1045 action.payload.add_stream_state.stream_state =
1046 *stream_state;
1047 add_action(iterator, &action);
1048
1049 if (stream_begin_notif) {
1050 add_action_push_notif(iterator, stream_begin_notif);
1051 } else {
1052 ret = add_action_push_notif_stream_begin(iterator,
1053 notif_stream);
1054 if (ret) {
5af447e5 1055 BT_LOGE_STR("Cannot add \"push stream beginning notification\" action.");
3230ee6b
PP
1056 goto error;
1057 }
1058 }
1059 }
1060
1061 goto end;
1062
1063error:
1064 destroy_stream_state(*stream_state);
1065 ret = -1;
1066
1067end:
1068 return ret;
1069}
1070
1071static
1072int handle_packet_switch(struct bt_notification_iterator *iterator,
1073 struct bt_notification *packet_begin_notif,
1074 struct bt_ctf_packet *new_packet,
1075 struct stream_state *stream_state)
1076{
1077 int ret = 0;
1078
1079 if (stream_state->cur_packet == new_packet) {
1080 goto end;
1081 }
1082
5af447e5
PP
1083 BT_LOGV("Handling packet switch: "
1084 "cur-packet-addr=%p, new-packet-addr=%p",
1085 stream_state->cur_packet, new_packet);
1086
3230ee6b
PP
1087 if (stream_state->cur_packet) {
1088 /* End of the current packet */
1089 ret = add_action_push_notif_packet_end(iterator,
1090 stream_state->cur_packet);
1091 if (ret) {
5af447e5 1092 BT_LOGE_STR("Cannot add \"push packet end notification\" action.");
3230ee6b
PP
1093 goto error;
1094 }
1095 }
1096
1097 /* Beginning of the new packet */
1098 if (packet_begin_notif) {
1099 add_action_push_notif(iterator, packet_begin_notif);
1100 } else if (new_packet) {
1101 ret = add_action_push_notif_packet_begin(iterator,
1102 new_packet);
1103 if (ret) {
5af447e5 1104 BT_LOGE_STR("Cannot add \"push packet beginning notification\" action.");
3230ee6b
PP
1105 goto error;
1106 }
1107 }
1108
1109 add_action_set_stream_state_cur_packet(iterator, stream_state,
1110 new_packet);
1111 goto end;
1112
1113error:
1114 ret = -1;
1115
1116end:
1117 return ret;
1118}
1119
1120static
1121int handle_notif_stream_begin(
1122 struct bt_notification_iterator *iterator,
1123 struct bt_notification *notif,
1124 struct bt_ctf_stream *notif_stream)
1125{
1126 int ret = 0;
1127 struct stream_state *stream_state;
1128
1129 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_BEGIN);
1130 assert(notif_stream);
1131 ret = ensure_stream_state_exists(iterator, notif, notif_stream,
1132 &stream_state);
1133 if (ret) {
5af447e5 1134 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1135 goto error;
1136 }
1137
1138 goto end;
1139
1140error:
1141 ret = -1;
1142
1143end:
1144 return ret;
1145}
1146
1147static
1148int handle_notif_stream_end(
1149 struct bt_notification_iterator *iterator,
1150 struct bt_notification *notif,
1151 struct bt_ctf_stream *notif_stream)
1152{
1153 int ret = 0;
1154 struct stream_state *stream_state;
1155
1156 assert(notif->type == BT_NOTIFICATION_TYPE_STREAM_END);
1157 assert(notif_stream);
1158 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1159 &stream_state);
1160 if (ret) {
5af447e5 1161 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1162 goto error;
1163 }
1164
1165 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1166 if (ret) {
5af447e5 1167 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1168 goto error;
1169 }
1170
1171 add_action_push_notif(iterator, notif);
1172 add_action_set_stream_state_is_ended(iterator, stream_state);
1173 goto end;
1174
1175error:
1176 ret = -1;
1177
1178end:
1179 return ret;
1180}
1181
1182static
1183int handle_notif_packet_begin(
1184 struct bt_notification_iterator *iterator,
1185 struct bt_notification *notif,
1186 struct bt_ctf_stream *notif_stream,
1187 struct bt_ctf_packet *notif_packet)
1188{
1189 int ret = 0;
1190 struct stream_state *stream_state;
1191
1192 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_BEGIN);
1193 assert(notif_packet);
1194 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1195 &stream_state);
1196 if (ret) {
5af447e5 1197 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1198 goto error;
1199 }
1200
1201 ret = handle_packet_switch(iterator, notif, notif_packet, stream_state);
1202 if (ret) {
5af447e5 1203 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1204 goto error;
1205 }
1206
1207 goto end;
1208
1209error:
1210 ret = -1;
1211
1212end:
1213 return ret;
1214}
1215
1216static
1217int handle_notif_packet_end(
1218 struct bt_notification_iterator *iterator,
1219 struct bt_notification *notif,
1220 struct bt_ctf_stream *notif_stream,
1221 struct bt_ctf_packet *notif_packet)
1222{
1223 int ret = 0;
1224 struct stream_state *stream_state;
1225
1226 assert(notif->type == BT_NOTIFICATION_TYPE_PACKET_END);
1227 assert(notif_packet);
1228 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1229 &stream_state);
1230 if (ret) {
5af447e5 1231 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1232 goto error;
1233 }
1234
1235 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1236 if (ret) {
5af447e5 1237 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1238 goto error;
1239 }
1240
1241 /* End of the current packet */
1242 add_action_push_notif(iterator, notif);
1243 add_action_set_stream_state_cur_packet(iterator, stream_state, NULL);
1244 goto end;
1245
1246error:
1247 ret = -1;
1248
1249end:
1250 return ret;
1251}
1252
1253static
1254int handle_notif_event(
1255 struct bt_notification_iterator *iterator,
1256 struct bt_notification *notif,
1257 struct bt_ctf_stream *notif_stream,
1258 struct bt_ctf_packet *notif_packet)
1259{
1260 int ret = 0;
1261 struct stream_state *stream_state;
1262
1263 assert(notif->type == BT_NOTIFICATION_TYPE_EVENT);
1264 assert(notif_packet);
1265 ret = ensure_stream_state_exists(iterator, NULL, notif_stream,
1266 &stream_state);
1267 if (ret) {
5af447e5 1268 BT_LOGE_STR("Cannot ensure that stream state exists.");
3230ee6b
PP
1269 goto error;
1270 }
1271
1272 ret = handle_packet_switch(iterator, NULL, notif_packet, stream_state);
1273 if (ret) {
5af447e5 1274 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1275 goto error;
1276 }
1277
1278 add_action_push_notif(iterator, notif);
1279 goto end;
1280
1281error:
1282 ret = -1;
1283
1284end:
1285 return ret;
1286}
1287
1288static
1289int enqueue_notification_and_automatic(
1290 struct bt_notification_iterator *iterator,
1291 struct bt_notification *notif)
1292{
1293 int ret = 0;
1294 struct bt_ctf_event *notif_event = NULL;
1295 struct bt_ctf_stream *notif_stream = NULL;
1296 struct bt_ctf_packet *notif_packet = NULL;
1297
1298 assert(notif);
1299
5af447e5
PP
1300 BT_LOGV("Enqueuing user notification and automatic notifications: "
1301 "iter-addr=%p, notif-addr=%p", iterator, notif);
1302
fa054faf
PP
1303 // TODO: Skip most of this if the iterator is only subscribed
1304 // to event/inactivity notifications.
1305
3230ee6b
PP
1306 /* Get the stream and packet referred by the notification */
1307 switch (notif->type) {
1308 case BT_NOTIFICATION_TYPE_EVENT:
1309 notif_event = bt_notification_event_borrow_event(notif);
1310 assert(notif_event);
1311 notif_packet = bt_ctf_event_borrow_packet(notif_event);
1312 assert(notif_packet);
1313 break;
1314 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1315 notif_stream =
1316 bt_notification_stream_begin_borrow_stream(notif);
1317 assert(notif_stream);
1318 break;
1319 case BT_NOTIFICATION_TYPE_STREAM_END:
1320 notif_stream = bt_notification_stream_end_borrow_stream(notif);
1321 assert(notif_stream);
1322 break;
1323 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1324 notif_packet =
1325 bt_notification_packet_begin_borrow_packet(notif);
1326 assert(notif_packet);
1327 break;
1328 case BT_NOTIFICATION_TYPE_PACKET_END:
1329 notif_packet = bt_notification_packet_end_borrow_packet(notif);
1330 assert(notif_packet);
1331 break;
1332 case BT_NOTIFICATION_TYPE_INACTIVITY:
1333 /* Always valid */
7cdc2bab 1334 goto handle_notif;
3230ee6b
PP
1335 default:
1336 /*
1337 * Invalid type of notification. Only the notification
1338 * types above are allowed to be returned by a user
1339 * component.
1340 */
1341 goto error;
1342 }
1343
1344 if (notif_packet) {
1345 notif_stream = bt_ctf_packet_borrow_stream(notif_packet);
1346 assert(notif_stream);
1347 }
1348
1349 if (!notif_stream) {
1350 /*
1351 * The notification has no reference to a stream: it
1352 * cannot cause the creation of automatic notifications.
1353 */
5af447e5 1354 BT_LOGV_STR("Notification has no reference to any stream: skipping automatic notification generation.");
3230ee6b
PP
1355 goto end;
1356 }
1357
1358 if (!validate_notification(iterator, notif, notif_stream,
1359 notif_packet)) {
5af447e5 1360 BT_LOGW_STR("Invalid notification.");
3230ee6b
PP
1361 goto error;
1362 }
1363
7cdc2bab 1364handle_notif:
3230ee6b
PP
1365 switch (notif->type) {
1366 case BT_NOTIFICATION_TYPE_EVENT:
1367 ret = handle_notif_event(iterator, notif, notif_stream,
1368 notif_packet);
1369 break;
1370 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
1371 ret = handle_notif_stream_begin(iterator, notif, notif_stream);
1372 break;
1373 case BT_NOTIFICATION_TYPE_STREAM_END:
1374 ret = handle_notif_stream_end(iterator, notif, notif_stream);
1375 break;
1376 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
1377 ret = handle_notif_packet_begin(iterator, notif, notif_stream,
1378 notif_packet);
1379 break;
1380 case BT_NOTIFICATION_TYPE_PACKET_END:
1381 ret = handle_notif_packet_end(iterator, notif, notif_stream,
1382 notif_packet);
1383 break;
7cdc2bab
MD
1384 case BT_NOTIFICATION_TYPE_INACTIVITY:
1385 add_action_push_notif(iterator, notif);
1386 break;
3230ee6b
PP
1387 default:
1388 break;
1389 }
1390
1391 if (ret) {
5af447e5 1392 BT_LOGW_STR("Failed to handle notification for automatic notification generation.");
3230ee6b
PP
1393 goto error;
1394 }
1395
1396 apply_actions(iterator);
5af447e5
PP
1397 BT_LOGV("Enqueued user notification and automatic notifications: "
1398 "iter-addr=%p, notif-addr=%p", iterator, notif);
3230ee6b
PP
1399 goto end;
1400
1401error:
1402 ret = -1;
1403
1404end:
1405 return ret;
1406}
1407
1408static
1409int handle_end(struct bt_notification_iterator *iterator)
1410{
1411 GHashTableIter stream_state_iter;
1412 gpointer stream_gptr, stream_state_gptr;
1413 int ret = 0;
1414
5af447e5
PP
1415 BT_LOGV("Handling end of iteration: addr=%p", iterator);
1416
3230ee6b
PP
1417 /*
1418 * Emit a "stream end" notification for each non-ended stream
1419 * known by this iterator and mark them as ended.
1420 */
1421 g_hash_table_iter_init(&stream_state_iter, iterator->stream_states);
1422
1423 while (g_hash_table_iter_next(&stream_state_iter, &stream_gptr,
1424 &stream_state_gptr)) {
1425 struct stream_state *stream_state = stream_state_gptr;
1426
1427 assert(stream_state_gptr);
1428
1429 if (stream_state->is_ended) {
1430 continue;
1431 }
1432
1433 ret = handle_packet_switch(iterator, NULL, NULL, stream_state);
1434 if (ret) {
5af447e5 1435 BT_LOGE_STR("Cannot handle packet switch.");
3230ee6b
PP
1436 goto error;
1437 }
1438
1439 ret = add_action_push_notif_stream_end(iterator, stream_gptr);
1440 if (ret) {
5af447e5 1441 BT_LOGE_STR("Cannot add \"push stream end notification\" action.");
3230ee6b
PP
1442 goto error;
1443 }
1444
1445 add_action_set_stream_state_is_ended(iterator, stream_state);
1446 }
1447
1448 apply_actions(iterator);
5af447e5 1449 BT_LOGV("Handled end of iteration: addr=%p", iterator);
3230ee6b
PP
1450 goto end;
1451
1452error:
1453 ret = -1;
1454
1455end:
1456 return ret;
1457}
1458
1459static
1460enum bt_notification_iterator_status ensure_queue_has_notifications(
1461 struct bt_notification_iterator *iterator)
53d45b87 1462{
890882ef
PP
1463 struct bt_private_notification_iterator *priv_iterator =
1464 bt_private_notification_iterator_from_notification_iterator(iterator);
d3eb6e8f 1465 bt_component_class_notification_iterator_next_method next_method = NULL;
fe8ad2b6
PP
1466 struct bt_notification_iterator_next_return next_return = {
1467 .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
1468 .notification = NULL,
1469 };
3230ee6b
PP
1470 enum bt_notification_iterator_status status =
1471 BT_NOTIFICATION_ITERATOR_STATUS_OK;
1472 int ret;
41a2b7ae 1473
3230ee6b 1474 assert(iterator);
5af447e5
PP
1475 BT_LOGD("Ensuring that notification iterator's queue has at least one notification: "
1476 "iter-addr=%p, queue-size=%u",
1477 iterator, iterator->queue->length);
3230ee6b
PP
1478
1479 if (iterator->queue->length > 0) {
1480 /* We already have enough */
5af447e5 1481 BT_LOGD_STR("Queue already has at least one notification.");
3230ee6b
PP
1482 goto end;
1483 }
1484
bd14d768
PP
1485 switch (iterator->state) {
1486 case BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
5af447e5 1487 BT_LOGD_STR("Notification iterator's \"next\" called, but it is finalized.");
bd14d768
PP
1488 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
1489 goto end;
1490 case BT_NOTIFICATION_ITERATOR_STATE_ENDED:
5af447e5 1491 BT_LOGD_STR("Notification iterator is ended.");
3230ee6b 1492 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
41a2b7ae 1493 goto end;
bd14d768
PP
1494 default:
1495 break;
41a2b7ae 1496 }
d3eb6e8f 1497
3230ee6b
PP
1498 assert(iterator->upstream_component);
1499 assert(iterator->upstream_component->class);
d3eb6e8f 1500
3230ee6b
PP
1501 /* Pick the appropriate "next" method */
1502 switch (iterator->upstream_component->class->type) {
d3eb6e8f
PP
1503 case BT_COMPONENT_CLASS_TYPE_SOURCE:
1504 {
1505 struct bt_component_class_source *source_class =
3230ee6b 1506 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
1507 struct bt_component_class_source, parent);
1508
1509 assert(source_class->methods.iterator.next);
1510 next_method = source_class->methods.iterator.next;
1511 break;
1512 }
1513 case BT_COMPONENT_CLASS_TYPE_FILTER:
1514 {
1515 struct bt_component_class_filter *filter_class =
3230ee6b 1516 container_of(iterator->upstream_component->class,
d3eb6e8f
PP
1517 struct bt_component_class_filter, parent);
1518
1519 assert(filter_class->methods.iterator.next);
1520 next_method = filter_class->methods.iterator.next;
1521 break;
1522 }
1523 default:
c55a9f58 1524 assert(BT_FALSE);
d3eb6e8f
PP
1525 break;
1526 }
1527
3230ee6b
PP
1528 /*
1529 * Call the user's "next" method to get the next notification
fa054faf 1530 * and status.
3230ee6b 1531 */
d3eb6e8f 1532 assert(next_method);
3230ee6b 1533
fa054faf 1534 while (iterator->queue->length == 0) {
5af447e5 1535 BT_LOGD_STR("Calling user's \"next\" method.");
fa054faf 1536 next_return = next_method(priv_iterator);
5af447e5
PP
1537 BT_LOGD("User method returned: status=%s",
1538 bt_notification_iterator_status_string(next_return.status));
fa054faf 1539 if (next_return.status < 0) {
5af447e5 1540 BT_LOGW_STR("User method failed.");
fa054faf 1541 status = next_return.status;
3230ee6b
PP
1542 goto end;
1543 }
1544
fa054faf
PP
1545 switch (next_return.status) {
1546 case BT_NOTIFICATION_ITERATOR_STATUS_END:
1547 ret = handle_end(iterator);
1548 if (ret) {
5af447e5 1549 BT_LOGW_STR("Cannot handle end of iteration.");
fa054faf
PP
1550 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1551 goto end;
1552 }
3230ee6b 1553
bd14d768
PP
1554 if (iterator->state == BT_NOTIFICATION_ITERATOR_STATE_FINALIZED) {
1555 iterator->state =
1556 BT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
41a2b7ae 1557
bd14d768
PP
1558 if (iterator->queue->length == 0) {
1559 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
1560 }
1561 } else {
1562 iterator->state =
1563 BT_NOTIFICATION_ITERATOR_STATE_ENDED;
1564
1565 if (iterator->queue->length == 0) {
1566 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
1567 }
1568 }
5af447e5
PP
1569
1570 BT_LOGD("Set new status: status=%s",
1571 bt_notification_iterator_status_string(status));
3230ee6b 1572 goto end;
fa054faf
PP
1573 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
1574 status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
1575 goto end;
1576 case BT_NOTIFICATION_ITERATOR_STATUS_OK:
1577 if (!next_return.notification) {
5af447e5 1578 BT_LOGW_STR("User method returned BT_NOTIFICATION_ITERATOR_STATUS_OK, but notification is NULL.");
fa054faf
PP
1579 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1580 goto end;
1581 }
1582
1583 /*
1584 * We know the notification is valid. Before we
1585 * push it to the head of the queue, push the
1586 * appropriate automatic notifications if any.
1587 */
1588 ret = enqueue_notification_and_automatic(iterator,
1589 next_return.notification);
1590 BT_PUT(next_return.notification);
1591 if (ret) {
5af447e5 1592 BT_LOGW("Cannot enqueue notification and automatic notifications.");
fa054faf
PP
1593 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1594 goto end;
1595 }
1596 break;
1597 default:
1598 /* Unknown non-error status */
c55a9f58 1599 assert(BT_FALSE);
3230ee6b 1600 }
41a2b7ae
PP
1601 }
1602
1603end:
3230ee6b
PP
1604 return status;
1605}
1606
1607enum bt_notification_iterator_status
1608bt_notification_iterator_next(struct bt_notification_iterator *iterator)
1609{
1610 enum bt_notification_iterator_status status;
1611
1612 if (!iterator) {
5af447e5 1613 BT_LOGW_STR("Invalid parameter: notification iterator is NULL.");
3230ee6b
PP
1614 status = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
1615 goto end;
1616 }
1617
5af447e5
PP
1618 BT_LOGD("Notification iterator's \"next\": iter-addr=%p", iterator);
1619
3230ee6b
PP
1620 /*
1621 * Make sure that the iterator's queue contains at least one
1622 * notification.
1623 */
1624 status = ensure_queue_has_notifications(iterator);
1625 if (status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
5af447e5 1626 /* Not an error */
3230ee6b
PP
1627 goto end;
1628 }
1629
1630 /*
1631 * Move the notification at the tail of the queue to the
1632 * iterator's current notification.
1633 */
1634 assert(iterator->queue->length > 0);
1635 bt_put(iterator->current_notification);
1636 iterator->current_notification = g_queue_pop_tail(iterator->queue);
1637 assert(iterator->current_notification);
1638
1639end:
1640 return status;
53d45b87
JG
1641}
1642
413bc2c4
JG
1643struct bt_component *bt_notification_iterator_get_component(
1644 struct bt_notification_iterator *iterator)
1645{
3230ee6b 1646 return bt_get(iterator->upstream_component);
413bc2c4
JG
1647}
1648
91457551
PP
1649struct bt_private_component *
1650bt_private_notification_iterator_get_private_component(
1651 struct bt_private_notification_iterator *private_iterator)
1652{
1653 return bt_private_component_from_component(
1654 bt_notification_iterator_get_component(
1655 bt_notification_iterator_from_private(private_iterator)));
1656}
1657
9531634f
JG
1658enum bt_notification_iterator_status bt_notification_iterator_seek_time(
1659 struct bt_notification_iterator *iterator,
1660 enum bt_notification_iterator_seek_origin seek_origin,
1661 int64_t time)
1662{
b7726e32
MD
1663 enum bt_notification_iterator_status ret =
1664 BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED;
9531634f
JG
1665 return ret;
1666}
This page took 0.100507 seconds and 4 git commands to generate.