Logging: standardize logging tags
[babeltrace.git] / src / plugins / utils / trimmer / trimmer.c
CommitLineData
cab3f160 1/*
cab3f160 2 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7de0e49a 3 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
cab3f160
JG
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
350ad6c1 24#define BT_LOG_TAG "PLUGIN/FLT.UTILS.TRIMMER"
b4565e8b
PP
25#include "logging.h"
26
578e048b
MJ
27#include "compat/utc.h"
28#include "compat/time.h"
3fadfbc0 29#include <babeltrace2/babeltrace.h>
578e048b 30#include "common/common.h"
578e048b 31#include "common/assert.h"
7de0e49a
PP
32#include <stdint.h>
33#include <inttypes.h>
34#include <glib.h>
35
36#include "trimmer.h"
37
38#define NS_PER_S INT64_C(1000000000)
39
40static const char * const in_port_name = "in";
41
42struct trimmer_time {
43 unsigned int hour, minute, second, ns;
44};
45
46struct trimmer_bound {
47 /*
48 * Nanoseconds from origin, valid if `is_set` is set and
49 * `is_infinite` is false.
50 */
51 int64_t ns_from_origin;
52
53 /* True if this bound's full time (`ns_from_origin`) is set */
54 bool is_set;
55
56 /*
57 * True if this bound represents the infinity (negative or
58 * positive depending on which bound it is). If this is true,
59 * then we don't care about `ns_from_origin` above.
60 */
61 bool is_infinite;
62
63 /*
64 * This bound's time without the date; this time is used to set
65 * `ns_from_origin` once we know the date.
66 */
67 struct trimmer_time time;
68};
69
70struct trimmer_comp {
71 struct trimmer_bound begin, end;
72 bool is_gmt;
73};
74
75enum trimmer_iterator_state {
76 /*
77 * Find the first message's date and set the bounds's times
78 * accordingly.
79 */
80 TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN,
81
82 /*
83 * Initially seek to the trimming range's beginning time.
84 */
85 TRIMMER_ITERATOR_STATE_SEEK_INITIALLY,
86
87 /*
88 * Fill the output message queue for as long as received input
89 * messages are within the trimming time range.
90 */
91 TRIMMER_ITERATOR_STATE_TRIM,
92
93 /* Flush the remaining messages in the output message queue */
94 TRIMMER_ITERATOR_STATE_ENDING,
95
96 /* Trimming operation and message iterator is ended */
97 TRIMMER_ITERATOR_STATE_ENDED,
98};
99
100struct trimmer_iterator {
101 /* Weak */
102 struct trimmer_comp *trimmer_comp;
103
104 /* Weak */
105 bt_self_message_iterator *self_msg_iter;
106
107 enum trimmer_iterator_state state;
108
109 /* Owned by this */
110 bt_self_component_port_input_message_iterator *upstream_iter;
111 struct trimmer_bound begin, end;
112
113 /*
114 * Queue of `const bt_message *` (owned by the queue).
115 *
116 * This is where the trimming operation pushes the messages to
117 * output by this message iterator.
118 */
119 GQueue *output_messages;
120
121 /*
122 * Hash table of `bt_stream *` (weak) to
123 * `struct trimmer_iterator_stream_state *` (owned by the HT).
124 */
125 GHashTable *stream_states;
126};
127
128struct trimmer_iterator_stream_state {
129 /*
130 * True if both stream beginning and initial stream activity
131 * beginning messages were pushed for this stream.
132 */
133 bool inited;
134
135 /*
136 * True if the last pushed message for this stream was a stream
137 * activity end message.
138 */
139 bool last_msg_is_stream_activity_end;
140
141 /*
142 * Time to use for a generated stream end activity message when
143 * ending the stream.
144 */
145 int64_t stream_act_end_ns_from_origin;
146
147 /* Weak */
148 const bt_stream *stream;
149
150 /* Owned by this (`NULL` initially and between packets) */
151 const bt_packet *cur_packet;
152
153 /* Owned by this */
154 const bt_message *stream_beginning_msg;
155};
cab3f160
JG
156
157static
7de0e49a 158void destroy_trimmer_comp(struct trimmer_comp *trimmer_comp)
cab3f160 159{
7de0e49a
PP
160 BT_ASSERT(trimmer_comp);
161 g_free(trimmer_comp);
cab3f160
JG
162}
163
164static
7de0e49a
PP
165struct trimmer_comp *create_trimmer_comp(void)
166{
167 return g_new0(struct trimmer_comp, 1);
168}
169
170BT_HIDDEN
171void trimmer_finalize(bt_self_component_filter *self_comp)
cab3f160 172{
7de0e49a
PP
173 struct trimmer_comp *trimmer_comp =
174 bt_self_component_get_data(
175 bt_self_component_filter_as_self_component(self_comp));
176
177 if (trimmer_comp) {
178 destroy_trimmer_comp(trimmer_comp);
179 }
cab3f160
JG
180}
181
7de0e49a
PP
182/*
183 * Sets the time (in ns from origin) of a trimmer bound from date and
184 * time components.
185 *
186 * Returns a negative value if anything goes wrong.
187 */
188static
189int set_bound_ns_from_origin(struct trimmer_bound *bound,
190 unsigned int year, unsigned int month, unsigned int day,
191 unsigned int hour, unsigned int minute, unsigned int second,
192 unsigned int ns, bool is_gmt)
cab3f160 193{
7de0e49a
PP
194 int ret = 0;
195 time_t result;
196 struct tm tm = {
197 .tm_sec = second,
198 .tm_min = minute,
199 .tm_hour = hour,
200 .tm_mday = day,
201 .tm_mon = month - 1,
202 .tm_year = year - 1900,
203 .tm_isdst = -1,
204 };
205
206 if (is_gmt) {
207 result = bt_timegm(&tm);
208 } else {
209 result = mktime(&tm);
210 }
211
212 if (result < 0) {
213 ret = -1;
214 goto end;
215 }
cab3f160 216
7de0e49a
PP
217 BT_ASSERT(bound);
218 bound->ns_from_origin = (int64_t) result;
219 bound->ns_from_origin *= NS_PER_S;
220 bound->ns_from_origin += ns;
221 bound->is_set = true;
222
223end:
224 return ret;
cab3f160
JG
225}
226
528debdf
MD
227/*
228 * Parses a timestamp, figuring out its format.
229 *
230 * Returns a negative value if anything goes wrong.
231 *
232 * Expected formats:
233 *
7de0e49a
PP
234 * YYYY-MM-DD hh:mm[:ss[.ns]]
235 * [hh:mm:]ss[.ns]
236 * [-]s[.ns]
237 *
238 * TODO: Check overflows.
239 */
240static
241int set_bound_from_str(const char *str, struct trimmer_bound *bound,
242 bool is_gmt)
243{
244 int ret = 0;
245 int s_ret;
246 unsigned int year, month, day, hour, minute, second, ns;
247 char dummy;
248
249 /* Try `YYYY-MM-DD hh:mm:ss.ns` format */
250 s_ret = sscanf(str, "%u-%u-%u %u:%u:%u.%u%c", &year, &month, &day,
251 &hour, &minute, &second, &ns, &dummy);
252 if (s_ret == 7) {
253 ret = set_bound_ns_from_origin(bound, year, month, day,
254 hour, minute, second, ns, is_gmt);
255 goto end;
256 }
257
258 /* Try `YYYY-MM-DD hh:mm:ss` format */
259 s_ret = sscanf(str, "%u-%u-%u %u:%u:%u%c", &year, &month, &day,
260 &hour, &minute, &second, &dummy);
261 if (s_ret == 6) {
262 ret = set_bound_ns_from_origin(bound, year, month, day,
263 hour, minute, second, 0, is_gmt);
264 goto end;
265 }
266
267 /* Try `YYYY-MM-DD hh:mm` format */
268 s_ret = sscanf(str, "%u-%u-%u %u:%u%c", &year, &month, &day,
269 &hour, &minute, &dummy);
270 if (s_ret == 5) {
271 ret = set_bound_ns_from_origin(bound, year, month, day,
272 hour, minute, 0, 0, is_gmt);
273 goto end;
274 }
275
276 /* Try `YYYY-MM-DD` format */
277 s_ret = sscanf(str, "%u-%u-%u%c", &year, &month, &day, &dummy);
278 if (s_ret == 3) {
279 ret = set_bound_ns_from_origin(bound, year, month, day,
280 0, 0, 0, 0, is_gmt);
281 goto end;
282 }
283
284 /* Try `hh:mm:ss.ns` format */
285 s_ret = sscanf(str, "%u:%u:%u.%u%c", &hour, &minute, &second, &ns,
286 &dummy);
287 if (s_ret == 4) {
288 bound->time.hour = hour;
289 bound->time.minute = minute;
290 bound->time.second = second;
291 bound->time.ns = ns;
292 goto end;
293 }
294
295 /* Try `hh:mm:ss` format */
296 s_ret = sscanf(str, "%u:%u:%u%c", &hour, &minute, &second, &dummy);
297 if (s_ret == 3) {
298 bound->time.hour = hour;
299 bound->time.minute = minute;
300 bound->time.second = second;
301 bound->time.ns = 0;
302 goto end;
303 }
304
305 /* Try `-s.ns` format */
306 s_ret = sscanf(str, "-%u.%u%c", &second, &ns, &dummy);
307 if (s_ret == 2) {
308 bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
309 bound->ns_from_origin -= (int64_t) ns;
310 bound->is_set = true;
311 goto end;
312 }
313
314 /* Try `s.ns` format */
315 s_ret = sscanf(str, "%u.%u%c", &second, &ns, &dummy);
316 if (s_ret == 2) {
317 bound->ns_from_origin = ((int64_t) second) * NS_PER_S;
318 bound->ns_from_origin += (int64_t) ns;
319 bound->is_set = true;
320 goto end;
321 }
322
323 /* Try `-s` format */
324 s_ret = sscanf(str, "-%u%c", &second, &dummy);
325 if (s_ret == 1) {
326 bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
327 bound->is_set = true;
328 goto end;
329 }
330
331 /* Try `s` format */
332 s_ret = sscanf(str, "%u%c", &second, &dummy);
333 if (s_ret == 1) {
334 bound->ns_from_origin = (int64_t) second * NS_PER_S;
335 bound->is_set = true;
336 goto end;
337 }
338
339 BT_LOGE("Invalid date/time format: param=\"%s\"", str);
340 ret = -1;
341
342end:
343 return ret;
344}
345
346/*
347 * Sets a trimmer bound's properties from a parameter string/integer
348 * value.
349 *
350 * Returns a negative value if anything goes wrong.
528debdf 351 */
44d3cbf0 352static
7de0e49a
PP
353int set_bound_from_param(const char *param_name, const bt_value *param,
354 struct trimmer_bound *bound, bool is_gmt)
528debdf
MD
355{
356 int ret;
268fae9a 357 const char *arg;
7de0e49a 358 char tmp_arg[64];
268fae9a 359
fdd3a2da
PP
360 if (bt_value_is_signed_integer(param)) {
361 int64_t value = bt_value_signed_integer_get(param);
7de0e49a
PP
362
363 /*
364 * Just convert it to a temporary string to handle
365 * everything the same way.
366 */
367 sprintf(tmp_arg, "%" PRId64, value);
368 arg = tmp_arg;
369 } else if (bt_value_is_string(param)) {
370 arg = bt_value_string_get(param);
371 } else {
268fae9a
PP
372 BT_LOGE("`%s` parameter must be an integer or a string value.",
373 param_name);
7de0e49a
PP
374 ret = -1;
375 goto end;
268fae9a
PP
376 }
377
7de0e49a
PP
378 ret = set_bound_from_str(arg, bound, is_gmt);
379
380end:
381 return ret;
382}
383
384static
385int validate_trimmer_bounds(struct trimmer_bound *begin,
386 struct trimmer_bound *end)
387{
388 int ret = 0;
389
390 BT_ASSERT(begin->is_set);
391 BT_ASSERT(end->is_set);
392
393 if (!begin->is_infinite && !end->is_infinite &&
394 begin->ns_from_origin > end->ns_from_origin) {
395 BT_LOGE("Trimming time range's beginning time is greater than end time: "
396 "begin-ns-from-origin=%" PRId64 ", "
397 "end-ns-from-origin=%" PRId64,
398 begin->ns_from_origin,
399 end->ns_from_origin);
400 ret = -1;
401 goto end;
528debdf
MD
402 }
403
7de0e49a
PP
404 if (!begin->is_infinite && begin->ns_from_origin == INT64_MIN) {
405 BT_LOGE("Invalid trimming time range's beginning time: "
406 "ns-from-origin=%" PRId64,
407 begin->ns_from_origin);
408 ret = -1;
409 goto end;
410 }
528debdf 411
7de0e49a
PP
412 if (!end->is_infinite && end->ns_from_origin == INT64_MIN) {
413 BT_LOGE("Invalid trimming time range's end time: "
414 "ns-from-origin=%" PRId64,
415 end->ns_from_origin);
416 ret = -1;
417 goto end;
418 }
528debdf 419
7de0e49a
PP
420end:
421 return ret;
528debdf
MD
422}
423
424static
7de0e49a
PP
425int init_trimmer_comp_from_params(struct trimmer_comp *trimmer_comp,
426 const bt_value *params)
44d3cbf0 427{
7de0e49a
PP
428 const bt_value *value;
429 int ret = 0;
44d3cbf0 430
f6ccaed9 431 BT_ASSERT(params);
7de0e49a 432 value = bt_value_map_borrow_entry_value_const(params, "gmt");
528debdf 433 if (value) {
7de0e49a 434 trimmer_comp->is_gmt = (bool) bt_value_bool_get(value);
528debdf
MD
435 }
436
7de0e49a 437 value = bt_value_map_borrow_entry_value_const(params, "begin");
528debdf 438 if (value) {
7de0e49a
PP
439 if (set_bound_from_param("begin", value,
440 &trimmer_comp->begin, trimmer_comp->is_gmt)) {
441 /* set_bound_from_param() logs errors */
442 ret = BT_SELF_COMPONENT_STATUS_ERROR;
268fae9a 443 goto end;
44d3cbf0 444 }
7de0e49a
PP
445 } else {
446 trimmer_comp->begin.is_infinite = true;
447 trimmer_comp->begin.is_set = true;
44d3cbf0 448 }
528debdf 449
7de0e49a 450 value = bt_value_map_borrow_entry_value_const(params, "end");
528debdf 451 if (value) {
7de0e49a
PP
452 if (set_bound_from_param("end", value,
453 &trimmer_comp->end, trimmer_comp->is_gmt)) {
454 /* set_bound_from_param() logs errors */
455 ret = BT_SELF_COMPONENT_STATUS_ERROR;
268fae9a 456 goto end;
528debdf 457 }
7de0e49a
PP
458 } else {
459 trimmer_comp->end.is_infinite = true;
460 trimmer_comp->end.is_set = true;
528debdf 461 }
268fae9a 462
528debdf 463end:
7de0e49a
PP
464 if (trimmer_comp->begin.is_set && trimmer_comp->end.is_set) {
465 /* validate_trimmer_bounds() logs errors */
466 ret = validate_trimmer_bounds(&trimmer_comp->begin,
467 &trimmer_comp->end);
55595636 468 }
7de0e49a 469
528debdf 470 return ret;
44d3cbf0
JG
471}
472
7de0e49a
PP
473bt_self_component_status trimmer_init(bt_self_component_filter *self_comp,
474 const bt_value *params, void *init_data)
cab3f160 475{
7de0e49a
PP
476 int ret;
477 bt_self_component_status status;
478 struct trimmer_comp *trimmer_comp = create_trimmer_comp();
cab3f160 479
7de0e49a 480 if (!trimmer_comp) {
8dad9b32 481 status = BT_SELF_COMPONENT_STATUS_NOMEM;
7de0e49a 482 goto error;
cab3f160
JG
483 }
484
7de0e49a
PP
485 status = bt_self_component_filter_add_input_port(
486 self_comp, in_port_name, NULL, NULL);
487 if (status != BT_SELF_COMPONENT_STATUS_OK) {
b9d103be
PP
488 goto error;
489 }
490
7de0e49a
PP
491 status = bt_self_component_filter_add_output_port(
492 self_comp, "out", NULL, NULL);
493 if (status != BT_SELF_COMPONENT_STATUS_OK) {
b9d103be
PP
494 goto error;
495 }
496
7de0e49a
PP
497 ret = init_trimmer_comp_from_params(trimmer_comp, params);
498 if (ret) {
8dad9b32 499 status = BT_SELF_COMPONENT_STATUS_ERROR;
cab3f160
JG
500 goto error;
501 }
502
7de0e49a
PP
503 bt_self_component_set_data(
504 bt_self_component_filter_as_self_component(self_comp),
505 trimmer_comp);
506 goto end;
507
508error:
509 if (status == BT_SELF_COMPONENT_STATUS_OK) {
510 status = BT_SELF_COMPONENT_STATUS_ERROR;
511 }
512
513 if (trimmer_comp) {
514 destroy_trimmer_comp(trimmer_comp);
515 }
516
cab3f160 517end:
8dad9b32 518 return status;
7de0e49a
PP
519}
520
521static
522void destroy_trimmer_iterator(struct trimmer_iterator *trimmer_it)
523{
524 BT_ASSERT(trimmer_it);
525 bt_self_component_port_input_message_iterator_put_ref(
526 trimmer_it->upstream_iter);
527
528 if (trimmer_it->output_messages) {
529 g_queue_free(trimmer_it->output_messages);
530 }
531
532 if (trimmer_it->stream_states) {
533 g_hash_table_destroy(trimmer_it->stream_states);
534 }
535
536 g_free(trimmer_it);
537}
538
539static
540void destroy_trimmer_iterator_stream_state(
541 struct trimmer_iterator_stream_state *sstate)
542{
543 BT_ASSERT(sstate);
544 BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
545 BT_MESSAGE_PUT_REF_AND_RESET(sstate->stream_beginning_msg);
546 g_free(sstate);
547}
548
549BT_HIDDEN
550bt_self_message_iterator_status trimmer_msg_iter_init(
551 bt_self_message_iterator *self_msg_iter,
552 bt_self_component_filter *self_comp,
553 bt_self_component_port_output *port)
554{
555 bt_self_message_iterator_status status =
556 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
557 struct trimmer_iterator *trimmer_it;
558
559 trimmer_it = g_new0(struct trimmer_iterator, 1);
560 if (!trimmer_it) {
561 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
562 goto end;
563 }
564
565 trimmer_it->trimmer_comp = bt_self_component_get_data(
566 bt_self_component_filter_as_self_component(self_comp));
567 BT_ASSERT(trimmer_it->trimmer_comp);
568
569 if (trimmer_it->trimmer_comp->begin.is_set &&
570 trimmer_it->trimmer_comp->end.is_set) {
571 /*
572 * Both trimming time range's bounds are set, so skip
573 * the
574 * `TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN`
575 * phase.
576 */
577 trimmer_it->state = TRIMMER_ITERATOR_STATE_SEEK_INITIALLY;
578 }
579
580 trimmer_it->begin = trimmer_it->trimmer_comp->begin;
581 trimmer_it->end = trimmer_it->trimmer_comp->end;
582 trimmer_it->upstream_iter =
583 bt_self_component_port_input_message_iterator_create(
584 bt_self_component_filter_borrow_input_port_by_name(
585 self_comp, in_port_name));
586 if (!trimmer_it->upstream_iter) {
587 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
588 goto end;
589 }
590
591 trimmer_it->output_messages = g_queue_new();
592 if (!trimmer_it->output_messages) {
593 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
594 goto end;
595 }
596
597 trimmer_it->stream_states = g_hash_table_new_full(g_direct_hash,
598 g_direct_equal, NULL,
599 (GDestroyNotify) destroy_trimmer_iterator_stream_state);
600 if (!trimmer_it->stream_states) {
601 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
602 goto end;
603 }
604
605 trimmer_it->self_msg_iter = self_msg_iter;
606 bt_self_message_iterator_set_data(self_msg_iter, trimmer_it);
607
608end:
609 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK && trimmer_it) {
610 destroy_trimmer_iterator(trimmer_it);
611 }
612
613 return status;
614}
615
616static inline
617int get_msg_ns_from_origin(const bt_message *msg, int64_t *ns_from_origin,
618 bool *skip)
619{
620 const bt_clock_class *clock_class = NULL;
621 const bt_clock_snapshot *clock_snapshot = NULL;
7de0e49a
PP
622 bt_message_stream_activity_clock_snapshot_state sa_cs_state;
623 int ret = 0;
624
625 BT_ASSERT(msg);
626 BT_ASSERT(ns_from_origin);
627 BT_ASSERT(skip);
628
629 switch (bt_message_get_type(msg)) {
630 case BT_MESSAGE_TYPE_EVENT:
631 clock_class =
632 bt_message_event_borrow_stream_class_default_clock_class_const(
633 msg);
91d81473 634 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
635 goto error;
636 }
637
0cbc2c33
PP
638 clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
639 msg);
7de0e49a
PP
640 break;
641 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
642 clock_class =
643 bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
644 msg);
91d81473 645 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
646 goto error;
647 }
648
0cbc2c33
PP
649 clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
650 msg);
7de0e49a
PP
651 break;
652 case BT_MESSAGE_TYPE_PACKET_END:
653 clock_class =
654 bt_message_packet_end_borrow_stream_class_default_clock_class_const(
655 msg);
91d81473 656 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
657 goto error;
658 }
659
0cbc2c33
PP
660 clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
661 msg);
7de0e49a
PP
662 break;
663 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
664 clock_class =
665 bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
666 msg);
91d81473 667 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
668 goto error;
669 }
670
9b24b6aa 671 clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
0cbc2c33 672 msg);
7de0e49a
PP
673 break;
674 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
675 clock_class =
676 bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
677 msg);
91d81473 678 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
679 goto error;
680 }
681
9b24b6aa 682 clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
0cbc2c33 683 msg);
7de0e49a
PP
684 break;
685 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
686 clock_class =
687 bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
688 msg);
91d81473 689 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
690 goto error;
691 }
692
693 sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
694 msg, &clock_snapshot);
695 if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN ||
696 sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
697 /* Lowest possible time to always include them */
698 *ns_from_origin = INT64_MIN;
699 goto no_clock_snapshot;
700 }
701
702 break;
703 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
704 clock_class =
705 bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
706 msg);
91d81473 707 if (G_UNLIKELY(!clock_class)) {
7de0e49a
PP
708 goto error;
709 }
710
711 sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
712 msg, &clock_snapshot);
713 if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN) {
714 /* Lowest time to always include it */
715 *ns_from_origin = INT64_MIN;
716 goto no_clock_snapshot;
717 } else if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
718 /* Greatest time to always exclude it */
719 *ns_from_origin = INT64_MAX;
720 goto no_clock_snapshot;
721 }
722
723 break;
724 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
0cbc2c33 725 clock_snapshot =
7de0e49a 726 bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
0cbc2c33 727 msg);
7de0e49a
PP
728 break;
729 default:
730 goto no_clock_snapshot;
731 }
732
7de0e49a
PP
733 ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot,
734 ns_from_origin);
91d81473 735 if (G_UNLIKELY(ret)) {
7de0e49a
PP
736 goto error;
737 }
738
739 goto end;
740
741no_clock_snapshot:
742 *skip = true;
743 goto end;
744
cab3f160 745error:
7de0e49a
PP
746 ret = -1;
747
748end:
749 return ret;
750}
751
752static inline
753void put_messages(bt_message_array_const msgs, uint64_t count)
754{
755 uint64_t i;
756
757 for (i = 0; i < count; i++) {
758 BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
759 }
760}
761
762static inline
763int set_trimmer_iterator_bound(struct trimmer_bound *bound,
764 int64_t ns_from_origin, bool is_gmt)
765{
766 struct tm tm;
767 time_t time_seconds = (time_t) (ns_from_origin / NS_PER_S);
768 int ret = 0;
769
770 BT_ASSERT(!bound->is_set);
771 errno = 0;
772
773 /* We only need to extract the date from this time */
774 if (is_gmt) {
775 bt_gmtime_r(&time_seconds, &tm);
776 } else {
777 bt_localtime_r(&time_seconds, &tm);
778 }
779
780 if (errno) {
781 BT_LOGE_ERRNO("Cannot convert timestamp to date and time",
782 "ts=%" PRId64, (int64_t) time_seconds);
783 ret = -1;
784 goto end;
785 }
786
787 ret = set_bound_ns_from_origin(bound, tm.tm_year + 1900, tm.tm_mon + 1,
788 tm.tm_mday, bound->time.hour, bound->time.minute,
789 bound->time.second, bound->time.ns, is_gmt);
790
791end:
cab3f160
JG
792 return ret;
793}
7de0e49a
PP
794
795static
796bt_self_message_iterator_status state_set_trimmer_iterator_bounds(
797 struct trimmer_iterator *trimmer_it)
798{
799 bt_message_iterator_status upstream_iter_status =
800 BT_MESSAGE_ITERATOR_STATUS_OK;
801 struct trimmer_comp *trimmer_comp = trimmer_it->trimmer_comp;
802 bt_message_array_const msgs;
803 uint64_t count = 0;
804 int64_t ns_from_origin = INT64_MIN;
805 uint64_t i;
806 int ret;
807
808 BT_ASSERT(!trimmer_it->begin.is_set ||
809 !trimmer_it->end.is_set);
810
811 while (true) {
812 upstream_iter_status =
813 bt_self_component_port_input_message_iterator_next(
814 trimmer_it->upstream_iter, &msgs, &count);
815 if (upstream_iter_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
816 goto end;
817 }
818
819 for (i = 0; i < count; i++) {
820 const bt_message *msg = msgs[i];
821 bool skip = false;
822 int ret;
823
824 ret = get_msg_ns_from_origin(msg, &ns_from_origin,
825 &skip);
826 if (ret) {
827 goto error;
828 }
829
830 if (skip) {
831 continue;
832 }
833
834 BT_ASSERT(ns_from_origin != INT64_MIN &&
835 ns_from_origin != INT64_MAX);
836 put_messages(msgs, count);
837 goto found;
838 }
839
840 put_messages(msgs, count);
841 }
842
843found:
844 if (!trimmer_it->begin.is_set) {
845 BT_ASSERT(!trimmer_it->begin.is_infinite);
846 ret = set_trimmer_iterator_bound(&trimmer_it->begin,
847 ns_from_origin, trimmer_comp->is_gmt);
848 if (ret) {
849 goto error;
850 }
851 }
852
853 if (!trimmer_it->end.is_set) {
854 BT_ASSERT(!trimmer_it->end.is_infinite);
855 ret = set_trimmer_iterator_bound(&trimmer_it->end,
856 ns_from_origin, trimmer_comp->is_gmt);
857 if (ret) {
858 goto error;
859 }
860 }
861
862 ret = validate_trimmer_bounds(&trimmer_it->begin,
863 &trimmer_it->end);
864 if (ret) {
865 goto error;
866 }
867
868 goto end;
869
870error:
871 put_messages(msgs, count);
872 upstream_iter_status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
873
874end:
875 return (int) upstream_iter_status;
876}
877
878static
879bt_self_message_iterator_status state_seek_initially(
880 struct trimmer_iterator *trimmer_it)
881{
882 bt_self_message_iterator_status status =
883 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
884
885 BT_ASSERT(trimmer_it->begin.is_set);
886
887 if (trimmer_it->begin.is_infinite) {
888 if (!bt_self_component_port_input_message_iterator_can_seek_beginning(
889 trimmer_it->upstream_iter)) {
890 BT_LOGE_STR("Cannot make upstream message iterator initially seek its beginning.");
419f470d 891 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
7de0e49a
PP
892 goto end;
893 }
894
895 status = (int) bt_self_component_port_input_message_iterator_seek_beginning(
896 trimmer_it->upstream_iter);
897 } else {
898 if (!bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
899 trimmer_it->upstream_iter,
900 trimmer_it->begin.ns_from_origin)) {
901 BT_LOGE("Cannot make upstream message iterator initially seek: "
902 "seek-ns-from-origin=%" PRId64,
903 trimmer_it->begin.ns_from_origin);
419f470d 904 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
7de0e49a
PP
905 goto end;
906 }
907
908 status = (int) bt_self_component_port_input_message_iterator_seek_ns_from_origin(
909 trimmer_it->upstream_iter, trimmer_it->begin.ns_from_origin);
910 }
911
912 if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
913 trimmer_it->state = TRIMMER_ITERATOR_STATE_TRIM;
914 }
915
916end:
917 return status;
918}
919
920static inline
921void push_message(struct trimmer_iterator *trimmer_it, const bt_message *msg)
922{
923 g_queue_push_head(trimmer_it->output_messages, (void *) msg);
924}
925
926static inline
927const bt_message *pop_message(struct trimmer_iterator *trimmer_it)
928{
929 return g_queue_pop_tail(trimmer_it->output_messages);
930}
931
932static inline
933int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
934 int64_t ns_from_origin, uint64_t *raw_value)
935{
936
937 int64_t cc_offset_s;
938 uint64_t cc_offset_cycles;
939 uint64_t cc_freq;
940
941 bt_clock_class_get_offset(clock_class, &cc_offset_s, &cc_offset_cycles);
942 cc_freq = bt_clock_class_get_frequency(clock_class);
943 return bt_common_clock_value_from_ns_from_origin(cc_offset_s,
944 cc_offset_cycles, cc_freq, ns_from_origin, raw_value);
945}
946
947static inline
948bt_self_message_iterator_status end_stream(struct trimmer_iterator *trimmer_it,
949 struct trimmer_iterator_stream_state *sstate)
950{
951 bt_self_message_iterator_status status =
952 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
953 uint64_t raw_value;
954 const bt_clock_class *clock_class;
955 int ret;
956 bt_message *msg = NULL;
957
958 BT_ASSERT(!trimmer_it->end.is_infinite);
959
960 if (!sstate->stream) {
961 goto end;
962 }
963
964 if (sstate->cur_packet) {
965 /*
966 * The last message could not have been a stream
967 * activity end message if we have a current packet.
968 */
969 BT_ASSERT(!sstate->last_msg_is_stream_activity_end);
970
971 /*
972 * Create and push a packet end message, making its time
973 * the trimming range's end time.
974 */
975 clock_class = bt_stream_class_borrow_default_clock_class_const(
976 bt_stream_borrow_class_const(sstate->stream));
977 BT_ASSERT(clock_class);
978 ret = clock_raw_value_from_ns_from_origin(clock_class,
979 trimmer_it->end.ns_from_origin, &raw_value);
980 if (ret) {
981 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
982 goto end;
983 }
984
985 msg = bt_message_packet_end_create_with_default_clock_snapshot(
986 trimmer_it->self_msg_iter, sstate->cur_packet,
987 raw_value);
988 if (!msg) {
989 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
990 goto end;
991 }
992
993 push_message(trimmer_it, msg);
994 msg = NULL;
995 BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
996
997 /*
998 * Because we generated a packet end message, set the
999 * stream activity end message's time to use to the
1000 * trimming range's end time (this packet end message's
1001 * time).
1002 */
1003 sstate->stream_act_end_ns_from_origin =
1004 trimmer_it->end.ns_from_origin;
1005 }
1006
1007 if (!sstate->last_msg_is_stream_activity_end) {
1008 /* Create and push a stream activity end message */
1009 msg = bt_message_stream_activity_end_create(
1010 trimmer_it->self_msg_iter, sstate->stream);
1011 if (!msg) {
1012 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1013 goto end;
1014 }
1015
1016 clock_class = bt_stream_class_borrow_default_clock_class_const(
1017 bt_stream_borrow_class_const(sstate->stream));
1018 BT_ASSERT(clock_class);
cb179cb6
PP
1019
1020 if (sstate->stream_act_end_ns_from_origin == INT64_MIN) {
1021 /*
1022 * We received at least what is necessary to
1023 * have a stream state (stream beginning and
1024 * stream activity beginning messages), but
1025 * nothing else: use the trimmer range's end
1026 * time.
1027 */
1028 sstate->stream_act_end_ns_from_origin =
1029 trimmer_it->end.ns_from_origin;
1030 }
1031
7de0e49a
PP
1032 ret = clock_raw_value_from_ns_from_origin(clock_class,
1033 sstate->stream_act_end_ns_from_origin, &raw_value);
1034 if (ret) {
1035 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1036 goto end;
1037 }
1038
1039 bt_message_stream_activity_end_set_default_clock_snapshot(
1040 msg, raw_value);
1041 push_message(trimmer_it, msg);
1042 msg = NULL;
1043 }
1044
1045 /* Create and push a stream end message */
1046 msg = bt_message_stream_end_create(trimmer_it->self_msg_iter,
1047 sstate->stream);
1048 if (!msg) {
1049 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1050 goto end;
1051 }
1052
1053 push_message(trimmer_it, msg);
1054 msg = NULL;
1055
1056 /*
1057 * Just to make sure that we don't use this stream state again
1058 * in the future without an obvious error.
1059 */
1060 sstate->stream = NULL;
1061
1062end:
1063 bt_message_put_ref(msg);
1064 return status;
1065}
1066
1067static inline
1068bt_self_message_iterator_status end_iterator_streams(
1069 struct trimmer_iterator *trimmer_it)
1070{
1071 bt_self_message_iterator_status status =
1072 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1073 GHashTableIter iter;
1074 gpointer key, sstate;
1075
1076 if (trimmer_it->end.is_infinite) {
1077 /*
1078 * An infinite trimming range's end time guarantees that
1079 * we received (and pushed) all the appropriate end
1080 * messages.
1081 */
1082 goto remove_all;
1083 }
1084
1085 /*
1086 * End each stream and then remove them from the hash table of
1087 * stream states to release unneeded references.
1088 */
1089 g_hash_table_iter_init(&iter, trimmer_it->stream_states);
1090
1091 while (g_hash_table_iter_next(&iter, &key, &sstate)) {
1092 status = end_stream(trimmer_it, sstate);
1093 if (status) {
1094 goto end;
1095 }
1096 }
1097
1098remove_all:
1099 g_hash_table_remove_all(trimmer_it->stream_states);
1100
1101end:
1102 return status;
1103}
1104
1105static inline
1106bt_self_message_iterator_status create_stream_beginning_activity_message(
1107 struct trimmer_iterator *trimmer_it,
1108 const bt_stream *stream,
1109 const bt_clock_class *clock_class, bt_message **msg)
1110{
75a15167 1111 bt_message *local_msg;
7de0e49a
PP
1112 bt_self_message_iterator_status status =
1113 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1114
1115 BT_ASSERT(msg);
1116 BT_ASSERT(!trimmer_it->begin.is_infinite);
1117
75a15167 1118 local_msg = bt_message_stream_activity_beginning_create(
7de0e49a 1119 trimmer_it->self_msg_iter, stream);
75a15167 1120 if (!local_msg) {
7de0e49a
PP
1121 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1122 goto end;
1123 }
1124
1125 if (clock_class) {
1126 int ret;
1127 uint64_t raw_value;
1128
1129 ret = clock_raw_value_from_ns_from_origin(clock_class,
1130 trimmer_it->begin.ns_from_origin, &raw_value);
1131 if (ret) {
1132 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
75a15167 1133 bt_message_put_ref(local_msg);
7de0e49a
PP
1134 goto end;
1135 }
1136
1137 bt_message_stream_activity_beginning_set_default_clock_snapshot(
75a15167 1138 local_msg, raw_value);
7de0e49a
PP
1139 }
1140
75a15167
FD
1141 BT_MESSAGE_MOVE_REF(*msg, local_msg);
1142
7de0e49a
PP
1143end:
1144 return status;
1145}
1146
1147/*
1148 * Makes sure to initialize a stream state, pushing the appropriate
1149 * initial messages.
1150 *
1151 * `stream_act_beginning_msg` is an initial stream activity beginning
1152 * message to potentially use, depending on its clock snapshot state.
1153 * This function consumes `stream_act_beginning_msg` unconditionally.
1154 */
1155static inline
1156bt_self_message_iterator_status ensure_stream_state_is_inited(
1157 struct trimmer_iterator *trimmer_it,
1158 struct trimmer_iterator_stream_state *sstate,
1159 const bt_message *stream_act_beginning_msg)
1160{
1161 bt_self_message_iterator_status status =
1162 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1163 bt_message *new_msg = NULL;
1164 const bt_clock_class *clock_class =
1165 bt_stream_class_borrow_default_clock_class_const(
1166 bt_stream_borrow_class_const(sstate->stream));
1167
1168 BT_ASSERT(!sstate->inited);
1169
1170 if (!sstate->stream_beginning_msg) {
1171 /* No initial stream beginning message: create one */
1172 sstate->stream_beginning_msg =
1173 bt_message_stream_beginning_create(
1174 trimmer_it->self_msg_iter, sstate->stream);
1175 if (!sstate->stream_beginning_msg) {
1176 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1177 goto end;
1178 }
1179 }
1180
1181 /* Push initial stream beginning message */
1182 BT_ASSERT(sstate->stream_beginning_msg);
1183 push_message(trimmer_it, sstate->stream_beginning_msg);
1184 sstate->stream_beginning_msg = NULL;
1185
1186 if (stream_act_beginning_msg) {
1187 /*
1188 * Initial stream activity beginning message exists: if
1189 * its time is -inf, then create and push a new one
1190 * having the trimming range's beginning time. Otherwise
1191 * push it as is (known and unknown).
1192 */
1193 const bt_clock_snapshot *cs;
1194 bt_message_stream_activity_clock_snapshot_state sa_cs_state;
1195
1196 sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
1197 stream_act_beginning_msg, &cs);
1198 if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE &&
1199 !trimmer_it->begin.is_infinite) {
1200 /*
1201 * -inf time: use trimming range's beginning
1202 * time (which is not -inf).
1203 */
1204 status = create_stream_beginning_activity_message(
1205 trimmer_it, sstate->stream, clock_class,
1206 &new_msg);
1207 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1208 goto end;
1209 }
1210
1211 push_message(trimmer_it, new_msg);
1212 new_msg = NULL;
1213 } else {
1214 /* Known/unknown: push as is */
1215 push_message(trimmer_it, stream_act_beginning_msg);
1216 stream_act_beginning_msg = NULL;
1217 }
1218 } else {
1219 BT_ASSERT(!trimmer_it->begin.is_infinite);
1220
1221 /*
1222 * No stream beginning activity message: create and push
1223 * a new message.
1224 */
1225 status = create_stream_beginning_activity_message(
1226 trimmer_it, sstate->stream, clock_class, &new_msg);
1227 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1228 goto end;
1229 }
1230
1231 push_message(trimmer_it, new_msg);
1232 new_msg = NULL;
1233 }
1234
1235 sstate->inited = true;
1236
1237end:
1238 bt_message_put_ref(new_msg);
1239 bt_message_put_ref(stream_act_beginning_msg);
1240 return status;
1241}
1242
1243static inline
1244bt_self_message_iterator_status ensure_cur_packet_exists(
1245 struct trimmer_iterator *trimmer_it,
1246 struct trimmer_iterator_stream_state *sstate,
1247 const bt_packet *packet)
1248{
1249 bt_self_message_iterator_status status =
1250 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1251 int ret;
1252 const bt_clock_class *clock_class =
1253 bt_stream_class_borrow_default_clock_class_const(
1254 bt_stream_borrow_class_const(sstate->stream));
1255 bt_message *msg = NULL;
1256 uint64_t raw_value;
1257
1258 BT_ASSERT(!trimmer_it->begin.is_infinite);
1259 BT_ASSERT(!sstate->cur_packet);
1260
1261 /*
1262 * Create and push an initial packet beginning message,
1263 * making its time the trimming range's beginning time.
1264 */
1265 ret = clock_raw_value_from_ns_from_origin(clock_class,
1266 trimmer_it->begin.ns_from_origin, &raw_value);
1267 if (ret) {
1268 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1269 goto end;
1270 }
1271
1272 msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
1273 trimmer_it->self_msg_iter, packet, raw_value);
1274 if (!msg) {
1275 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1276 goto end;
1277 }
1278
1279 push_message(trimmer_it, msg);
1280 msg = NULL;
1281
1282 /* Set packet as this stream's current packet */
1283 sstate->cur_packet = packet;
1284 bt_packet_get_ref(sstate->cur_packet);
1285
1286end:
1287 bt_message_put_ref(msg);
1288 return status;
1289}
1290
1291/*
1292 * Handles a message which is associated to a given stream state. This
1293 * _could_ make the iterator's output message queue grow; this could
1294 * also consume the message without pushing anything to this queue, only
1295 * modifying the stream state.
1296 *
1297 * This function consumes the `msg` reference, _whatever the outcome_.
1298 *
1299 * `ns_from_origin` is the message's time, as given by
1300 * get_msg_ns_from_origin().
1301 *
1302 * This function sets `reached_end` if handling this message made the
1303 * iterator reach the end of the trimming range. Note that the output
1304 * message queue could contain messages even if this function sets
1305 * `reached_end`.
1306 */
1307static inline
1308bt_self_message_iterator_status handle_message_with_stream_state(
1309 struct trimmer_iterator *trimmer_it, const bt_message *msg,
1310 struct trimmer_iterator_stream_state *sstate,
1311 int64_t ns_from_origin, bool *reached_end)
1312{
1313 bt_self_message_iterator_status status =
1314 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1315 bt_message_type msg_type = bt_message_get_type(msg);
1316 int ret;
1317
1318 switch (msg_type) {
1319 case BT_MESSAGE_TYPE_EVENT:
91d81473 1320 if (G_UNLIKELY(!trimmer_it->end.is_infinite &&
7de0e49a
PP
1321 ns_from_origin > trimmer_it->end.ns_from_origin)) {
1322 status = end_iterator_streams(trimmer_it);
1323 *reached_end = true;
1324 break;
1325 }
1326
91d81473 1327 if (G_UNLIKELY(!sstate->inited)) {
7de0e49a
PP
1328 status = ensure_stream_state_is_inited(trimmer_it,
1329 sstate, NULL);
1330 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1331 goto end;
1332 }
1333 }
1334
91d81473 1335 if (G_UNLIKELY(!sstate->cur_packet)) {
7de0e49a
PP
1336 const bt_event *event =
1337 bt_message_event_borrow_event_const(msg);
1338 const bt_packet *packet = bt_event_borrow_packet_const(
1339 event);
1340
1341 status = ensure_cur_packet_exists(trimmer_it, sstate,
1342 packet);
1343 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1344 goto end;
1345 }
1346 }
1347
1348 BT_ASSERT(sstate->cur_packet);
1349 push_message(trimmer_it, msg);
1350 msg = NULL;
1351 break;
1352 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
91d81473 1353 if (G_UNLIKELY(!trimmer_it->end.is_infinite &&
7de0e49a
PP
1354 ns_from_origin > trimmer_it->end.ns_from_origin)) {
1355 status = end_iterator_streams(trimmer_it);
1356 *reached_end = true;
1357 break;
1358 }
1359
91d81473 1360 if (G_UNLIKELY(!sstate->inited)) {
7de0e49a
PP
1361 status = ensure_stream_state_is_inited(trimmer_it,
1362 sstate, NULL);
1363 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1364 goto end;
1365 }
1366 }
1367
1368 BT_ASSERT(!sstate->cur_packet);
1369 sstate->cur_packet =
1370 bt_message_packet_beginning_borrow_packet_const(msg);
1371 bt_packet_get_ref(sstate->cur_packet);
1372 push_message(trimmer_it, msg);
1373 msg = NULL;
1374 break;
1375 case BT_MESSAGE_TYPE_PACKET_END:
1376 sstate->stream_act_end_ns_from_origin = ns_from_origin;
1377
91d81473 1378 if (G_UNLIKELY(!trimmer_it->end.is_infinite &&
7de0e49a
PP
1379 ns_from_origin > trimmer_it->end.ns_from_origin)) {
1380 status = end_iterator_streams(trimmer_it);
1381 *reached_end = true;
1382 break;
1383 }
1384
91d81473 1385 if (G_UNLIKELY(!sstate->inited)) {
7de0e49a
PP
1386 status = ensure_stream_state_is_inited(trimmer_it,
1387 sstate, NULL);
1388 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1389 goto end;
1390 }
1391 }
1392
91d81473 1393 if (G_UNLIKELY(!sstate->cur_packet)) {
7de0e49a
PP
1394 const bt_packet *packet =
1395 bt_message_packet_end_borrow_packet_const(msg);
1396
1397 status = ensure_cur_packet_exists(trimmer_it, sstate,
1398 packet);
1399 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1400 goto end;
1401 }
1402 }
1403
1404 BT_ASSERT(sstate->cur_packet);
1405 BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
1406 push_message(trimmer_it, msg);
1407 msg = NULL;
1408 break;
1409 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1410 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1411 {
1412 /*
1413 * `ns_from_origin` is the message's time range's
1414 * beginning time here.
1415 */
1416 int64_t end_ns_from_origin;
1417 const bt_clock_snapshot *end_cs;
1418
1419 if (bt_message_get_type(msg) ==
1420 BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
1421 /*
1422 * Safe to ignore the return value because we
1423 * know there's a default clock and it's always
1424 * known.
1425 */
9b24b6aa 1426 end_cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
0cbc2c33 1427 msg);
7de0e49a
PP
1428 } else {
1429 /*
1430 * Safe to ignore the return value because we
1431 * know there's a default clock and it's always
1432 * known.
1433 */
9b24b6aa 1434 end_cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
0cbc2c33 1435 msg);
7de0e49a
PP
1436 }
1437
1438 if (bt_clock_snapshot_get_ns_from_origin(end_cs,
1439 &end_ns_from_origin)) {
1440 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1441 goto end;
1442 }
1443
1444 sstate->stream_act_end_ns_from_origin = end_ns_from_origin;
1445
1446 if (!trimmer_it->end.is_infinite &&
1447 ns_from_origin > trimmer_it->end.ns_from_origin) {
1448 status = end_iterator_streams(trimmer_it);
1449 *reached_end = true;
1450 break;
1451 }
1452
1453 if (!trimmer_it->end.is_infinite &&
1454 end_ns_from_origin > trimmer_it->end.ns_from_origin) {
1455 /*
1456 * This message's end time is outside the
1457 * trimming time range: replace it with a new
1458 * message having an end time equal to the
1459 * trimming time range's end and without a
1460 * count.
1461 */
1462 const bt_clock_class *clock_class =
1463 bt_clock_snapshot_borrow_clock_class_const(
1464 end_cs);
1465 const bt_clock_snapshot *begin_cs;
1466 bt_message *new_msg;
1467 uint64_t end_raw_value;
1468
1469 ret = clock_raw_value_from_ns_from_origin(clock_class,
1470 trimmer_it->end.ns_from_origin, &end_raw_value);
1471 if (ret) {
1472 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1473 goto end;
1474 }
1475
1476 if (msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
9b24b6aa 1477 begin_cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
0cbc2c33 1478 msg);
7de0e49a
PP
1479 new_msg = bt_message_discarded_events_create_with_default_clock_snapshots(
1480 trimmer_it->self_msg_iter,
1481 sstate->stream,
1482 bt_clock_snapshot_get_value(begin_cs),
1483 end_raw_value);
1484 } else {
9b24b6aa 1485 begin_cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
0cbc2c33 1486 msg);
7de0e49a
PP
1487 new_msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
1488 trimmer_it->self_msg_iter,
1489 sstate->stream,
1490 bt_clock_snapshot_get_value(begin_cs),
1491 end_raw_value);
1492 }
1493
1494 if (!new_msg) {
1495 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1496 goto end;
1497 }
1498
1499 /* Replace the original message */
1500 BT_MESSAGE_MOVE_REF(msg, new_msg);
1501 }
1502
91d81473 1503 if (G_UNLIKELY(!sstate->inited)) {
7de0e49a
PP
1504 status = ensure_stream_state_is_inited(trimmer_it,
1505 sstate, NULL);
1506 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1507 goto end;
1508 }
1509 }
1510
1511 push_message(trimmer_it, msg);
1512 msg = NULL;
1513 break;
1514 }
1515 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
1516 if (!trimmer_it->end.is_infinite &&
1517 ns_from_origin > trimmer_it->end.ns_from_origin) {
1518 /*
1519 * This only happens when the message's time is
1520 * known and is greater than the trimming
1521 * range's end time. Unknown and -inf times are
1522 * always less than
1523 * `trimmer_it->end.ns_from_origin`.
1524 */
1525 status = end_iterator_streams(trimmer_it);
1526 *reached_end = true;
1527 break;
1528 }
1529
1530 if (!sstate->inited) {
1531 status = ensure_stream_state_is_inited(trimmer_it,
1532 sstate, msg);
1533 msg = NULL;
1534 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1535 goto end;
1536 }
1537 } else {
1538 push_message(trimmer_it, msg);
1539 msg = NULL;
1540 }
1541
1542 break;
1543 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
1544 if (trimmer_it->end.is_infinite) {
1545 push_message(trimmer_it, msg);
1546 msg = NULL;
1547 break;
1548 }
1549
1550 if (ns_from_origin == INT64_MIN) {
1551 /* Unknown: push as is if stream state is inited */
1552 if (sstate->inited) {
1553 push_message(trimmer_it, msg);
1554 msg = NULL;
1555 sstate->last_msg_is_stream_activity_end = true;
1556 }
1557 } else if (ns_from_origin == INT64_MAX) {
1558 /* Infinite: use trimming range's end time */
1559 sstate->stream_act_end_ns_from_origin =
1560 trimmer_it->end.ns_from_origin;
1561 } else {
1562 /* Known: check if outside of trimming range */
1563 if (ns_from_origin > trimmer_it->end.ns_from_origin) {
1564 sstate->stream_act_end_ns_from_origin =
1565 trimmer_it->end.ns_from_origin;
1566 status = end_iterator_streams(trimmer_it);
1567 *reached_end = true;
1568 break;
1569 }
1570
1571 if (!sstate->inited) {
1572 /*
1573 * First message for this stream is a
1574 * stream activity end: we can't deduce
1575 * anything about the stream activity
1576 * beginning's time, and using this
1577 * message's time would make a useless
1578 * pair of stream activity beginning/end
1579 * with the same time. Just skip this
1580 * message and wait for something
1581 * useful.
1582 */
1583 break;
1584 }
1585
1586 push_message(trimmer_it, msg);
1587 msg = NULL;
1588 sstate->last_msg_is_stream_activity_end = true;
1589 sstate->stream_act_end_ns_from_origin = ns_from_origin;
1590 }
1591
1592 break;
1593 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
1594 /*
1595 * We don't know what follows at this point, so just
1596 * keep this message until we know what to do with it
1597 * (it will be used in ensure_stream_state_is_inited()).
1598 */
1599 BT_ASSERT(!sstate->inited);
1600 BT_MESSAGE_MOVE_REF(sstate->stream_beginning_msg, msg);
1601 break;
1602 case BT_MESSAGE_TYPE_STREAM_END:
1603 if (sstate->inited) {
1604 /*
1605 * This is the end of an inited stream: end this
1606 * stream if its stream activity end message
1607 * time is not the trimming range's end time
1608 * (which means the final stream activity end
1609 * message had an infinite time). end_stream()
1610 * will generate its own stream end message.
1611 */
1612 if (trimmer_it->end.is_infinite) {
1613 push_message(trimmer_it, msg);
1614 msg = NULL;
1615 g_hash_table_remove(trimmer_it->stream_states,
1616 sstate->stream);
1617 } else if (sstate->stream_act_end_ns_from_origin <
1618 trimmer_it->end.ns_from_origin) {
1619 status = end_stream(trimmer_it, sstate);
1620 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1621 goto end;
1622 }
1623
1624 /* We won't need this stream state again */
1625 g_hash_table_remove(trimmer_it->stream_states,
1626 sstate->stream);
1627 }
1628 } else {
1629 /* We dont't need this stream state anymore */
1630 g_hash_table_remove(trimmer_it->stream_states, sstate->stream);
1631 }
1632
1633 break;
1634 default:
1635 break;
1636 }
1637
1638end:
1639 /* We release the message's reference whatever the outcome */
1640 bt_message_put_ref(msg);
1641 return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1642}
1643
1644/*
1645 * Handles an input message. This _could_ make the iterator's output
1646 * message queue grow; this could also consume the message without
1647 * pushing anything to this queue, only modifying the stream state.
1648 *
1649 * This function consumes the `msg` reference, _whatever the outcome_.
1650 *
1651 * This function sets `reached_end` if handling this message made the
1652 * iterator reach the end of the trimming range. Note that the output
1653 * message queue could contain messages even if this function sets
1654 * `reached_end`.
1655 */
1656static inline
1657bt_self_message_iterator_status handle_message(
1658 struct trimmer_iterator *trimmer_it, const bt_message *msg,
1659 bool *reached_end)
1660{
1661 bt_self_message_iterator_status status;
1662 const bt_stream *stream = NULL;
1663 int64_t ns_from_origin = INT64_MIN;
1664 bool skip;
1665 int ret;
1666 struct trimmer_iterator_stream_state *sstate = NULL;
1667
1668 /* Find message's associated stream */
1669 switch (bt_message_get_type(msg)) {
1670 case BT_MESSAGE_TYPE_EVENT:
1671 stream = bt_event_borrow_stream_const(
1672 bt_message_event_borrow_event_const(msg));
1673 break;
1674 case BT_MESSAGE_TYPE_PACKET_BEGINNING:
1675 stream = bt_packet_borrow_stream_const(
1676 bt_message_packet_beginning_borrow_packet_const(msg));
1677 break;
1678 case BT_MESSAGE_TYPE_PACKET_END:
1679 stream = bt_packet_borrow_stream_const(
1680 bt_message_packet_end_borrow_packet_const(msg));
1681 break;
1682 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1683 stream = bt_message_discarded_events_borrow_stream_const(msg);
1684 break;
1685 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1686 stream = bt_message_discarded_packets_borrow_stream_const(msg);
1687 break;
1688 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
1689 stream = bt_message_stream_activity_beginning_borrow_stream_const(msg);
1690 break;
1691 case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
1692 stream = bt_message_stream_activity_end_borrow_stream_const(msg);
1693 break;
1694 case BT_MESSAGE_TYPE_STREAM_BEGINNING:
1695 stream = bt_message_stream_beginning_borrow_stream_const(msg);
1696 break;
1697 case BT_MESSAGE_TYPE_STREAM_END:
1698 stream = bt_message_stream_end_borrow_stream_const(msg);
1699 break;
1700 default:
1701 break;
1702 }
1703
91d81473 1704 if (G_LIKELY(stream)) {
7de0e49a
PP
1705 /* Find stream state */
1706 sstate = g_hash_table_lookup(trimmer_it->stream_states,
1707 stream);
91d81473 1708 if (G_UNLIKELY(!sstate)) {
7de0e49a
PP
1709 /* No stream state yet: create one now */
1710 const bt_stream_class *sc;
1711
1712 /*
1713 * Validate right now that the stream's class
1714 * has a registered default clock class so that
1715 * an existing stream state guarantees existing
1716 * default clock snapshots for its associated
1717 * messages.
1718 *
1719 * Also check that clock snapshots are always
1720 * known.
1721 */
1722 sc = bt_stream_borrow_class_const(stream);
1723 if (!bt_stream_class_borrow_default_clock_class_const(sc)) {
1724 BT_LOGE("Unsupported stream: stream class does "
1725 "not have a default clock class: "
1726 "stream-addr=%p, "
1727 "stream-id=%" PRIu64 ", "
1728 "stream-name=\"%s\"",
1729 stream, bt_stream_get_id(stream),
1730 bt_stream_get_name(stream));
1731 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1732 goto end;
1733 }
1734
649934d2 1735 /*
2e90378a
PP
1736 * Temporary: make sure packet beginning, packet
1737 * end, discarded events, and discarded packets
649934d2
PP
1738 * messages have default clock snapshots until
1739 * the support for not having them is
1740 * implemented.
1741 */
9b24b6aa 1742 if (!bt_stream_class_packets_have_beginning_default_clock_snapshot(
649934d2
PP
1743 sc)) {
1744 BT_LOGE("Unsupported stream: packets have "
1745 "no beginning clock snapshot: "
1746 "stream-addr=%p, "
1747 "stream-id=%" PRIu64 ", "
1748 "stream-name=\"%s\"",
1749 stream, bt_stream_get_id(stream),
1750 bt_stream_get_name(stream));
1751 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1752 goto end;
1753 }
1754
9b24b6aa 1755 if (!bt_stream_class_packets_have_end_default_clock_snapshot(
649934d2
PP
1756 sc)) {
1757 BT_LOGE("Unsupported stream: packets have "
1758 "no end clock snapshot: "
1759 "stream-addr=%p, "
1760 "stream-id=%" PRIu64 ", "
1761 "stream-name=\"%s\"",
1762 stream, bt_stream_get_id(stream),
1763 bt_stream_get_name(stream));
1764 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1765 goto end;
1766 }
1767
2e90378a
PP
1768 if (bt_stream_class_supports_discarded_events(sc) &&
1769 !bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
1770 BT_LOGE("Unsupported stream: discarded events "
1771 "have no clock snapshots: "
1772 "stream-addr=%p, "
1773 "stream-id=%" PRIu64 ", "
1774 "stream-name=\"%s\"",
1775 stream, bt_stream_get_id(stream),
1776 bt_stream_get_name(stream));
1777 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1778 goto end;
1779 }
1780
1781 if (bt_stream_class_supports_discarded_packets(sc) &&
1782 !bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
1783 BT_LOGE("Unsupported stream: discarded packets "
1784 "have no clock snapshots: "
1785 "stream-addr=%p, "
1786 "stream-id=%" PRIu64 ", "
1787 "stream-name=\"%s\"",
1788 stream, bt_stream_get_id(stream),
1789 bt_stream_get_name(stream));
1790 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1791 goto end;
1792 }
1793
7de0e49a
PP
1794 sstate = g_new0(struct trimmer_iterator_stream_state,
1795 1);
1796 if (!sstate) {
1797 status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
1798 goto end;
1799 }
1800
1801 sstate->stream = stream;
1802 sstate->stream_act_end_ns_from_origin = INT64_MIN;
1803 g_hash_table_insert(trimmer_it->stream_states,
1804 (void *) stream, sstate);
1805 }
1806 }
1807
1808 /* Retrieve the message's time */
1809 ret = get_msg_ns_from_origin(msg, &ns_from_origin, &skip);
91d81473 1810 if (G_UNLIKELY(ret)) {
7de0e49a
PP
1811 status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
1812 goto end;
1813 }
1814
91d81473 1815 if (G_LIKELY(sstate)) {
7de0e49a
PP
1816 /* Message associated to a stream */
1817 status = handle_message_with_stream_state(trimmer_it, msg,
1818 sstate, ns_from_origin, reached_end);
1819
1820 /*
1821 * handle_message_with_stream_state() unconditionally
1822 * consumes `msg`.
1823 */
1824 msg = NULL;
1825 } else {
1826 /*
1827 * Message not associated to a stream (message iterator
1828 * inactivity).
1829 */
91d81473 1830 if (G_UNLIKELY(ns_from_origin > trimmer_it->end.ns_from_origin)) {
7de0e49a
PP
1831 BT_MESSAGE_PUT_REF_AND_RESET(msg);
1832 status = end_iterator_streams(trimmer_it);
1833 *reached_end = true;
1834 } else {
1835 push_message(trimmer_it, msg);
8dad9b32 1836 status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
7de0e49a
PP
1837 msg = NULL;
1838 }
1839 }
1840
1841end:
1842 /* We release the message's reference whatever the outcome */
1843 bt_message_put_ref(msg);
1844 return status;
1845}
1846
1847static inline
1848void fill_message_array_from_output_messages(
1849 struct trimmer_iterator *trimmer_it,
1850 bt_message_array_const msgs, uint64_t capacity, uint64_t *count)
1851{
1852 *count = 0;
1853
1854 /*
1855 * Move auto-seek messages to the output array (which is this
1856 * iterator's base message array).
1857 */
1858 while (capacity > 0 && !g_queue_is_empty(trimmer_it->output_messages)) {
1859 msgs[*count] = pop_message(trimmer_it);
1860 capacity--;
1861 (*count)++;
1862 }
1863
1864 BT_ASSERT(*count > 0);
1865}
1866
1867static inline
1868bt_self_message_iterator_status state_ending(
1869 struct trimmer_iterator *trimmer_it,
1870 bt_message_array_const msgs, uint64_t capacity,
1871 uint64_t *count)
1872{
1873 bt_self_message_iterator_status status =
1874 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1875
1876 if (g_queue_is_empty(trimmer_it->output_messages)) {
1877 trimmer_it->state = TRIMMER_ITERATOR_STATE_ENDED;
1878 status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
1879 goto end;
1880 }
1881
1882 fill_message_array_from_output_messages(trimmer_it, msgs,
1883 capacity, count);
1884
1885end:
1886 return status;
1887}
1888
1889static inline
1890bt_self_message_iterator_status state_trim(struct trimmer_iterator *trimmer_it,
1891 bt_message_array_const msgs, uint64_t capacity,
1892 uint64_t *count)
1893{
1894 bt_self_message_iterator_status status =
1895 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1896 bt_message_array_const my_msgs;
1897 uint64_t my_count;
1898 uint64_t i;
1899 bool reached_end = false;
1900
1901 while (g_queue_is_empty(trimmer_it->output_messages)) {
1902 status = (int) bt_self_component_port_input_message_iterator_next(
1903 trimmer_it->upstream_iter, &my_msgs, &my_count);
91d81473 1904 if (G_UNLIKELY(status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
7de0e49a
PP
1905 if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_END) {
1906 status = end_iterator_streams(trimmer_it);
1907 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1908 goto end;
1909 }
1910
1911 trimmer_it->state =
1912 TRIMMER_ITERATOR_STATE_ENDING;
1913 status = state_ending(trimmer_it, msgs,
1914 capacity, count);
1915 }
1916
1917 goto end;
1918 }
1919
1920 BT_ASSERT(my_count > 0);
1921
1922 for (i = 0; i < my_count; i++) {
1923 status = handle_message(trimmer_it, my_msgs[i],
1924 &reached_end);
1925
1926 /*
1927 * handle_message() unconditionally consumes the
1928 * message reference.
1929 */
1930 my_msgs[i] = NULL;
1931
91d81473 1932 if (G_UNLIKELY(status !=
7de0e49a
PP
1933 BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
1934 put_messages(my_msgs, my_count);
1935 goto end;
1936 }
1937
91d81473 1938 if (G_UNLIKELY(reached_end)) {
7de0e49a
PP
1939 /*
1940 * This message's time was passed the
1941 * trimming time range's end time: we
1942 * are done. Their might still be
1943 * messages in the output message queue,
1944 * so move to the "ending" state and
1945 * apply it immediately since
1946 * state_trim() is called within the
1947 * "next" method.
1948 */
1949 put_messages(my_msgs, my_count);
1950 trimmer_it->state =
1951 TRIMMER_ITERATOR_STATE_ENDING;
1952 status = state_ending(trimmer_it, msgs,
1953 capacity, count);
1954 goto end;
1955 }
1956 }
1957 }
1958
1959 /*
1960 * There's at least one message in the output message queue:
1961 * move the messages to the output message array.
1962 */
1963 BT_ASSERT(!g_queue_is_empty(trimmer_it->output_messages));
1964 fill_message_array_from_output_messages(trimmer_it, msgs,
1965 capacity, count);
1966
1967end:
1968 return status;
1969}
1970
1971BT_HIDDEN
1972bt_self_message_iterator_status trimmer_msg_iter_next(
1973 bt_self_message_iterator *self_msg_iter,
1974 bt_message_array_const msgs, uint64_t capacity,
1975 uint64_t *count)
1976{
1977 struct trimmer_iterator *trimmer_it =
1978 bt_self_message_iterator_get_data(self_msg_iter);
1979 bt_self_message_iterator_status status =
1980 BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
1981
1982 BT_ASSERT(trimmer_it);
1983
91d81473 1984 if (G_LIKELY(trimmer_it->state == TRIMMER_ITERATOR_STATE_TRIM)) {
7de0e49a
PP
1985 status = state_trim(trimmer_it, msgs, capacity, count);
1986 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1987 goto end;
1988 }
1989 } else {
1990 switch (trimmer_it->state) {
1991 case TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN:
1992 status = state_set_trimmer_iterator_bounds(trimmer_it);
1993 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1994 goto end;
1995 }
1996
1997 status = state_seek_initially(trimmer_it);
1998 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
1999 goto end;
2000 }
2001
2002 status = state_trim(trimmer_it, msgs, capacity, count);
2003 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
2004 goto end;
2005 }
2006
2007 break;
2008 case TRIMMER_ITERATOR_STATE_SEEK_INITIALLY:
2009 status = state_seek_initially(trimmer_it);
2010 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
2011 goto end;
2012 }
2013
2014 status = state_trim(trimmer_it, msgs, capacity, count);
2015 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
2016 goto end;
2017 }
2018
2019 break;
2020 case TRIMMER_ITERATOR_STATE_ENDING:
2021 status = state_ending(trimmer_it, msgs, capacity,
2022 count);
2023 if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
2024 goto end;
2025 }
2026
2027 break;
2028 case TRIMMER_ITERATOR_STATE_ENDED:
2029 status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
2030 break;
2031 default:
2032 abort();
2033 }
2034 }
2035
2036end:
2037 return status;
2038}
2039
2040BT_HIDDEN
2041void trimmer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
2042{
2043 struct trimmer_iterator *trimmer_it =
2044 bt_self_message_iterator_get_data(self_msg_iter);
2045
2046 BT_ASSERT(trimmer_it);
2047 destroy_trimmer_iterator(trimmer_it);
2048}
This page took 0.134149 seconds and 4 git commands to generate.