Move to kernel style SPDX license identifiers
[babeltrace.git] / src / lib / graph / iterator.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 */
7
8 #define BT_LOG_TAG "LIB/MSG-ITER"
9 #include "lib/logging.h"
10
11 #include "compat/compiler.h"
12 #include "compat/glib.h"
13 #include "lib/trace-ir/clock-class.h"
14 #include "lib/trace-ir/clock-snapshot.h"
15 #include <babeltrace2/trace-ir/field.h>
16 #include <babeltrace2/trace-ir/event.h>
17 #include "lib/trace-ir/event.h"
18 #include <babeltrace2/trace-ir/packet.h>
19 #include "lib/trace-ir/packet.h"
20 #include "lib/trace-ir/stream.h"
21 #include <babeltrace2/trace-ir/clock-class.h>
22 #include <babeltrace2/trace-ir/stream-class.h>
23 #include <babeltrace2/trace-ir/stream.h>
24 #include <babeltrace2/graph/connection.h>
25 #include <babeltrace2/graph/component.h>
26 #include <babeltrace2/graph/message.h>
27 #include <babeltrace2/graph/self-component.h>
28 #include <babeltrace2/graph/port.h>
29 #include <babeltrace2/graph/graph.h>
30 #include <babeltrace2/graph/message-iterator.h>
31 #include <babeltrace2/types.h>
32 #include "common/assert.h"
33 #include "lib/assert-pre.h"
34 #include "lib/assert-post.h"
35 #include <stdint.h>
36 #include <inttypes.h>
37 #include <stdbool.h>
38 #include <stdlib.h>
39
40 #include "component-class.h"
41 #include "component.h"
42 #include "component-sink.h"
43 #include "component-source.h"
44 #include "connection.h"
45 #include "graph.h"
46 #include "message-iterator-class.h"
47 #include "message/discarded-items.h"
48 #include "message/event.h"
49 #include "message/iterator.h"
50 #include "message/message.h"
51 #include "message/message-iterator-inactivity.h"
52 #include "message/stream.h"
53 #include "message/packet.h"
54 #include "lib/func-status.h"
55
56 /*
57 * TODO: Use graph's state (number of active iterators, etc.) and
58 * possibly system specifications to make a better guess than this.
59 */
60 #define MSG_BATCH_SIZE 15
61
62 #define BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(_iter) \
63 BT_ASSERT_PRE((_iter)->state == BT_MESSAGE_ITERATOR_STATE_ACTIVE || \
64 (_iter)->state == BT_MESSAGE_ITERATOR_STATE_ENDED || \
65 (_iter)->state == BT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN || \
66 (_iter)->state == BT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR, \
67 "Message iterator is in the wrong state: %!+i", _iter)
68
69 static inline
70 void set_msg_iterator_state(struct bt_message_iterator *iterator,
71 enum bt_message_iterator_state state)
72 {
73 BT_ASSERT_DBG(iterator);
74 BT_LIB_LOGD("Updating message iterator's state: new-state=%s",
75 bt_message_iterator_state_string(state));
76 iterator->state = state;
77 }
78
79 static
80 void bt_message_iterator_destroy(struct bt_object *obj)
81 {
82 struct bt_message_iterator *iterator;
83
84 BT_ASSERT(obj);
85
86 /*
87 * The message iterator's reference count is 0 if we're
88 * here. Increment it to avoid a double-destroy (possibly
89 * infinitely recursive). This could happen for example if the
90 * message iterator's finalization function does
91 * bt_object_get_ref() (or anything that causes
92 * bt_object_get_ref() to be called) on itself (ref. count goes
93 * from 0 to 1), and then bt_object_put_ref(): the reference
94 * count would go from 1 to 0 again and this function would be
95 * called again.
96 */
97 obj->ref_count++;
98 iterator = (void *) obj;
99 BT_LIB_LOGI("Destroying self component input port message iterator object: "
100 "%!+i", iterator);
101 bt_message_iterator_try_finalize(iterator);
102
103 if (iterator->connection) {
104 /*
105 * Remove ourself from the originating connection so
106 * that it does not try to finalize a dangling pointer
107 * later.
108 */
109 bt_connection_remove_iterator(iterator->connection, iterator);
110 iterator->connection = NULL;
111 }
112
113 if (iterator->auto_seek.msgs) {
114 while (!g_queue_is_empty(iterator->auto_seek.msgs)) {
115 bt_object_put_ref_no_null_check(
116 g_queue_pop_tail(iterator->auto_seek.msgs));
117 }
118
119 g_queue_free(iterator->auto_seek.msgs);
120 iterator->auto_seek.msgs = NULL;
121 }
122
123 if (iterator->upstream_msg_iters) {
124 /*
125 * At this point the message iterator is finalized, so
126 * it's detached from any upstream message iterator.
127 */
128 BT_ASSERT(iterator->upstream_msg_iters->len == 0);
129 g_ptr_array_free(iterator->upstream_msg_iters, TRUE);
130 iterator->upstream_msg_iters = NULL;
131 }
132
133 if (iterator->msgs) {
134 g_ptr_array_free(iterator->msgs, TRUE);
135 iterator->msgs = NULL;
136 }
137
138 g_free(iterator);
139 }
140
141 BT_HIDDEN
142 void bt_message_iterator_try_finalize(
143 struct bt_message_iterator *iterator)
144 {
145 uint64_t i;
146 bool call_user_finalize = true;
147
148 BT_ASSERT(iterator);
149
150 switch (iterator->state) {
151 case BT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED:
152 /*
153 * If this function is called while the iterator is in the
154 * NON_INITIALIZED state, it means the user initialization
155 * method has either not been called, or has failed. We
156 * therefore don't want to call the user finalization method.
157 * However, the initialization method might have created some
158 * upstream message iterators before failing, so we want to
159 * execute the rest of this function, which unlinks the related
160 * iterators.
161 */
162 call_user_finalize = false;
163 break;
164 case BT_MESSAGE_ITERATOR_STATE_FINALIZED:
165 /* Already finalized */
166 BT_LIB_LOGD("Not finalizing message iterator: already finalized: "
167 "%!+i", iterator);
168 goto end;
169 case BT_MESSAGE_ITERATOR_STATE_FINALIZING:
170 /* Finalizing */
171 BT_LIB_LOGF("Message iterator is already being finalized: "
172 "%!+i", iterator);
173 bt_common_abort();
174 default:
175 break;
176 }
177
178 BT_LIB_LOGD("Finalizing message iterator: %!+i", iterator);
179 set_msg_iterator_state(iterator,
180 BT_MESSAGE_ITERATOR_STATE_FINALIZING);
181 BT_ASSERT(iterator->upstream_component);
182
183 /* Call user-defined destroy method */
184 if (call_user_finalize) {
185 typedef void (*method_t)(void *);
186 method_t method;
187 struct bt_component_class *comp_class =
188 iterator->upstream_component->class;
189 struct bt_component_class_with_iterator_class *class_with_iter_class;
190
191 BT_ASSERT(bt_component_class_has_message_iterator_class(comp_class));
192 class_with_iter_class = container_of(comp_class,
193 struct bt_component_class_with_iterator_class, parent);
194 method = (method_t) class_with_iter_class->msg_iter_cls->methods.finalize;
195
196 if (method) {
197 const bt_error *saved_error;
198
199 saved_error = bt_current_thread_take_error();
200
201 BT_LIB_LOGD("Calling user's finalization method: %!+i",
202 iterator);
203 method(iterator);
204
205 if (saved_error) {
206 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(saved_error);
207 }
208 }
209 }
210
211 /* Detach upstream message iterators */
212 for (i = 0; i < iterator->upstream_msg_iters->len; i++) {
213 struct bt_message_iterator *upstream_msg_iter =
214 iterator->upstream_msg_iters->pdata[i];
215
216 upstream_msg_iter->downstream_msg_iter = NULL;
217 }
218
219 g_ptr_array_set_size(iterator->upstream_msg_iters, 0);
220
221 /* Detach downstream message iterator */
222 if (iterator->downstream_msg_iter) {
223 gboolean existed;
224
225 BT_ASSERT(iterator->downstream_msg_iter->upstream_msg_iters);
226 existed = g_ptr_array_remove_fast(
227 iterator->downstream_msg_iter->upstream_msg_iters,
228 iterator);
229 BT_ASSERT(existed);
230 }
231
232 iterator->upstream_component = NULL;
233 iterator->upstream_port = NULL;
234 set_msg_iterator_state(iterator,
235 BT_MESSAGE_ITERATOR_STATE_FINALIZED);
236 BT_LIB_LOGD("Finalized message iterator: %!+i", iterator);
237
238 end:
239 return;
240 }
241
242 BT_HIDDEN
243 void bt_message_iterator_set_connection(
244 struct bt_message_iterator *iterator,
245 struct bt_connection *connection)
246 {
247 BT_ASSERT(iterator);
248 iterator->connection = connection;
249 BT_LIB_LOGI("Set message iterator's connection: "
250 "%![iter-]+i, %![conn-]+x", iterator, connection);
251 }
252
253 static
254 enum bt_message_iterator_can_seek_beginning_status can_seek_ns_from_origin_true(
255 struct bt_message_iterator *iterator,
256 int64_t ns_from_origin, bt_bool *can_seek)
257 {
258 *can_seek = BT_TRUE;
259
260 return BT_FUNC_STATUS_OK;
261 }
262
263 static
264 enum bt_message_iterator_can_seek_beginning_status can_seek_beginning_true(
265 struct bt_message_iterator *iterator,
266 bt_bool *can_seek)
267 {
268 *can_seek = BT_TRUE;
269
270 return BT_FUNC_STATUS_OK;
271 }
272
273 static
274 int create_self_component_input_port_message_iterator(
275 struct bt_self_message_iterator *self_downstream_msg_iter,
276 struct bt_self_component_port_input *self_port,
277 struct bt_message_iterator **message_iterator)
278 {
279 bt_message_iterator_class_initialize_method init_method = NULL;
280 struct bt_message_iterator *iterator =
281 NULL;
282 struct bt_message_iterator *downstream_msg_iter =
283 (void *) self_downstream_msg_iter;
284 struct bt_port *port = (void *) self_port;
285 struct bt_port *upstream_port;
286 struct bt_component *comp;
287 struct bt_component *upstream_comp;
288 struct bt_component_class *upstream_comp_cls;
289 struct bt_component_class_with_iterator_class *upstream_comp_cls_with_iter_cls;
290 int status;
291
292 BT_ASSERT_PRE_NON_NULL(message_iterator, "Created message iterator");
293 BT_ASSERT_PRE_NON_NULL(port, "Input port");
294 comp = bt_port_borrow_component_inline(port);
295 BT_ASSERT_PRE(bt_port_is_connected(port),
296 "Input port is not connected: %![port-]+p", port);
297 BT_ASSERT_PRE(comp, "Input port is not part of a component: %![port-]+p",
298 port);
299 BT_ASSERT(port->connection);
300 upstream_port = port->connection->upstream_port;
301 BT_ASSERT(upstream_port);
302 upstream_comp = bt_port_borrow_component_inline(upstream_port);
303 BT_ASSERT(upstream_comp);
304 BT_ASSERT_PRE(
305 bt_component_borrow_graph(upstream_comp)->config_state ==
306 BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED ||
307 bt_component_borrow_graph(upstream_comp)->config_state ==
308 BT_GRAPH_CONFIGURATION_STATE_CONFIGURED,
309 "Graph is not configured: %!+g",
310 bt_component_borrow_graph(upstream_comp));
311 upstream_comp_cls = upstream_comp->class;
312 BT_ASSERT(upstream_comp->class->type ==
313 BT_COMPONENT_CLASS_TYPE_SOURCE ||
314 upstream_comp->class->type ==
315 BT_COMPONENT_CLASS_TYPE_FILTER);
316 BT_LIB_LOGI("Creating message iterator on self component input port: "
317 "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
318 iterator = g_new0(
319 struct bt_message_iterator, 1);
320 if (!iterator) {
321 BT_LIB_LOGE_APPEND_CAUSE(
322 "Failed to allocate one self component input port "
323 "message iterator.");
324 status = BT_FUNC_STATUS_MEMORY_ERROR;
325 goto error;
326 }
327
328 bt_object_init_shared(&iterator->base,
329 bt_message_iterator_destroy);
330 iterator->msgs = g_ptr_array_new();
331 if (!iterator->msgs) {
332 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
333 status = BT_FUNC_STATUS_MEMORY_ERROR;
334 goto error;
335 }
336
337 g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
338 iterator->last_ns_from_origin = INT64_MIN;
339 iterator->auto_seek.msgs = g_queue_new();
340 if (!iterator->auto_seek.msgs) {
341 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GQueue.");
342 status = BT_FUNC_STATUS_MEMORY_ERROR;
343 goto error;
344 }
345
346 iterator->upstream_msg_iters = g_ptr_array_new();
347 if (!iterator->upstream_msg_iters) {
348 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
349 status = BT_FUNC_STATUS_MEMORY_ERROR;
350 goto error;
351 }
352
353 iterator->upstream_component = upstream_comp;
354 iterator->upstream_port = upstream_port;
355 iterator->connection = iterator->upstream_port->connection;
356 iterator->graph = bt_component_borrow_graph(upstream_comp);
357 set_msg_iterator_state(iterator,
358 BT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED);
359
360 /* Copy methods from the message iterator class to the message iterator. */
361 BT_ASSERT(bt_component_class_has_message_iterator_class(upstream_comp_cls));
362 upstream_comp_cls_with_iter_cls = container_of(upstream_comp_cls,
363 struct bt_component_class_with_iterator_class, parent);
364
365 iterator->methods.next =
366 (bt_message_iterator_next_method)
367 upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.next;
368 iterator->methods.seek_ns_from_origin =
369 (bt_message_iterator_seek_ns_from_origin_method)
370 upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.seek_ns_from_origin;
371 iterator->methods.seek_beginning =
372 (bt_message_iterator_seek_beginning_method)
373 upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.seek_beginning;
374 iterator->methods.can_seek_ns_from_origin =
375 (bt_message_iterator_can_seek_ns_from_origin_method)
376 upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.can_seek_ns_from_origin;
377 iterator->methods.can_seek_beginning =
378 (bt_message_iterator_can_seek_beginning_method)
379 upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.can_seek_beginning;
380
381 if (iterator->methods.seek_ns_from_origin &&
382 !iterator->methods.can_seek_ns_from_origin) {
383 iterator->methods.can_seek_ns_from_origin =
384 (bt_message_iterator_can_seek_ns_from_origin_method)
385 can_seek_ns_from_origin_true;
386 }
387
388 if (iterator->methods.seek_beginning &&
389 !iterator->methods.can_seek_beginning) {
390 iterator->methods.can_seek_beginning =
391 (bt_message_iterator_can_seek_beginning_method)
392 can_seek_beginning_true;
393 }
394
395 /* Call iterator's init method. */
396 init_method = upstream_comp_cls_with_iter_cls->msg_iter_cls->methods.initialize;
397
398 if (init_method) {
399 enum bt_message_iterator_class_initialize_method_status iter_status;
400
401 BT_LIB_LOGD("Calling user's initialization method: %!+i", iterator);
402 iter_status = init_method(
403 (struct bt_self_message_iterator *) iterator,
404 &iterator->config,
405 (struct bt_self_component_port_output *) upstream_port);
406 BT_LOGD("User method returned: status=%s",
407 bt_common_func_status_string(iter_status));
408 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(iter_status);
409 if (iter_status != BT_FUNC_STATUS_OK) {
410 BT_LIB_LOGW_APPEND_CAUSE(
411 "Component input port message iterator initialization method failed: "
412 "%![iter-]+i, status=%s",
413 iterator,
414 bt_common_func_status_string(iter_status));
415 status = iter_status;
416 goto error;
417 }
418
419 iterator->config.frozen = true;
420 }
421
422 if (downstream_msg_iter) {
423 /* Set this message iterator's downstream message iterator */
424 iterator->downstream_msg_iter = downstream_msg_iter;
425
426 /*
427 * Add this message iterator to the downstream message
428 * iterator's array of upstream message iterators.
429 */
430 g_ptr_array_add(downstream_msg_iter->upstream_msg_iters,
431 iterator);
432 }
433
434 set_msg_iterator_state(iterator,
435 BT_MESSAGE_ITERATOR_STATE_ACTIVE);
436 g_ptr_array_add(port->connection->iterators, iterator);
437 BT_LIB_LOGI("Created message iterator on self component input port: "
438 "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
439 upstream_port, upstream_comp, iterator);
440
441 *message_iterator = iterator;
442 status = BT_FUNC_STATUS_OK;
443 goto end;
444
445 error:
446 BT_OBJECT_PUT_REF_AND_RESET(iterator);
447
448 end:
449 return status;
450 }
451
452 bt_message_iterator_create_from_message_iterator_status
453 bt_message_iterator_create_from_message_iterator(
454 struct bt_self_message_iterator *self_msg_iter,
455 struct bt_self_component_port_input *input_port,
456 struct bt_message_iterator **message_iterator)
457 {
458 BT_ASSERT_PRE_NO_ERROR();
459 BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
460 return create_self_component_input_port_message_iterator(self_msg_iter,
461 input_port, message_iterator);
462 }
463
464 bt_message_iterator_create_from_sink_component_status
465 bt_message_iterator_create_from_sink_component(
466 struct bt_self_component_sink *self_comp,
467 struct bt_self_component_port_input *input_port,
468 struct bt_message_iterator **message_iterator)
469 {
470 BT_ASSERT_PRE_NO_ERROR();
471 BT_ASSERT_PRE_NON_NULL(self_comp, "Sink component");
472 return create_self_component_input_port_message_iterator(NULL,
473 input_port, message_iterator);
474 }
475
476 void *bt_self_message_iterator_get_data(
477 const struct bt_self_message_iterator *self_iterator)
478 {
479 struct bt_message_iterator *iterator =
480 (void *) self_iterator;
481
482 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
483 return iterator->user_data;
484 }
485
486 void bt_self_message_iterator_set_data(
487 struct bt_self_message_iterator *self_iterator, void *data)
488 {
489 struct bt_message_iterator *iterator =
490 (void *) self_iterator;
491
492 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
493 iterator->user_data = data;
494 BT_LIB_LOGD("Set message iterator's user data: "
495 "%!+i, user-data-addr=%p", iterator, data);
496 }
497
498 void bt_self_message_iterator_configuration_set_can_seek_forward(
499 bt_self_message_iterator_configuration *config,
500 bt_bool can_seek_forward)
501 {
502 BT_ASSERT_PRE_NON_NULL(config, "Message iterator configuration");
503 BT_ASSERT_PRE_DEV_HOT(config, "Message iterator configuration", "");
504
505 config->can_seek_forward = can_seek_forward;
506 }
507
508 /*
509 * Validate that the default clock snapshot in `msg` doesn't make us go back in
510 * time.
511 */
512
513 BT_ASSERT_POST_DEV_FUNC
514 static
515 bool clock_snapshots_are_monotonic_one(
516 struct bt_message_iterator *iterator,
517 const bt_message *msg)
518 {
519 const struct bt_clock_snapshot *clock_snapshot = NULL;
520 bt_message_type message_type = bt_message_get_type(msg);
521 int64_t ns_from_origin;
522 enum bt_clock_snapshot_get_ns_from_origin_status clock_snapshot_status;
523
524 /*
525 * The default is true: if we can't figure out the clock snapshot
526 * (or there is none), assume it is fine.
527 */
528 bool result = true;
529
530 switch (message_type) {
531 case BT_MESSAGE_TYPE_EVENT:
532 {
533 struct bt_message_event *event_msg = (struct bt_message_event *) msg;
534 clock_snapshot = event_msg->default_cs;
535 break;
536 }
537 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
538 {
539 struct bt_message_message_iterator_inactivity *inactivity_msg =
540 (struct bt_message_message_iterator_inactivity *) msg;
541 clock_snapshot = inactivity_msg->cs;
542 break;
543 }
544 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
545 case BT_MESSAGE_TYPE_PACKET_END:
546 {
547 struct bt_message_packet *packet_msg = (struct bt_message_packet *) msg;
548 clock_snapshot = packet_msg->default_cs;
549 break;
550 }
551 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
552 case BT_MESSAGE_TYPE_STREAM_END:
553 {
554 struct bt_message_stream *stream_msg = (struct bt_message_stream *) msg;
555 if (stream_msg->default_cs_state != BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
556 goto end;
557 }
558
559 clock_snapshot = stream_msg->default_cs;
560 break;
561 }
562 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
563 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
564 {
565 struct bt_message_discarded_items *discarded_msg =
566 (struct bt_message_discarded_items *) msg;
567
568 clock_snapshot = discarded_msg->default_begin_cs;
569 break;
570 }
571 }
572
573 if (!clock_snapshot) {
574 goto end;
575 }
576
577 clock_snapshot_status = bt_clock_snapshot_get_ns_from_origin(
578 clock_snapshot, &ns_from_origin);
579 if (clock_snapshot_status != BT_FUNC_STATUS_OK) {
580 /*
581 * bt_clock_snapshot_get_ns_from_origin can return
582 * OVERFLOW_ERROR. We don't really want to report an error to
583 * our caller, so just clear it.
584 */
585 bt_current_thread_clear_error();
586 goto end;
587 }
588
589 result = ns_from_origin >= iterator->last_ns_from_origin;
590 iterator->last_ns_from_origin = ns_from_origin;
591 end:
592 return result;
593 }
594
595 BT_ASSERT_POST_DEV_FUNC
596 static
597 bool clock_snapshots_are_monotonic(
598 struct bt_message_iterator *iterator,
599 bt_message_array_const msgs, uint64_t msg_count)
600 {
601 uint64_t i;
602 bool result;
603
604 for (i = 0; i < msg_count; i++) {
605 if (!clock_snapshots_are_monotonic_one(iterator, msgs[i])) {
606 result = false;
607 goto end;
608 }
609 }
610
611 result = true;
612
613 end:
614 return result;
615 }
616
617 /*
618 * When a new stream begins, verify that the clock class tied to this
619 * stream is compatible with what we've seen before.
620 */
621
622 BT_ASSERT_POST_DEV_FUNC
623 static
624 bool clock_classes_are_compatible_one(struct bt_message_iterator *iterator,
625 const struct bt_message *msg)
626 {
627 enum bt_message_type message_type = bt_message_get_type(msg);
628 bool result;
629
630 if (message_type == BT_MESSAGE_TYPE_STREAM_BEGINNING) {
631 const struct bt_message_stream *stream_msg = (struct bt_message_stream *) msg;
632 const struct bt_clock_class *clock_class = stream_msg->stream->class->default_clock_class;
633 bt_uuid clock_class_uuid = NULL;
634
635 if (clock_class) {
636 clock_class_uuid = bt_clock_class_get_uuid(clock_class);
637 }
638
639 switch (iterator->clock_expectation.type) {
640 case CLOCK_EXPECTATION_UNSET:
641 /*
642 * This is the first time we see a message with a clock
643 * snapshot: record the properties of that clock, against
644 * which we'll compare the clock properties of the following
645 * messages.
646 */
647
648 if (!clock_class) {
649 iterator->clock_expectation.type = CLOCK_EXPECTATION_NONE;
650 } else if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
651 iterator->clock_expectation.type = CLOCK_EXPECTATION_ORIGIN_UNIX;
652 } else if (clock_class_uuid) {
653 iterator->clock_expectation.type = CLOCK_EXPECTATION_ORIGIN_OTHER_UUID;
654 bt_uuid_copy(iterator->clock_expectation.uuid, clock_class_uuid);
655 } else {
656 iterator->clock_expectation.type = CLOCK_EXPECTATION_ORIGIN_OTHER_NO_UUID;
657 }
658 break;
659
660 case CLOCK_EXPECTATION_NONE:
661 if (clock_class) {
662 BT_ASSERT_POST_DEV_MSG(
663 "Expecting no clock class, got one: %![cc-]+K",
664 clock_class);
665 result = false;
666 goto end;
667 }
668
669 break;
670
671 case CLOCK_EXPECTATION_ORIGIN_UNIX:
672 if (!clock_class) {
673 BT_ASSERT_POST_DEV_MSG(
674 "Expecting a clock class, got none.");
675 result = false;
676 goto end;
677 }
678
679 if (!bt_clock_class_origin_is_unix_epoch(clock_class)) {
680 BT_ASSERT_POST_DEV_MSG(
681 "Expecting a clock class with Unix epoch origin: %![cc-]+K",
682 clock_class);
683 result = false;
684 goto end;
685 }
686 break;
687
688 case CLOCK_EXPECTATION_ORIGIN_OTHER_UUID:
689 if (!clock_class) {
690 BT_ASSERT_POST_DEV_MSG(
691 "Expecting a clock class, got none.");
692 result = false;
693 goto end;
694 }
695
696 if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
697 BT_ASSERT_POST_DEV_MSG(
698 "Expecting a clock class without Unix epoch origin: %![cc-]+K",
699 clock_class);
700 result = false;
701 goto end;
702 }
703
704 if (!clock_class_uuid) {
705 BT_ASSERT_POST_DEV_MSG(
706 "Expecting a clock class with UUID: %![cc-]+K",
707 clock_class);
708 result = false;
709 goto end;
710 }
711
712 if (bt_uuid_compare(iterator->clock_expectation.uuid, clock_class_uuid)) {
713 BT_ASSERT_POST_DEV_MSG(
714 "Expecting a clock class with UUID, got one "
715 "with a different UUID: %![cc-]+K, expected-uuid=%!u",
716 clock_class, iterator->clock_expectation.uuid);
717 result = false;
718 goto end;
719 }
720 break;
721
722 case CLOCK_EXPECTATION_ORIGIN_OTHER_NO_UUID:
723 if (!clock_class) {
724 BT_ASSERT_POST_DEV_MSG(
725 "Expecting a clock class, got none.");
726 result = false;
727 goto end;
728 }
729
730 if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
731 BT_ASSERT_POST_DEV_MSG(
732 "Expecting a clock class without Unix epoch origin: %![cc-]+K",
733 clock_class);
734 result = false;
735 goto end;
736 }
737
738 if (clock_class_uuid) {
739 BT_ASSERT_POST_DEV_MSG(
740 "Expecting a clock class without UUID: %![cc-]+K",
741 clock_class);
742 result = false;
743 goto end;
744 }
745 break;
746 }
747 }
748
749 result = true;
750
751 end:
752 return result;
753 }
754
755 BT_ASSERT_POST_DEV_FUNC
756 static
757 bool clock_classes_are_compatible(
758 struct bt_message_iterator *iterator,
759 bt_message_array_const msgs, uint64_t msg_count)
760 {
761 uint64_t i;
762 bool result;
763
764 for (i = 0; i < msg_count; i++) {
765 if (!clock_classes_are_compatible_one(iterator, msgs[i])) {
766 result = false;
767 goto end;
768 }
769 }
770
771 result = true;
772
773 end:
774 return result;
775 }
776
777 /*
778 * Call the `next` method of the iterator. Do some validation on the returned
779 * messages.
780 */
781
782 static
783 enum bt_message_iterator_class_next_method_status
784 call_iterator_next_method(
785 struct bt_message_iterator *iterator,
786 bt_message_array_const msgs, uint64_t capacity, uint64_t *user_count)
787 {
788 enum bt_message_iterator_class_next_method_status status;
789
790 BT_ASSERT_DBG(iterator->methods.next);
791 BT_LOGD_STR("Calling user's \"next\" method.");
792 status = iterator->methods.next(iterator, msgs, capacity, user_count);
793 BT_LOGD("User method returned: status=%s, msg-count=%" PRIu64,
794 bt_common_func_status_string(status), *user_count);
795
796 if (status == BT_FUNC_STATUS_OK) {
797 BT_ASSERT_POST_DEV(clock_classes_are_compatible(iterator, msgs, *user_count),
798 "Clocks are not compatible");
799 BT_ASSERT_POST_DEV(clock_snapshots_are_monotonic(iterator, msgs, *user_count),
800 "Clock snapshots are not monotonic");
801 }
802
803 BT_ASSERT_POST_DEV_NO_ERROR_IF_NO_ERROR_STATUS(status);
804
805 return status;
806 }
807
808 enum bt_message_iterator_next_status
809 bt_message_iterator_next(
810 struct bt_message_iterator *iterator,
811 bt_message_array_const *msgs, uint64_t *user_count)
812 {
813 enum bt_message_iterator_next_status status = BT_FUNC_STATUS_OK;
814
815 BT_ASSERT_PRE_DEV_NO_ERROR();
816 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
817 BT_ASSERT_PRE_DEV_NON_NULL(msgs, "Message array (output)");
818 BT_ASSERT_PRE_DEV_NON_NULL(user_count, "Message count (output)");
819 BT_ASSERT_PRE_DEV(iterator->state ==
820 BT_MESSAGE_ITERATOR_STATE_ACTIVE,
821 "Message iterator's \"next\" called, but "
822 "message iterator is in the wrong state: %!+i", iterator);
823 BT_ASSERT_DBG(iterator->upstream_component);
824 BT_ASSERT_DBG(iterator->upstream_component->class);
825 BT_ASSERT_PRE_DEV(
826 bt_component_borrow_graph(iterator->upstream_component)->config_state !=
827 BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
828 "Graph is not configured: %!+g",
829 bt_component_borrow_graph(iterator->upstream_component));
830 BT_LIB_LOGD("Getting next self component input port "
831 "message iterator's messages: %!+i, batch-size=%u",
832 iterator, MSG_BATCH_SIZE);
833
834 /*
835 * Call the user's "next" method to get the next messages
836 * and status.
837 */
838 *user_count = 0;
839 status = (int) call_iterator_next_method(iterator,
840 (void *) iterator->msgs->pdata, MSG_BATCH_SIZE,
841 user_count);
842 BT_LOGD("User method returned: status=%s, msg-count=%" PRIu64,
843 bt_common_func_status_string(status), *user_count);
844 if (status < 0) {
845 BT_LIB_LOGW_APPEND_CAUSE(
846 "Component input port message iterator's \"next\" method failed: "
847 "%![iter-]+i, status=%s",
848 iterator, bt_common_func_status_string(status));
849 goto end;
850 }
851
852 /*
853 * There is no way that this iterator could have been finalized
854 * during its "next" method, as the only way to do this is to
855 * put the last iterator's reference, and this can only be done
856 * by its downstream owner.
857 *
858 * For the same reason, there is no way that this iterator could
859 * have seeked (cannot seek a self message iterator).
860 */
861 BT_ASSERT_DBG(iterator->state ==
862 BT_MESSAGE_ITERATOR_STATE_ACTIVE);
863
864 switch (status) {
865 case BT_FUNC_STATUS_OK:
866 BT_ASSERT_POST_DEV(*user_count <= MSG_BATCH_SIZE,
867 "Invalid returned message count: greater than "
868 "batch size: count=%" PRIu64 ", batch-size=%u",
869 *user_count, MSG_BATCH_SIZE);
870 *msgs = (void *) iterator->msgs->pdata;
871 break;
872 case BT_FUNC_STATUS_AGAIN:
873 goto end;
874 case BT_FUNC_STATUS_END:
875 set_msg_iterator_state(iterator,
876 BT_MESSAGE_ITERATOR_STATE_ENDED);
877 goto end;
878 default:
879 /* Unknown non-error status */
880 bt_common_abort();
881 }
882
883 end:
884 return status;
885 }
886
887 struct bt_component *
888 bt_message_iterator_borrow_component(
889 struct bt_message_iterator *iterator)
890 {
891 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
892 return iterator->upstream_component;
893 }
894
895 struct bt_self_component *bt_self_message_iterator_borrow_component(
896 struct bt_self_message_iterator *self_iterator)
897 {
898 struct bt_message_iterator *iterator =
899 (void *) self_iterator;
900
901 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
902 return (void *) iterator->upstream_component;
903 }
904
905 struct bt_self_component_port_output *bt_self_message_iterator_borrow_port(
906 struct bt_self_message_iterator *self_iterator)
907 {
908 struct bt_message_iterator *iterator =
909 (void *) self_iterator;
910
911 BT_ASSERT_PRE_DEV_NON_NULL(iterator, "Message iterator");
912 return (void *) iterator->upstream_port;
913 }
914
915 enum bt_message_iterator_can_seek_ns_from_origin_status
916 bt_message_iterator_can_seek_ns_from_origin(
917 struct bt_message_iterator *iterator,
918 int64_t ns_from_origin, bt_bool *can_seek)
919 {
920 enum bt_message_iterator_can_seek_ns_from_origin_status status;
921
922 BT_ASSERT_PRE_NO_ERROR();
923 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
924 BT_ASSERT_PRE_NON_NULL(can_seek, "Result (output)");
925 BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
926 BT_ASSERT_PRE(
927 bt_component_borrow_graph(iterator->upstream_component)->config_state !=
928 BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
929 "Graph is not configured: %!+g",
930 bt_component_borrow_graph(iterator->upstream_component));
931
932 if (iterator->methods.can_seek_ns_from_origin) {
933 /*
934 * Initialize to an invalid value, so we can post-assert that
935 * the method returned a valid value.
936 */
937 *can_seek = -1;
938
939 BT_LIB_LOGD("Calling user's \"can seek nanoseconds from origin\" method: %!+i",
940 iterator);
941
942 status = (int) iterator->methods.can_seek_ns_from_origin(iterator,
943 ns_from_origin, can_seek);
944
945 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status);
946
947 if (status != BT_FUNC_STATUS_OK) {
948 BT_LIB_LOGW_APPEND_CAUSE(
949 "Component input port message iterator's \"can seek nanoseconds from origin\" method failed: "
950 "%![iter-]+i, status=%s",
951 iterator, bt_common_func_status_string(status));
952 goto end;
953 }
954
955 BT_ASSERT_POST(*can_seek == BT_TRUE || *can_seek == BT_FALSE,
956 "Unexpected boolean value returned from user's \"can seek ns from origin\" method: val=%d, %![iter-]+i",
957 *can_seek, iterator);
958
959 BT_LIB_LOGD(
960 "User's \"can seek nanoseconds from origin\" returned successfully: "
961 "%![iter-]+i, can-seek=%d",
962 iterator, *can_seek);
963
964 if (*can_seek) {
965 goto end;
966 }
967 }
968
969 /*
970 * Automatic seeking fall back: if we can seek to the beginning and the
971 * iterator supports forward seeking then we can automatically seek to
972 * any timestamp.
973 */
974 status = (int) bt_message_iterator_can_seek_beginning(
975 iterator, can_seek);
976 if (status != BT_FUNC_STATUS_OK) {
977 goto end;
978 }
979
980 *can_seek = *can_seek && iterator->config.can_seek_forward;
981
982 end:
983 return status;
984 }
985
986 enum bt_message_iterator_can_seek_beginning_status
987 bt_message_iterator_can_seek_beginning(
988 struct bt_message_iterator *iterator,
989 bt_bool *can_seek)
990 {
991 enum bt_message_iterator_can_seek_beginning_status status;
992
993 BT_ASSERT_PRE_NO_ERROR();
994 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
995 BT_ASSERT_PRE_NON_NULL(can_seek, "Result (output)");
996 BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
997 BT_ASSERT_PRE(
998 bt_component_borrow_graph(iterator->upstream_component)->config_state !=
999 BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
1000 "Graph is not configured: %!+g",
1001 bt_component_borrow_graph(iterator->upstream_component));
1002
1003 if (iterator->methods.can_seek_beginning) {
1004 /*
1005 * Initialize to an invalid value, so we can post-assert that
1006 * the method returned a valid value.
1007 */
1008 *can_seek = -1;
1009
1010 status = (int) iterator->methods.can_seek_beginning(iterator, can_seek);
1011
1012 BT_ASSERT_POST(
1013 status != BT_FUNC_STATUS_OK ||
1014 *can_seek == BT_TRUE ||
1015 *can_seek == BT_FALSE,
1016 "Unexpected boolean value returned from user's \"can seek beginning\" method: val=%d, %![iter-]+i",
1017 *can_seek, iterator);
1018 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status);
1019 } else {
1020 *can_seek = BT_FALSE;
1021 status = BT_FUNC_STATUS_OK;
1022 }
1023
1024 return status;
1025 }
1026
1027 static inline
1028 void set_iterator_state_after_seeking(
1029 struct bt_message_iterator *iterator,
1030 int status)
1031 {
1032 enum bt_message_iterator_state new_state = 0;
1033
1034 /* Set iterator's state depending on seeking status */
1035 switch (status) {
1036 case BT_FUNC_STATUS_OK:
1037 new_state = BT_MESSAGE_ITERATOR_STATE_ACTIVE;
1038 break;
1039 case BT_FUNC_STATUS_AGAIN:
1040 new_state = BT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN;
1041 break;
1042 case BT_FUNC_STATUS_ERROR:
1043 case BT_FUNC_STATUS_MEMORY_ERROR:
1044 new_state = BT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR;
1045 break;
1046 case BT_FUNC_STATUS_END:
1047 new_state = BT_MESSAGE_ITERATOR_STATE_ENDED;
1048 break;
1049 default:
1050 bt_common_abort();
1051 }
1052
1053 set_msg_iterator_state(iterator, new_state);
1054 }
1055
1056 static
1057 void reset_iterator_expectations(
1058 struct bt_message_iterator *iterator)
1059 {
1060 iterator->last_ns_from_origin = INT64_MIN;
1061 iterator->clock_expectation.type = CLOCK_EXPECTATION_UNSET;
1062 }
1063
1064 static
1065 bool message_iterator_can_seek_beginning(
1066 struct bt_message_iterator *iterator)
1067 {
1068 enum bt_message_iterator_can_seek_beginning_status status;
1069 bt_bool can_seek;
1070
1071 status = bt_message_iterator_can_seek_beginning(
1072 iterator, &can_seek);
1073 if (status != BT_FUNC_STATUS_OK) {
1074 can_seek = BT_FALSE;
1075 }
1076
1077 return can_seek;
1078 }
1079
1080 enum bt_message_iterator_seek_beginning_status
1081 bt_message_iterator_seek_beginning(
1082 struct bt_message_iterator *iterator)
1083 {
1084 int status;
1085
1086 BT_ASSERT_PRE_NO_ERROR();
1087 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
1088 BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
1089 BT_ASSERT_PRE(
1090 bt_component_borrow_graph(iterator->upstream_component)->config_state !=
1091 BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
1092 "Graph is not configured: %!+g",
1093 bt_component_borrow_graph(iterator->upstream_component));
1094 BT_ASSERT_PRE(message_iterator_can_seek_beginning(iterator),
1095 "Message iterator cannot seek beginning: %!+i", iterator);
1096
1097 /*
1098 * We are seeking, reset our expectations about how the following
1099 * messages should look like.
1100 */
1101 reset_iterator_expectations(iterator);
1102
1103 BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i", iterator);
1104 set_msg_iterator_state(iterator,
1105 BT_MESSAGE_ITERATOR_STATE_SEEKING);
1106 status = iterator->methods.seek_beginning(iterator);
1107 BT_LOGD("User method returned: status=%s",
1108 bt_common_func_status_string(status));
1109 BT_ASSERT_POST(status == BT_FUNC_STATUS_OK ||
1110 status == BT_FUNC_STATUS_ERROR ||
1111 status == BT_FUNC_STATUS_MEMORY_ERROR ||
1112 status == BT_FUNC_STATUS_AGAIN,
1113 "Unexpected status: %![iter-]+i, status=%s",
1114 iterator, bt_common_func_status_string(status));
1115 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status);
1116 if (status < 0) {
1117 BT_LIB_LOGW_APPEND_CAUSE(
1118 "Component input port message iterator's \"seek beginning\" method failed: "
1119 "%![iter-]+i, status=%s",
1120 iterator, bt_common_func_status_string(status));
1121 }
1122
1123 set_iterator_state_after_seeking(iterator, status);
1124 return status;
1125 }
1126
1127 bt_bool
1128 bt_message_iterator_can_seek_forward(
1129 bt_message_iterator *iterator)
1130 {
1131 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
1132
1133 return iterator->config.can_seek_forward;
1134 }
1135
1136 /*
1137 * Structure used to record the state of a given stream during the fast-forward
1138 * phase of an auto-seek.
1139 */
1140 struct auto_seek_stream_state {
1141 /*
1142 * Value representing which step of this timeline we are at.
1143 *
1144 * time --->
1145 * [SB] 1 [PB] 2 [PE] 1 [SE]
1146 *
1147 * At each point in the timeline, the messages we need to replicate are:
1148 *
1149 * 1: Stream beginning
1150 * 2: Stream beginning, packet beginning
1151 *
1152 * Before "Stream beginning" and after "Stream end", we don't need to
1153 * replicate anything as the stream doesn't exist.
1154 */
1155 enum {
1156 AUTO_SEEK_STREAM_STATE_STREAM_BEGAN,
1157 AUTO_SEEK_STREAM_STATE_PACKET_BEGAN,
1158 } state;
1159
1160 /*
1161 * If `state` is AUTO_SEEK_STREAM_STATE_PACKET_BEGAN, the packet we are
1162 * in. This is a weak reference, since the packet will always be
1163 * alive by the time we use it.
1164 */
1165 struct bt_packet *packet;
1166
1167 /* Have we see a message with a clock snapshot yet? */
1168 bool seen_clock_snapshot;
1169 };
1170
1171 static
1172 struct auto_seek_stream_state *create_auto_seek_stream_state(void)
1173 {
1174 return g_new0(struct auto_seek_stream_state, 1);
1175 }
1176
1177 static
1178 void destroy_auto_seek_stream_state(void *ptr)
1179 {
1180 g_free(ptr);
1181 }
1182
1183 static
1184 GHashTable *create_auto_seek_stream_states(void)
1185 {
1186 return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
1187 destroy_auto_seek_stream_state);
1188 }
1189
1190 static
1191 void destroy_auto_seek_stream_states(GHashTable *stream_states)
1192 {
1193 g_hash_table_destroy(stream_states);
1194 }
1195
1196 /*
1197 * Handle one message while we are in the fast-forward phase of an auto-seek.
1198 *
1199 * Sets `*got_first` to true if the message's timestamp is greater or equal to
1200 * `ns_from_origin`. In other words, if this is the first message after our
1201 * seek point.
1202 *
1203 * `stream_states` is an hash table of `bt_stream *` (weak reference) to
1204 * `struct auto_seek_stream_state` used to keep the state of each stream
1205 * during the fast-forward.
1206 */
1207
1208 static inline
1209 int auto_seek_handle_message(
1210 struct bt_message_iterator *iterator,
1211 int64_t ns_from_origin, const struct bt_message *msg,
1212 bool *got_first, GHashTable *stream_states)
1213 {
1214 int status = BT_FUNC_STATUS_OK;
1215 int64_t msg_ns_from_origin;
1216 const struct bt_clock_snapshot *clk_snapshot = NULL;
1217 int ret;
1218
1219 BT_ASSERT_DBG(msg);
1220 BT_ASSERT_DBG(got_first);
1221
1222 switch (msg->type) {
1223 case BT_MESSAGE_TYPE_EVENT:
1224 {
1225 const struct bt_message_event *event_msg =
1226 (const void *) msg;
1227
1228 clk_snapshot = event_msg->default_cs;
1229 BT_ASSERT_POST_DEV(clk_snapshot,
1230 "Event message has no default clock snapshot: %!+n",
1231 event_msg);
1232 break;
1233 }
1234 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
1235 {
1236 const struct bt_message_message_iterator_inactivity *inactivity_msg =
1237 (const void *) msg;
1238
1239 clk_snapshot = inactivity_msg->cs;
1240 BT_ASSERT_DBG(clk_snapshot);
1241 break;
1242 }
1243 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
1244 case BT_MESSAGE_TYPE_PACKET_END:
1245 {
1246 const struct bt_message_packet *packet_msg =
1247 (const void *) msg;
1248
1249 clk_snapshot = packet_msg->default_cs;
1250 BT_ASSERT_POST_DEV(clk_snapshot,
1251 "Packet message has no default clock snapshot: %!+n",
1252 packet_msg);
1253 break;
1254 }
1255 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1256 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1257 {
1258 struct bt_message_discarded_items *msg_disc_items =
1259 (void *) msg;
1260
1261 BT_ASSERT_POST_DEV(msg_disc_items->default_begin_cs &&
1262 msg_disc_items->default_end_cs,
1263 "Discarded events/packets message has no default clock snapshots: %!+n",
1264 msg_disc_items);
1265 ret = bt_clock_snapshot_get_ns_from_origin(
1266 msg_disc_items->default_begin_cs,
1267 &msg_ns_from_origin);
1268 if (ret) {
1269 status = BT_FUNC_STATUS_ERROR;
1270 goto end;
1271 }
1272
1273 if (msg_ns_from_origin >= ns_from_origin) {
1274 *got_first = true;
1275 goto push_msg;
1276 }
1277
1278 ret = bt_clock_snapshot_get_ns_from_origin(
1279 msg_disc_items->default_end_cs,
1280 &msg_ns_from_origin);
1281 if (ret) {
1282 status = BT_FUNC_STATUS_ERROR;
1283 goto end;
1284 }
1285
1286 if (msg_ns_from_origin >= ns_from_origin) {
1287 /*
1288 * The discarded items message's beginning time
1289 * is before the requested seeking time, but its
1290 * end time is after. Modify the message so as
1291 * to set its beginning time to the requested
1292 * seeking time, and make its item count unknown
1293 * as we don't know if items were really
1294 * discarded within the new time range.
1295 */
1296 uint64_t new_begin_raw_value = 0;
1297
1298 ret = bt_clock_class_clock_value_from_ns_from_origin(
1299 msg_disc_items->default_end_cs->clock_class,
1300 ns_from_origin, &new_begin_raw_value);
1301 if (ret) {
1302 status = BT_FUNC_STATUS_ERROR;
1303 goto end;
1304 }
1305
1306 bt_clock_snapshot_set_raw_value(
1307 msg_disc_items->default_begin_cs,
1308 new_begin_raw_value);
1309 msg_disc_items->count.base.avail =
1310 BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
1311
1312 /*
1313 * It is safe to push it because its beginning
1314 * time is exactly the requested seeking time.
1315 */
1316 goto push_msg;
1317 } else {
1318 goto skip_msg;
1319 }
1320 }
1321 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
1322 case BT_MESSAGE_TYPE_STREAM_END:
1323 {
1324 struct bt_message_stream *stream_msg =
1325 (struct bt_message_stream *) msg;
1326
1327 if (stream_msg->default_cs_state != BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1328 /* Ignore */
1329 goto skip_msg;
1330 }
1331
1332 clk_snapshot = stream_msg->default_cs;
1333 break;
1334 }
1335 default:
1336 bt_common_abort();
1337 }
1338
1339 BT_ASSERT_DBG(clk_snapshot);
1340 ret = bt_clock_snapshot_get_ns_from_origin(clk_snapshot,
1341 &msg_ns_from_origin);
1342 if (ret) {
1343 status = BT_FUNC_STATUS_ERROR;
1344 goto end;
1345 }
1346
1347 if (msg_ns_from_origin >= ns_from_origin) {
1348 *got_first = true;
1349 goto push_msg;
1350 }
1351
1352 skip_msg:
1353 /* This message won't be sent downstream. */
1354 switch (msg->type) {
1355 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
1356 {
1357 const struct bt_message_stream *stream_msg = (const void *) msg;
1358 struct auto_seek_stream_state *stream_state;
1359
1360 /* Update stream's state: stream began. */
1361 stream_state = create_auto_seek_stream_state();
1362 if (!stream_state) {
1363 status = BT_FUNC_STATUS_MEMORY_ERROR;
1364 goto end;
1365 }
1366
1367 stream_state->state = AUTO_SEEK_STREAM_STATE_STREAM_BEGAN;
1368
1369 if (stream_msg->default_cs_state == BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN) {
1370 stream_state->seen_clock_snapshot = true;
1371 }
1372
1373 BT_ASSERT_DBG(!bt_g_hash_table_contains(stream_states, stream_msg->stream));
1374 g_hash_table_insert(stream_states, stream_msg->stream, stream_state);
1375 break;
1376 }
1377 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
1378 {
1379 const struct bt_message_packet *packet_msg =
1380 (const void *) msg;
1381 struct auto_seek_stream_state *stream_state;
1382
1383 /* Update stream's state: packet began. */
1384 stream_state = g_hash_table_lookup(stream_states, packet_msg->packet->stream);
1385 BT_ASSERT_DBG(stream_state);
1386 BT_ASSERT_DBG(stream_state->state == AUTO_SEEK_STREAM_STATE_STREAM_BEGAN);
1387 stream_state->state = AUTO_SEEK_STREAM_STATE_PACKET_BEGAN;
1388 BT_ASSERT_DBG(!stream_state->packet);
1389 stream_state->packet = packet_msg->packet;
1390
1391 if (packet_msg->packet->stream->class->packets_have_beginning_default_clock_snapshot) {
1392 stream_state->seen_clock_snapshot = true;
1393 }
1394
1395 break;
1396 }
1397 case BT_MESSAGE_TYPE_EVENT:
1398 {
1399 const struct bt_message_event *event_msg = (const void *) msg;
1400 struct auto_seek_stream_state *stream_state;
1401
1402 stream_state = g_hash_table_lookup(stream_states,
1403 event_msg->event->stream);
1404 BT_ASSERT_DBG(stream_state);
1405
1406 // HELPME: are we sure that event messages have clock snapshots at this point?
1407 stream_state->seen_clock_snapshot = true;
1408
1409 break;
1410 }
1411 case BT_MESSAGE_TYPE_PACKET_END:
1412 {
1413 const struct bt_message_packet *packet_msg =
1414 (const void *) msg;
1415 struct auto_seek_stream_state *stream_state;
1416
1417 /* Update stream's state: packet ended. */
1418 stream_state = g_hash_table_lookup(stream_states, packet_msg->packet->stream);
1419 BT_ASSERT_DBG(stream_state);
1420 BT_ASSERT_DBG(stream_state->state == AUTO_SEEK_STREAM_STATE_PACKET_BEGAN);
1421 stream_state->state = AUTO_SEEK_STREAM_STATE_STREAM_BEGAN;
1422 BT_ASSERT_DBG(stream_state->packet);
1423 stream_state->packet = NULL;
1424
1425 if (packet_msg->packet->stream->class->packets_have_end_default_clock_snapshot) {
1426 stream_state->seen_clock_snapshot = true;
1427 }
1428
1429 break;
1430 }
1431 case BT_MESSAGE_TYPE_STREAM_END:
1432 {
1433 const struct bt_message_stream *stream_msg = (const void *) msg;
1434 struct auto_seek_stream_state *stream_state;
1435
1436 stream_state = g_hash_table_lookup(stream_states, stream_msg->stream);
1437 BT_ASSERT_DBG(stream_state);
1438 BT_ASSERT_DBG(stream_state->state == AUTO_SEEK_STREAM_STATE_STREAM_BEGAN);
1439 BT_ASSERT_DBG(!stream_state->packet);
1440
1441 /* Update stream's state: this stream doesn't exist anymore. */
1442 g_hash_table_remove(stream_states, stream_msg->stream);
1443 break;
1444 }
1445 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1446 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1447 {
1448 const struct bt_message_discarded_items *discarded_msg =
1449 (const void *) msg;
1450 struct auto_seek_stream_state *stream_state;
1451
1452 stream_state = g_hash_table_lookup(stream_states, discarded_msg->stream);
1453 BT_ASSERT_DBG(stream_state);
1454
1455 if ((msg->type == BT_MESSAGE_TYPE_DISCARDED_EVENTS && discarded_msg->stream->class->discarded_events_have_default_clock_snapshots) ||
1456 (msg->type == BT_MESSAGE_TYPE_DISCARDED_PACKETS && discarded_msg->stream->class->discarded_packets_have_default_clock_snapshots)) {
1457 stream_state->seen_clock_snapshot = true;
1458 }
1459
1460 break;
1461 }
1462 default:
1463 break;
1464 }
1465
1466 bt_object_put_ref_no_null_check(msg);
1467 msg = NULL;
1468 goto end;
1469
1470 push_msg:
1471 g_queue_push_tail(iterator->auto_seek.msgs, (void *) msg);
1472 msg = NULL;
1473
1474 end:
1475 BT_ASSERT_DBG(!msg || status != BT_FUNC_STATUS_OK);
1476 return status;
1477 }
1478
1479 static
1480 int find_message_ge_ns_from_origin(
1481 struct bt_message_iterator *iterator,
1482 int64_t ns_from_origin, GHashTable *stream_states)
1483 {
1484 int status = BT_FUNC_STATUS_OK;
1485 enum bt_message_iterator_state init_state =
1486 iterator->state;
1487 const struct bt_message *messages[MSG_BATCH_SIZE];
1488 uint64_t user_count = 0;
1489 uint64_t i;
1490 bool got_first = false;
1491
1492 BT_ASSERT_DBG(iterator);
1493 memset(&messages[0], 0, sizeof(messages[0]) * MSG_BATCH_SIZE);
1494
1495 /*
1496 * Make this iterator temporarily active (not seeking) to call
1497 * the "next" method.
1498 */
1499 set_msg_iterator_state(iterator,
1500 BT_MESSAGE_ITERATOR_STATE_ACTIVE);
1501
1502 BT_ASSERT_DBG(iterator->methods.next);
1503
1504 while (!got_first) {
1505 /*
1506 * Call the user's "next" method to get the next
1507 * messages and status.
1508 */
1509 status = call_iterator_next_method(iterator,
1510 &messages[0], MSG_BATCH_SIZE, &user_count);
1511 BT_LOGD("User method returned: status=%s",
1512 bt_common_func_status_string(status));
1513 if (status < 0) {
1514 BT_LIB_LOGW_APPEND_CAUSE(
1515 "Component input port message iterator's \"next\" method failed: "
1516 "%![iter-]+i, status=%s",
1517 iterator, bt_common_func_status_string(status));
1518 }
1519
1520 /*
1521 * The user's "next" method must not do any action which
1522 * would change the iterator's state.
1523 */
1524 BT_ASSERT_DBG(iterator->state ==
1525 BT_MESSAGE_ITERATOR_STATE_ACTIVE);
1526
1527 switch (status) {
1528 case BT_FUNC_STATUS_OK:
1529 BT_ASSERT_POST_DEV(user_count <= MSG_BATCH_SIZE,
1530 "Invalid returned message count: greater than "
1531 "batch size: count=%" PRIu64 ", batch-size=%u",
1532 user_count, MSG_BATCH_SIZE);
1533 break;
1534 case BT_FUNC_STATUS_AGAIN:
1535 case BT_FUNC_STATUS_ERROR:
1536 case BT_FUNC_STATUS_MEMORY_ERROR:
1537 case BT_FUNC_STATUS_END:
1538 goto end;
1539 default:
1540 bt_common_abort();
1541 }
1542
1543 for (i = 0; i < user_count; i++) {
1544 if (got_first) {
1545 g_queue_push_tail(iterator->auto_seek.msgs,
1546 (void *) messages[i]);
1547 messages[i] = NULL;
1548 continue;
1549 }
1550
1551 status = auto_seek_handle_message(iterator,
1552 ns_from_origin, messages[i], &got_first,
1553 stream_states);
1554 if (status == BT_FUNC_STATUS_OK) {
1555 /* Message was either pushed or moved */
1556 messages[i] = NULL;
1557 } else {
1558 goto end;
1559 }
1560 }
1561 }
1562
1563 end:
1564 for (i = 0; i < user_count; i++) {
1565 if (messages[i]) {
1566 bt_object_put_ref_no_null_check(messages[i]);
1567 }
1568 }
1569
1570 set_msg_iterator_state(iterator, init_state);
1571 return status;
1572 }
1573
1574 /*
1575 * This function is installed as the iterator's next callback after we have
1576 * auto-seeked (seeked to the beginning and fast-forwarded) to send the
1577 * messages saved in iterator->auto_seek.msgs. Once this is done, the original
1578 * next callback is put back.
1579 */
1580
1581 static
1582 enum bt_message_iterator_class_next_method_status post_auto_seek_next(
1583 struct bt_message_iterator *iterator,
1584 bt_message_array_const msgs, uint64_t capacity,
1585 uint64_t *count)
1586 {
1587 BT_ASSERT(!g_queue_is_empty(iterator->auto_seek.msgs));
1588 *count = 0;
1589
1590 /*
1591 * Move auto-seek messages to the output array (which is this
1592 * iterator's base message array).
1593 */
1594 while (capacity > 0 && !g_queue_is_empty(iterator->auto_seek.msgs)) {
1595 msgs[*count] = g_queue_pop_head(iterator->auto_seek.msgs);
1596 capacity--;
1597 (*count)++;
1598 }
1599
1600 BT_ASSERT(*count > 0);
1601
1602 if (g_queue_is_empty(iterator->auto_seek.msgs)) {
1603 /* No more auto-seek messages, restore user's next callback. */
1604 BT_ASSERT(iterator->auto_seek.original_next_callback);
1605 iterator->methods.next = iterator->auto_seek.original_next_callback;
1606 iterator->auto_seek.original_next_callback = NULL;
1607 }
1608
1609 return BT_FUNC_STATUS_OK;
1610 }
1611
1612 static inline
1613 int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
1614 int64_t ns_from_origin, uint64_t *raw_value)
1615 {
1616
1617 int64_t cc_offset_s = clock_class->offset_seconds;
1618 uint64_t cc_offset_cycles = clock_class->offset_cycles;
1619 uint64_t cc_freq = clock_class->frequency;
1620
1621 return bt_common_clock_value_from_ns_from_origin(cc_offset_s,
1622 cc_offset_cycles, cc_freq, ns_from_origin, raw_value);
1623 }
1624
1625 static
1626 bool message_iterator_can_seek_ns_from_origin(
1627 struct bt_message_iterator *iterator,
1628 int64_t ns_from_origin)
1629 {
1630 enum bt_message_iterator_can_seek_ns_from_origin_status status;
1631 bt_bool can_seek;
1632
1633 status = bt_message_iterator_can_seek_ns_from_origin(
1634 iterator, ns_from_origin, &can_seek);
1635 if (status != BT_FUNC_STATUS_OK) {
1636 can_seek = BT_FALSE;
1637 }
1638
1639 return can_seek;
1640 }
1641
1642 enum bt_message_iterator_seek_ns_from_origin_status
1643 bt_message_iterator_seek_ns_from_origin(
1644 struct bt_message_iterator *iterator,
1645 int64_t ns_from_origin)
1646 {
1647 int status;
1648 GHashTable *stream_states = NULL;
1649 bt_bool can_seek_by_itself;
1650
1651 BT_ASSERT_PRE_NO_ERROR();
1652 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
1653 BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
1654 BT_ASSERT_PRE(
1655 bt_component_borrow_graph(iterator->upstream_component)->config_state !=
1656 BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
1657 "Graph is not configured: %!+g",
1658 bt_component_borrow_graph(iterator->upstream_component));
1659 /* The iterator must be able to seek ns from origin one way or another. */
1660 BT_ASSERT_PRE(
1661 message_iterator_can_seek_ns_from_origin(iterator, ns_from_origin),
1662 "Message iterator cannot seek nanoseconds from origin: %!+i, "
1663 "ns-from-origin=%" PRId64, iterator, ns_from_origin);
1664 set_msg_iterator_state(iterator,
1665 BT_MESSAGE_ITERATOR_STATE_SEEKING);
1666
1667 /*
1668 * We are seeking, reset our expectations about how the following
1669 * messages should look like.
1670 */
1671 reset_iterator_expectations(iterator);
1672
1673 /* Check if the iterator can seek by itself. If not we'll use autoseek. */
1674 if (iterator->methods.can_seek_ns_from_origin) {
1675 bt_message_iterator_class_can_seek_ns_from_origin_method_status
1676 can_seek_status;
1677
1678 can_seek_status =
1679 iterator->methods.can_seek_ns_from_origin(
1680 iterator, ns_from_origin, &can_seek_by_itself);
1681 if (can_seek_status != BT_FUNC_STATUS_OK) {
1682 status = can_seek_status;
1683 goto end;
1684 }
1685 } else {
1686 can_seek_by_itself = false;
1687 }
1688
1689 if (can_seek_by_itself) {
1690 /* The iterator knows how to seek to a particular time, let it handle this. */
1691 BT_ASSERT(iterator->methods.seek_ns_from_origin);
1692 BT_LIB_LOGD("Calling user's \"seek nanoseconds from origin\" method: "
1693 "%![iter-]+i, ns=%" PRId64, iterator, ns_from_origin);
1694 status = iterator->methods.seek_ns_from_origin(iterator,
1695 ns_from_origin);
1696 BT_LOGD("User method returned: status=%s",
1697 bt_common_func_status_string(status));
1698 BT_ASSERT_POST(status == BT_FUNC_STATUS_OK ||
1699 status == BT_FUNC_STATUS_ERROR ||
1700 status == BT_FUNC_STATUS_MEMORY_ERROR ||
1701 status == BT_FUNC_STATUS_AGAIN,
1702 "Unexpected status: %![iter-]+i, status=%s",
1703 iterator, bt_common_func_status_string(status));
1704 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status);
1705 if (status < 0) {
1706 BT_LIB_LOGW_APPEND_CAUSE(
1707 "Component input port message iterator's \"seek nanoseconds from origin\" method failed: "
1708 "%![iter-]+i, status=%s",
1709 iterator, bt_common_func_status_string(status));
1710 }
1711 } else {
1712 /*
1713 * The iterator doesn't know how to seek by itself to a
1714 * particular time. We will seek to the beginning and fast
1715 * forward to the right place.
1716 */
1717 enum bt_message_iterator_class_can_seek_beginning_method_status can_seek_status;
1718 bt_bool can_seek_beginning;
1719
1720 can_seek_status = iterator->methods.can_seek_beginning(iterator,
1721 &can_seek_beginning);
1722 BT_ASSERT(can_seek_status == BT_FUNC_STATUS_OK);
1723 BT_ASSERT(can_seek_beginning);
1724 BT_ASSERT(iterator->methods.seek_beginning);
1725 BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i",
1726 iterator);
1727 status = iterator->methods.seek_beginning(iterator);
1728 BT_LOGD("User method returned: status=%s",
1729 bt_common_func_status_string(status));
1730 BT_ASSERT_POST(status == BT_FUNC_STATUS_OK ||
1731 status == BT_FUNC_STATUS_ERROR ||
1732 status == BT_FUNC_STATUS_MEMORY_ERROR ||
1733 status == BT_FUNC_STATUS_AGAIN,
1734 "Unexpected status: %![iter-]+i, status=%s",
1735 iterator, bt_common_func_status_string(status));
1736 if (status < 0) {
1737 BT_LIB_LOGW_APPEND_CAUSE(
1738 "Component input port message iterator's \"seek beginning\" method failed: "
1739 "%![iter-]+i, status=%s",
1740 iterator, bt_common_func_status_string(status));
1741 }
1742
1743 switch (status) {
1744 case BT_FUNC_STATUS_OK:
1745 break;
1746 case BT_FUNC_STATUS_ERROR:
1747 case BT_FUNC_STATUS_MEMORY_ERROR:
1748 case BT_FUNC_STATUS_AGAIN:
1749 goto end;
1750 default:
1751 bt_common_abort();
1752 }
1753
1754 /*
1755 * Find the first message which has a default clock
1756 * snapshot greater than or equal to the requested
1757 * seeking time, and move the received messages from
1758 * this point in the batch to this iterator's auto-seek
1759 * message queue.
1760 */
1761 while (!g_queue_is_empty(iterator->auto_seek.msgs)) {
1762 bt_object_put_ref_no_null_check(
1763 g_queue_pop_tail(iterator->auto_seek.msgs));
1764 }
1765
1766 stream_states = create_auto_seek_stream_states();
1767 if (!stream_states) {
1768 BT_LIB_LOGE_APPEND_CAUSE(
1769 "Failed to allocate one GHashTable.");
1770 status = BT_FUNC_STATUS_MEMORY_ERROR;
1771 goto end;
1772 }
1773
1774 status = find_message_ge_ns_from_origin(iterator,
1775 ns_from_origin, stream_states);
1776 switch (status) {
1777 case BT_FUNC_STATUS_OK:
1778 case BT_FUNC_STATUS_END:
1779 {
1780 GHashTableIter iter;
1781 gpointer key, value;
1782
1783 /*
1784 * If some streams exist at the seek time, prepend the
1785 * required messages to put those streams in the right
1786 * state.
1787 */
1788 g_hash_table_iter_init(&iter, stream_states);
1789 while (g_hash_table_iter_next (&iter, &key, &value)) {
1790 const bt_stream *stream = key;
1791 struct auto_seek_stream_state *stream_state =
1792 (struct auto_seek_stream_state *) value;
1793 bt_message *msg;
1794 const bt_clock_class *clock_class = bt_stream_class_borrow_default_clock_class_const(
1795 bt_stream_borrow_class_const(stream));
1796 /* Initialize to silence maybe-uninitialized warning. */
1797 uint64_t raw_value = 0;
1798
1799 /*
1800 * If we haven't seen a message with a clock snapshot, we don't know if our seek time is within
1801 * the clock's range, so it wouldn't be safe to try to convert ns_from_origin to a clock value.
1802 *
1803 * Also, it would be a bit of a lie to generate a stream begin message with the seek time as its
1804 * clock snapshot, because we don't really know if the stream existed at that time. If we have
1805 * seen a message with a clock snapshot in our seeking, then we are sure that the
1806 * seek time is not below the clock range, and we know the stream was active at that
1807 * time (and that we cut it short).
1808 */
1809 if (stream_state->seen_clock_snapshot) {
1810 if (clock_raw_value_from_ns_from_origin(clock_class, ns_from_origin, &raw_value) != 0) {
1811 BT_LIB_LOGW("Could not convert nanoseconds from origin to clock value: ns-from-origin=%" PRId64 ", %![cc-]+K",
1812 ns_from_origin, clock_class);
1813 status = BT_FUNC_STATUS_ERROR;
1814 goto end;
1815 }
1816 }
1817
1818 switch (stream_state->state) {
1819 case AUTO_SEEK_STREAM_STATE_PACKET_BEGAN:
1820 BT_ASSERT(stream_state->packet);
1821 BT_LIB_LOGD("Creating packet message: %![packet-]+a", stream_state->packet);
1822
1823 if (stream->class->packets_have_beginning_default_clock_snapshot) {
1824 /*
1825 * If we are in the PACKET_BEGAN state, it means we have seen a "packet beginning"
1826 * message. If "packet beginning" packets have clock snapshots, then we must have
1827 * seen a clock snapshot.
1828 */
1829 BT_ASSERT(stream_state->seen_clock_snapshot);
1830
1831 msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
1832 (bt_self_message_iterator *) iterator, stream_state->packet, raw_value);
1833 } else {
1834 msg = bt_message_packet_beginning_create((bt_self_message_iterator *) iterator,
1835 stream_state->packet);
1836 }
1837
1838 if (!msg) {
1839 status = BT_FUNC_STATUS_MEMORY_ERROR;
1840 goto end;
1841 }
1842
1843 g_queue_push_head(iterator->auto_seek.msgs, msg);
1844 msg = NULL;
1845 /* fall-thru */
1846
1847 case AUTO_SEEK_STREAM_STATE_STREAM_BEGAN:
1848 msg = bt_message_stream_beginning_create(
1849 (bt_self_message_iterator *) iterator, stream);
1850 if (!msg) {
1851 status = BT_FUNC_STATUS_MEMORY_ERROR;
1852 goto end;
1853 }
1854
1855 if (stream_state->seen_clock_snapshot) {
1856 bt_message_stream_beginning_set_default_clock_snapshot(msg, raw_value);
1857 }
1858
1859 g_queue_push_head(iterator->auto_seek.msgs, msg);
1860 msg = NULL;
1861 break;
1862 }
1863 }
1864
1865 /*
1866 * If there are messages in the auto-seek
1867 * message queue, replace the user's "next"
1868 * method with a custom, temporary "next" method
1869 * which returns them.
1870 */
1871 if (!g_queue_is_empty(iterator->auto_seek.msgs)) {
1872 BT_ASSERT(!iterator->auto_seek.original_next_callback);
1873 iterator->auto_seek.original_next_callback = iterator->methods.next;
1874
1875 iterator->methods.next =
1876 (bt_message_iterator_next_method)
1877 post_auto_seek_next;
1878 }
1879
1880 /*
1881 * `BT_FUNC_STATUS_END` becomes
1882 * `BT_FUNC_STATUS_OK`: the next
1883 * time this iterator's "next" method is called,
1884 * it will return
1885 * `BT_FUNC_STATUS_END`.
1886 */
1887 status = BT_FUNC_STATUS_OK;
1888 break;
1889 }
1890 case BT_FUNC_STATUS_ERROR:
1891 case BT_FUNC_STATUS_MEMORY_ERROR:
1892 case BT_FUNC_STATUS_AGAIN:
1893 goto end;
1894 default:
1895 bt_common_abort();
1896 }
1897 }
1898
1899 /*
1900 * The following messages returned by the next method (including
1901 * post_auto_seek_next) must be after (or at) `ns_from_origin`.
1902 */
1903 iterator->last_ns_from_origin = ns_from_origin;
1904
1905 end:
1906 if (stream_states) {
1907 destroy_auto_seek_stream_states(stream_states);
1908 stream_states = NULL;
1909 }
1910
1911 set_iterator_state_after_seeking(iterator, status);
1912 return status;
1913 }
1914
1915 bt_bool bt_self_message_iterator_is_interrupted(
1916 const struct bt_self_message_iterator *self_msg_iter)
1917 {
1918 const struct bt_message_iterator *iterator =
1919 (const void *) self_msg_iter;
1920
1921 BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
1922 return (bt_bool) bt_graph_is_interrupted(iterator->graph);
1923 }
1924
1925 void bt_message_iterator_get_ref(
1926 const struct bt_message_iterator *iterator)
1927 {
1928 bt_object_get_ref(iterator);
1929 }
1930
1931 void bt_message_iterator_put_ref(
1932 const struct bt_message_iterator *iterator)
1933 {
1934 bt_object_put_ref(iterator);
1935 }
This page took 0.074061 seconds and 4 git commands to generate.