cd9cc3f2f041fba30aed0ce957227c61cc2bccbe
[babeltrace.git] / plugins / utils / muxer / muxer.c
1 /*
2 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define BT_LOG_TAG "PLUGIN-UTILS-MUXER-FLT"
24 #include "logging.h"
25
26 #include <babeltrace/babeltrace-internal.h>
27 #include <babeltrace/compat/uuid-internal.h>
28 #include <babeltrace/ctf-ir/clock-class.h>
29 #include <babeltrace/ctf-ir/event.h>
30 #include <babeltrace/graph/clock-class-priority-map.h>
31 #include <babeltrace/graph/component-filter.h>
32 #include <babeltrace/graph/component.h>
33 #include <babeltrace/graph/component-internal.h>
34 #include <babeltrace/graph/notification-event.h>
35 #include <babeltrace/graph/notification-inactivity.h>
36 #include <babeltrace/graph/notification-iterator.h>
37 #include <babeltrace/graph/notification-iterator-internal.h>
38 #include <babeltrace/graph/notification.h>
39 #include <babeltrace/graph/port.h>
40 #include <babeltrace/graph/private-component-filter.h>
41 #include <babeltrace/graph/private-component.h>
42 #include <babeltrace/graph/private-component.h>
43 #include <babeltrace/graph/private-connection.h>
44 #include <babeltrace/graph/private-notification-iterator.h>
45 #include <babeltrace/graph/private-port.h>
46 #include <babeltrace/graph/connection.h>
47 #include <babeltrace/graph/connection-internal.h>
48 #include <babeltrace/values-internal.h>
49 #include <plugins-common.h>
50 #include <glib.h>
51 #include <stdbool.h>
52 #include <inttypes.h>
53 #include <assert.h>
54 #include <stdlib.h>
55 #include <string.h>
56
57 #define ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME "assume-absolute-clock-classes"
58
59 struct muxer_comp {
60 /* Array of struct bt_private_notification_iterator * (weak refs) */
61 GPtrArray *muxer_notif_iters;
62
63 /* Weak ref */
64 struct bt_private_component *priv_comp;
65 unsigned int next_port_num;
66 size_t available_input_ports;
67 bool error;
68 bool initializing_muxer_notif_iter;
69 bool assume_absolute_clock_classes;
70 };
71
72 struct muxer_upstream_notif_iter {
73 /* Owned by this, NULL if ended */
74 struct bt_notification_iterator *notif_iter;
75
76 /*
77 * This flag is true if the upstream notification iterator's
78 * current notification must be considered for the multiplexing
79 * operations. If the upstream iterator returns
80 * BT_NOTIFICATION_ITERATOR_STATUS_AGAIN, then this object
81 * is considered invalid, because its current notification is
82 * still the previous one, but we already took it into account.
83 *
84 * The value of this flag is not important if notif_iter above
85 * is NULL (which means the upstream iterator is finished).
86 */
87 bool is_valid;
88 };
89
90 enum muxer_notif_iter_clock_class_expectation {
91 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_ANY = 0,
92 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE,
93 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID,
94 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID,
95 };
96
97 struct muxer_notif_iter {
98 /*
99 * Array of struct muxer_upstream_notif_iter * (owned by this).
100 *
101 * NOTE: This array is searched in linearly to find the youngest
102 * current notification. Keep this until benchmarks confirm that
103 * another data structure is faster than this for our typical
104 * use cases.
105 */
106 GPtrArray *muxer_upstream_notif_iters;
107
108 /*
109 * List of "recently" connected input ports (weak) to
110 * handle by this muxer notification iterator.
111 * muxer_port_connected() adds entries to this list, and the
112 * entries are removed when a notification iterator is created
113 * on the port's connection and put into
114 * muxer_upstream_notif_iters above by
115 * muxer_notif_iter_handle_newly_connected_ports().
116 */
117 GList *newly_connected_priv_ports;
118
119 /* Next thing to return by the "next" method */
120 struct bt_notification_iterator_next_return next_next_return;
121
122 /* Last time returned in a notification */
123 int64_t last_returned_ts_ns;
124
125 /* Clock class expectation state */
126 enum muxer_notif_iter_clock_class_expectation clock_class_expectation;
127
128 /*
129 * Expected clock class UUID, only valid when
130 * clock_class_expectation is
131 * MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID.
132 */
133 unsigned char expected_clock_class_uuid[BABELTRACE_UUID_LEN];
134 };
135
136 static
137 void destroy_muxer_upstream_notif_iter(
138 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter)
139 {
140 if (!muxer_upstream_notif_iter) {
141 return;
142 }
143
144 BT_LOGD("Destroying muxer's upstream notification iterator wrapper: "
145 "addr=%p, notif-iter-addr=%p, is-valid=%d",
146 muxer_upstream_notif_iter,
147 muxer_upstream_notif_iter->notif_iter,
148 muxer_upstream_notif_iter->is_valid);
149 bt_put(muxer_upstream_notif_iter->notif_iter);
150 g_free(muxer_upstream_notif_iter);
151 }
152
153 static
154 struct muxer_upstream_notif_iter *muxer_notif_iter_add_upstream_notif_iter(
155 struct muxer_notif_iter *muxer_notif_iter,
156 struct bt_notification_iterator *notif_iter,
157 struct bt_private_port *priv_port)
158 {
159 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter =
160 g_new0(struct muxer_upstream_notif_iter, 1);
161
162 if (!muxer_upstream_notif_iter) {
163 BT_LOGE_STR("Failed to allocate one muxer's upstream notification iterator wrapper.");
164 goto end;
165 }
166
167 muxer_upstream_notif_iter->notif_iter = bt_get(notif_iter);
168 muxer_upstream_notif_iter->is_valid = false;
169 g_ptr_array_add(muxer_notif_iter->muxer_upstream_notif_iters,
170 muxer_upstream_notif_iter);
171 BT_LOGD("Added muxer's upstream notification iterator wrapper: "
172 "addr=%p, muxer-notif-iter-addr=%p, notif-iter-addr=%p",
173 muxer_upstream_notif_iter, muxer_notif_iter,
174 notif_iter);
175
176 end:
177 return muxer_upstream_notif_iter;
178 }
179
180 static
181 enum bt_component_status ensure_available_input_port(
182 struct bt_private_component *priv_comp)
183 {
184 struct muxer_comp *muxer_comp =
185 bt_private_component_get_user_data(priv_comp);
186 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
187 GString *port_name = NULL;
188
189 assert(muxer_comp);
190
191 if (muxer_comp->available_input_ports >= 1) {
192 goto end;
193 }
194
195 port_name = g_string_new("in");
196 if (!port_name) {
197 BT_LOGE_STR("Failed to allocate a GString.");
198 status = BT_COMPONENT_STATUS_NOMEM;
199 goto end;
200 }
201
202 g_string_append_printf(port_name, "%u", muxer_comp->next_port_num);
203 status = bt_private_component_filter_add_input_private_port(
204 priv_comp, port_name->str, NULL, NULL);
205 if (status != BT_COMPONENT_STATUS_OK) {
206 BT_LOGE("Cannot add input port to muxer component: "
207 "port-name=\"%s\", comp-addr=%p, status=%s",
208 port_name->str, priv_comp,
209 bt_component_status_string(status));
210 goto end;
211 }
212
213 muxer_comp->available_input_ports++;
214 muxer_comp->next_port_num++;
215 BT_LOGD("Added one input port to muxer component: "
216 "port-name=\"%s\", comp-addr=%p",
217 port_name->str, priv_comp);
218 end:
219 if (port_name) {
220 g_string_free(port_name, TRUE);
221 }
222
223 return status;
224 }
225
226 static
227 enum bt_component_status create_output_port(
228 struct bt_private_component *priv_comp)
229 {
230 return bt_private_component_filter_add_output_private_port(
231 priv_comp, "out", NULL, NULL);
232 }
233
234 static
235 void destroy_muxer_comp(struct muxer_comp *muxer_comp)
236 {
237 if (!muxer_comp) {
238 return;
239 }
240
241 BT_LOGD("Destroying muxer component: muxer-comp-addr=%p, "
242 "muxer-notif-iter-count=%u", muxer_comp,
243 muxer_comp->muxer_notif_iters->len);
244
245 if (muxer_comp->muxer_notif_iters) {
246 g_ptr_array_free(muxer_comp->muxer_notif_iters, TRUE);
247 }
248
249 g_free(muxer_comp);
250 }
251
252 static
253 struct bt_value *get_default_params(void)
254 {
255 struct bt_value *params;
256 int ret;
257
258 params = bt_value_map_create();
259 if (!params) {
260 BT_LOGE_STR("Cannot create a map value object.");
261 goto error;
262 }
263
264 ret = bt_value_map_insert_bool(params,
265 ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, false);
266 if (ret) {
267 BT_LOGE_STR("Cannot add boolean value to map value object.");
268 goto error;
269 }
270
271 goto end;
272
273 error:
274 BT_PUT(params);
275
276 end:
277 return params;
278 }
279
280 static
281 int configure_muxer_comp(struct muxer_comp *muxer_comp, struct bt_value *params)
282 {
283 struct bt_value *default_params = NULL;
284 struct bt_value *real_params = NULL;
285 struct bt_value *assume_absolute_clock_classes = NULL;
286 int ret = 0;
287 bt_bool bool_val;
288
289 default_params = get_default_params();
290 if (!default_params) {
291 BT_LOGE("Cannot get default parameters: "
292 "muxer-comp-addr=%p", muxer_comp);
293 goto error;
294 }
295
296 real_params = bt_value_map_extend(default_params, params);
297 if (!real_params) {
298 BT_LOGE("Cannot extend default parameters map value: "
299 "muxer-comp-addr=%p, def-params-addr=%p, "
300 "params-addr=%p", muxer_comp, default_params,
301 params);
302 goto error;
303 }
304
305 assume_absolute_clock_classes = bt_value_map_get(real_params,
306 ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME);
307 if (!bt_value_is_bool(assume_absolute_clock_classes)) {
308 BT_LOGE("Expecting a boolean value for the `%s` parameter: "
309 "muxer-comp-addr=%p, value-type=%s",
310 ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, muxer_comp,
311 bt_value_type_string(
312 bt_value_get_type(assume_absolute_clock_classes)));
313 goto error;
314 }
315
316 ret = bt_value_bool_get(assume_absolute_clock_classes, &bool_val);
317 assert(ret == 0);
318 muxer_comp->assume_absolute_clock_classes = (bool) bool_val;
319 BT_LOGD("Configured muxer component: muxer-comp-addr=%p, "
320 "assume-absolute-clock-classes=%d",
321 muxer_comp, muxer_comp->assume_absolute_clock_classes);
322 goto end;
323
324 error:
325 ret = -1;
326
327 end:
328 bt_put(default_params);
329 bt_put(real_params);
330 bt_put(assume_absolute_clock_classes);
331 return ret;
332 }
333
334 BT_HIDDEN
335 enum bt_component_status muxer_init(
336 struct bt_private_component *priv_comp,
337 struct bt_value *params, void *init_data)
338 {
339 int ret;
340 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
341 struct muxer_comp *muxer_comp = g_new0(struct muxer_comp, 1);
342
343 BT_LOGD("Initializing muxer component: "
344 "comp-addr=%p, params-addr=%p", priv_comp, params);
345
346 if (!muxer_comp) {
347 BT_LOGE_STR("Failed to allocate one muxer component.");
348 goto error;
349 }
350
351 ret = configure_muxer_comp(muxer_comp, params);
352 if (ret) {
353 BT_LOGE("Cannot configure muxer component: "
354 "muxer-comp-addr=%p, params-addr=%p",
355 muxer_comp, params);
356 goto error;
357 }
358
359 muxer_comp->muxer_notif_iters = g_ptr_array_new();
360 if (!muxer_comp->muxer_notif_iters) {
361 BT_LOGE_STR("Failed to allocate a GPtrArray.");
362 goto error;
363 }
364
365 muxer_comp->priv_comp = priv_comp;
366 ret = bt_private_component_set_user_data(priv_comp, muxer_comp);
367 assert(ret == 0);
368 status = ensure_available_input_port(priv_comp);
369 if (status != BT_COMPONENT_STATUS_OK) {
370 BT_LOGE("Cannot ensure that at least one muxer component's input port is available: "
371 "muxer-comp-addr=%p, status=%s",
372 muxer_comp,
373 bt_component_status_string(status));
374 goto error;
375 }
376
377 status = create_output_port(priv_comp);
378 if (status) {
379 BT_LOGE("Cannot create muxer component's output port: "
380 "muxer-comp-addr=%p, status=%s",
381 muxer_comp,
382 bt_component_status_string(status));
383 goto error;
384 }
385
386 BT_LOGD("Initialized muxer component: "
387 "comp-addr=%p, params-addr=%p, muxer-comp-addr=%p",
388 priv_comp, params, muxer_comp);
389
390 goto end;
391
392 error:
393 destroy_muxer_comp(muxer_comp);
394 ret = bt_private_component_set_user_data(priv_comp, NULL);
395 assert(ret == 0);
396
397 if (status == BT_COMPONENT_STATUS_OK) {
398 status = BT_COMPONENT_STATUS_ERROR;
399 }
400
401 end:
402 return status;
403 }
404
405 BT_HIDDEN
406 void muxer_finalize(struct bt_private_component *priv_comp)
407 {
408 struct muxer_comp *muxer_comp =
409 bt_private_component_get_user_data(priv_comp);
410
411 BT_LOGD("Finalizing muxer component: comp-addr=%p",
412 priv_comp);
413 destroy_muxer_comp(muxer_comp);
414 }
415
416 static
417 struct bt_notification_iterator *create_notif_iter_on_input_port(
418 struct bt_private_port *priv_port, int *ret)
419 {
420 struct bt_port *port = bt_port_from_private_port(priv_port);
421 struct bt_notification_iterator *notif_iter = NULL;
422 struct bt_private_connection *priv_conn = NULL;
423 enum bt_connection_status conn_status;
424
425 assert(ret);
426 *ret = 0;
427 assert(port);
428 assert(bt_port_is_connected(port));
429 priv_conn = bt_private_port_get_private_connection(priv_port);
430 assert(priv_conn);
431
432 // TODO: Advance the iterator to >= the time of the latest
433 // returned notification by the muxer notification
434 // iterator which creates it.
435 conn_status = bt_private_connection_create_notification_iterator(
436 priv_conn, NULL, &notif_iter);
437 if (conn_status != BT_CONNECTION_STATUS_OK) {
438 BT_LOGE("Cannot create upstream notification iterator on input port's connection: "
439 "port-addr=%p, port-name=\"%s\", conn-addr=%p, "
440 "status=%s",
441 port, bt_port_get_name(port), priv_conn,
442 bt_connection_status_string(conn_status));
443 *ret = -1;
444 goto end;
445 }
446
447 BT_LOGD("Created upstream notification iterator on input port's connection: "
448 "port-addr=%p, port-name=\"%s\", conn-addr=%p, "
449 "notif-iter-addr=%p",
450 port, bt_port_get_name(port), priv_conn, notif_iter);
451
452 end:
453 bt_put(port);
454 bt_put(priv_conn);
455 return notif_iter;
456 }
457
458 static
459 enum bt_notification_iterator_status muxer_upstream_notif_iter_next(
460 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter)
461 {
462 enum bt_notification_iterator_status status;
463
464 BT_LOGV("Calling upstream notification iterator's \"next\" method: "
465 "muxer-upstream-notif-iter-wrap-addr=%p, notif-iter-addr=%p",
466 muxer_upstream_notif_iter,
467 muxer_upstream_notif_iter->notif_iter);
468 status = bt_notification_iterator_next(
469 muxer_upstream_notif_iter->notif_iter);
470 BT_LOGV("Upstream notification iterator's \"next\" method returned: "
471 "status=%s", bt_notification_iterator_status_string(status));
472
473 switch (status) {
474 case BT_NOTIFICATION_ITERATOR_STATUS_OK:
475 /*
476 * Notification iterator's current notification is valid:
477 * it must be considered for muxing operations.
478 */
479 BT_LOGV_STR("Validated upstream notification iterator wrapper.");
480 muxer_upstream_notif_iter->is_valid = true;
481 break;
482 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
483 /*
484 * Notification iterator's current notification is not
485 * valid anymore. Return
486 * BT_NOTIFICATION_ITERATOR_STATUS_AGAIN
487 * immediately.
488 */
489 BT_LOGV_STR("Invalidated upstream notification iterator wrapper because of BT_NOTIFICATION_ITERATOR_STATUS_AGAIN.");
490 muxer_upstream_notif_iter->is_valid = false;
491 break;
492 case BT_NOTIFICATION_ITERATOR_STATUS_END: /* Fall-through. */
493 case BT_NOTIFICATION_ITERATOR_STATUS_CANCELED:
494 /*
495 * Notification iterator reached the end: release it. It
496 * won't be considered again to find the youngest
497 * notification.
498 */
499 BT_LOGV_STR("Invalidated upstream notification iterator wrapper because of BT_NOTIFICATION_ITERATOR_STATUS_END or BT_NOTIFICATION_ITERATOR_STATUS_CANCELED.");
500 BT_PUT(muxer_upstream_notif_iter->notif_iter);
501 muxer_upstream_notif_iter->is_valid = false;
502 status = BT_NOTIFICATION_ITERATOR_STATUS_OK;
503 break;
504 default:
505 /* Error or unsupported status code */
506 BT_LOGE("Error or unsupported status code: "
507 "status-code=%d", status);
508 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
509 break;
510 }
511
512 return status;
513 }
514
515 static
516 int muxer_notif_iter_handle_newly_connected_ports(
517 struct muxer_notif_iter *muxer_notif_iter)
518 {
519 int ret = 0;
520
521 BT_LOGV("Handling newly connected ports: "
522 "muxer-notif-iter-addr=%p", muxer_notif_iter);
523
524 /*
525 * Here we create one upstream notification iterator for each
526 * newly connected port. We do not perform an initial "next" on
527 * those new upstream notification iterators: they are
528 * invalidated, to be validated later. The list of newly
529 * connected ports to handle here is updated by
530 * muxer_port_connected().
531 */
532 while (true) {
533 GList *node = muxer_notif_iter->newly_connected_priv_ports;
534 struct bt_private_port *priv_port;
535 struct bt_port *port;
536 struct bt_notification_iterator *upstream_notif_iter = NULL;
537 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter;
538
539 if (!node) {
540 break;
541 }
542
543 priv_port = node->data;
544 port = bt_port_from_private_port(priv_port);
545 assert(port);
546
547 if (!bt_port_is_connected(port)) {
548 /*
549 * Looks like this port is not connected
550 * anymore: we can't create an upstream
551 * notification iterator on its (non-existing)
552 * connection in this case.
553 */
554 goto remove_node;
555 }
556
557 BT_PUT(port);
558 upstream_notif_iter = create_notif_iter_on_input_port(priv_port,
559 &ret);
560 if (ret) {
561 /* create_notif_iter_on_input_port() logs errors */
562 assert(!upstream_notif_iter);
563 goto error;
564 }
565
566 muxer_upstream_notif_iter =
567 muxer_notif_iter_add_upstream_notif_iter(
568 muxer_notif_iter, upstream_notif_iter,
569 priv_port);
570 BT_PUT(upstream_notif_iter);
571 if (!muxer_upstream_notif_iter) {
572 /*
573 * muxer_notif_iter_add_upstream_notif_iter()
574 * logs errors.
575 */
576 goto error;
577 }
578
579 remove_node:
580 bt_put(upstream_notif_iter);
581 bt_put(port);
582 muxer_notif_iter->newly_connected_priv_ports =
583 g_list_delete_link(
584 muxer_notif_iter->newly_connected_priv_ports,
585 node);
586 }
587
588 goto end;
589
590 error:
591 if (ret >= 0) {
592 ret = -1;
593 }
594
595 end:
596 return ret;
597 }
598
599 static
600 int get_notif_ts_ns(struct muxer_comp *muxer_comp,
601 struct muxer_notif_iter *muxer_notif_iter,
602 struct bt_notification *notif, int64_t last_returned_ts_ns,
603 int64_t *ts_ns)
604 {
605 struct bt_clock_class_priority_map *cc_prio_map = NULL;
606 struct bt_ctf_clock_class *clock_class = NULL;
607 struct bt_ctf_clock_value *clock_value = NULL;
608 struct bt_ctf_event *event = NULL;
609 int ret = 0;
610 const unsigned char *cc_uuid;
611 const char *cc_name;
612
613 assert(notif);
614 assert(ts_ns);
615
616 BT_LOGV("Getting notification's timestamp: "
617 "muxer-notif-iter-addr=%p, notif-addr=%p, "
618 "last-returned-ts=%" PRId64,
619 muxer_notif_iter, notif, last_returned_ts_ns);
620
621 switch (bt_notification_get_type(notif)) {
622 case BT_NOTIFICATION_TYPE_EVENT:
623 cc_prio_map =
624 bt_notification_event_get_clock_class_priority_map(
625 notif);
626 break;
627
628 case BT_NOTIFICATION_TYPE_INACTIVITY:
629 cc_prio_map =
630 bt_notification_inactivity_get_clock_class_priority_map(
631 notif);
632 break;
633 default:
634 /* All the other notifications have a higher priority */
635 BT_LOGV_STR("Notification has no timestamp: using the last returned timestamp.");
636 *ts_ns = last_returned_ts_ns;
637 goto end;
638 }
639
640 if (!cc_prio_map) {
641 BT_LOGE("Cannot get notification's clock class priority map: "
642 "notif-addr=%p", notif);
643 goto error;
644 }
645
646 /*
647 * If the clock class priority map is empty, then we consider
648 * that this notification has no time. In this case it's always
649 * the youngest.
650 */
651 if (bt_clock_class_priority_map_get_clock_class_count(cc_prio_map) == 0) {
652 BT_LOGV_STR("Notification's clock class priorty map contains 0 clock classes: "
653 "using the last returned timestamp.");
654 *ts_ns = last_returned_ts_ns;
655 goto end;
656 }
657
658 clock_class =
659 bt_clock_class_priority_map_get_highest_priority_clock_class(
660 cc_prio_map);
661 if (!clock_class) {
662 BT_LOGE("Cannot get the clock class with the highest priority from clock class priority map: "
663 "cc-prio-map-addr=%p", cc_prio_map);
664 goto error;
665 }
666
667 cc_uuid = bt_ctf_clock_class_get_uuid(clock_class);
668 cc_name = bt_ctf_clock_class_get_name(clock_class);
669
670 if (muxer_notif_iter->clock_class_expectation ==
671 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_ANY) {
672 /*
673 * This is the first clock class that this muxer
674 * notification iterator encounters. Its properties
675 * determine what to expect for the whole lifetime of
676 * the iterator without a true
677 * `assume-absolute-clock-classes` parameter.
678 */
679 if (bt_ctf_clock_class_is_absolute(clock_class)) {
680 /* Expect absolute clock classes */
681 muxer_notif_iter->clock_class_expectation =
682 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE;
683 } else {
684 if (cc_uuid) {
685 /*
686 * Expect non-absolute clock classes
687 * with a specific UUID.
688 */
689 muxer_notif_iter->clock_class_expectation =
690 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID;
691 memcpy(muxer_notif_iter->expected_clock_class_uuid,
692 cc_uuid, BABELTRACE_UUID_LEN);
693 } else {
694 /*
695 * Expect non-absolute clock classes
696 * with no UUID.
697 */
698 muxer_notif_iter->clock_class_expectation =
699 MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID;
700 }
701 }
702 }
703
704 if (!muxer_comp->assume_absolute_clock_classes) {
705 switch (muxer_notif_iter->clock_class_expectation) {
706 case MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE:
707 if (!bt_ctf_clock_class_is_absolute(clock_class)) {
708 BT_LOGE("Expecting an absolute clock class, "
709 "but got a non-absolute one: "
710 "clock-class-addr=%p, clock-class-name=\"%s\"",
711 clock_class, cc_name);
712 goto error;
713 }
714 break;
715 case MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID:
716 if (bt_ctf_clock_class_is_absolute(clock_class)) {
717 BT_LOGE("Expecting a non-absolute clock class with no UUID, "
718 "but got an absolute one: "
719 "clock-class-addr=%p, clock-class-name=\"%s\"",
720 clock_class, cc_name);
721 goto error;
722 }
723
724 if (cc_uuid) {
725 BT_LOGE("Expecting a non-absolute clock class with no UUID, "
726 "but got one with a UUID: "
727 "clock-class-addr=%p, clock-class-name=\"%s\", "
728 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
729 clock_class, cc_name,
730 (unsigned int) cc_uuid[0],
731 (unsigned int) cc_uuid[1],
732 (unsigned int) cc_uuid[2],
733 (unsigned int) cc_uuid[3],
734 (unsigned int) cc_uuid[4],
735 (unsigned int) cc_uuid[5],
736 (unsigned int) cc_uuid[6],
737 (unsigned int) cc_uuid[7],
738 (unsigned int) cc_uuid[8],
739 (unsigned int) cc_uuid[9],
740 (unsigned int) cc_uuid[10],
741 (unsigned int) cc_uuid[11],
742 (unsigned int) cc_uuid[12],
743 (unsigned int) cc_uuid[13],
744 (unsigned int) cc_uuid[14],
745 (unsigned int) cc_uuid[15]);
746 goto error;
747 }
748 break;
749 case MUXER_NOTIF_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID:
750 if (bt_ctf_clock_class_is_absolute(clock_class)) {
751 BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
752 "but got an absolute one: "
753 "clock-class-addr=%p, clock-class-name=\"%s\"",
754 clock_class, cc_name);
755 goto error;
756 }
757
758 if (!cc_uuid) {
759 BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
760 "but got one with no UUID: "
761 "clock-class-addr=%p, clock-class-name=\"%s\"",
762 clock_class, cc_name);
763 goto error;
764 }
765
766 if (memcmp(muxer_notif_iter->expected_clock_class_uuid,
767 cc_uuid, BABELTRACE_UUID_LEN) != 0) {
768 BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
769 "but got one with different UUID: "
770 "clock-class-addr=%p, clock-class-name=\"%s\", "
771 "expected-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
772 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
773 clock_class, cc_name,
774 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[0],
775 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[1],
776 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[2],
777 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[3],
778 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[4],
779 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[5],
780 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[6],
781 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[7],
782 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[8],
783 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[9],
784 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[10],
785 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[11],
786 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[12],
787 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[13],
788 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[14],
789 (unsigned int) muxer_notif_iter->expected_clock_class_uuid[15],
790 (unsigned int) cc_uuid[0],
791 (unsigned int) cc_uuid[1],
792 (unsigned int) cc_uuid[2],
793 (unsigned int) cc_uuid[3],
794 (unsigned int) cc_uuid[4],
795 (unsigned int) cc_uuid[5],
796 (unsigned int) cc_uuid[6],
797 (unsigned int) cc_uuid[7],
798 (unsigned int) cc_uuid[8],
799 (unsigned int) cc_uuid[9],
800 (unsigned int) cc_uuid[10],
801 (unsigned int) cc_uuid[11],
802 (unsigned int) cc_uuid[12],
803 (unsigned int) cc_uuid[13],
804 (unsigned int) cc_uuid[14],
805 (unsigned int) cc_uuid[15]);
806 goto error;
807 }
808 break;
809 default:
810 /* Unexpected */
811 BT_LOGF("Unexpected clock class expectation: "
812 "expectation-code=%d",
813 muxer_notif_iter->clock_class_expectation);
814 abort();
815 }
816 }
817
818 switch (bt_notification_get_type(notif)) {
819 case BT_NOTIFICATION_TYPE_EVENT:
820 event = bt_notification_event_get_event(notif);
821 assert(event);
822 clock_value = bt_ctf_event_get_clock_value(event,
823 clock_class);
824 break;
825 case BT_NOTIFICATION_TYPE_INACTIVITY:
826 clock_value = bt_notification_inactivity_get_clock_value(
827 notif, clock_class);
828 break;
829 default:
830 BT_LOGF("Unexpected notification type at this point: "
831 "type=%d", bt_notification_get_type(notif));
832 abort();
833 }
834
835 if (!clock_value) {
836 BT_LOGE("Cannot get notification's clock value for clock class: "
837 "clock-class-addr=%p, clock-class-name=\"%s\"",
838 clock_class, cc_name);
839 goto error;
840 }
841
842 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, ts_ns);
843 if (ret) {
844 BT_LOGE("Cannot get nanoseconds from Epoch of clock value: "
845 "clock-value-addr=%p", clock_value);
846 goto error;
847 }
848
849 goto end;
850
851 error:
852 ret = -1;
853
854 end:
855 if (ret == 0) {
856 BT_LOGV("Found notification's timestamp: "
857 "muxer-notif-iter-addr=%p, notif-addr=%p, "
858 "last-returned-ts=%" PRId64 ", ts=%" PRId64,
859 muxer_notif_iter, notif, last_returned_ts_ns,
860 *ts_ns);
861 }
862
863 bt_put(cc_prio_map);
864 bt_put(event);
865 bt_put(clock_class);
866 bt_put(clock_value);
867 return ret;
868 }
869
870 /*
871 * This function finds the youngest available notification amongst the
872 * non-ended upstream notification iterators and returns the upstream
873 * notification iterator which has it, or
874 * BT_NOTIFICATION_ITERATOR_STATUS_END if there's no available
875 * notification.
876 *
877 * This function does NOT:
878 *
879 * * Update any upstream notification iterator.
880 * * Check for newly connected ports.
881 * * Check the upstream notification iterators to retry.
882 *
883 * On sucess, this function sets *muxer_upstream_notif_iter to the
884 * upstream notification iterator of which the current notification is
885 * the youngest, and sets *ts_ns to its time.
886 */
887 static
888 enum bt_notification_iterator_status
889 muxer_notif_iter_youngest_upstream_notif_iter(
890 struct muxer_comp *muxer_comp,
891 struct muxer_notif_iter *muxer_notif_iter,
892 struct muxer_upstream_notif_iter **muxer_upstream_notif_iter,
893 int64_t *ts_ns)
894 {
895 size_t i;
896 int ret;
897 int64_t youngest_ts_ns = INT64_MAX;
898 enum bt_notification_iterator_status status =
899 BT_NOTIFICATION_ITERATOR_STATUS_OK;
900
901 assert(muxer_comp);
902 assert(muxer_notif_iter);
903 assert(muxer_upstream_notif_iter);
904 *muxer_upstream_notif_iter = NULL;
905
906 for (i = 0; i < muxer_notif_iter->muxer_upstream_notif_iters->len; i++) {
907 struct bt_notification *notif;
908 struct muxer_upstream_notif_iter *cur_muxer_upstream_notif_iter =
909 g_ptr_array_index(muxer_notif_iter->muxer_upstream_notif_iters, i);
910 int64_t notif_ts_ns;
911
912 if (!cur_muxer_upstream_notif_iter->notif_iter) {
913 /* This upstream notification iterator is ended */
914 BT_LOGV("Skipping ended upstream notification iterator: "
915 "muxer-upstream-notif-iter-wrap-addr=%p",
916 cur_muxer_upstream_notif_iter);
917 continue;
918 }
919
920 assert(cur_muxer_upstream_notif_iter->is_valid);
921 notif = bt_notification_iterator_get_notification(
922 cur_muxer_upstream_notif_iter->notif_iter);
923 assert(notif);
924 ret = get_notif_ts_ns(muxer_comp, muxer_notif_iter, notif,
925 muxer_notif_iter->last_returned_ts_ns, &notif_ts_ns);
926 bt_put(notif);
927 if (ret) {
928 /* get_notif_ts_ns() logs errors */
929 *muxer_upstream_notif_iter = NULL;
930 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
931 goto end;
932 }
933
934 if (notif_ts_ns <= youngest_ts_ns) {
935 *muxer_upstream_notif_iter =
936 cur_muxer_upstream_notif_iter;
937 youngest_ts_ns = notif_ts_ns;
938 *ts_ns = youngest_ts_ns;
939 }
940 }
941
942 if (!*muxer_upstream_notif_iter) {
943 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
944 *ts_ns = INT64_MIN;
945 }
946
947 end:
948 return status;
949 }
950
951 static
952 enum bt_notification_iterator_status validate_muxer_upstream_notif_iter(
953 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter)
954 {
955 enum bt_notification_iterator_status status =
956 BT_NOTIFICATION_ITERATOR_STATUS_OK;
957
958 BT_LOGV("Validating muxer's upstream notification iterator wrapper: "
959 "muxer-upstream-notif-iter-wrap-addr=%p",
960 muxer_upstream_notif_iter);
961
962 if (muxer_upstream_notif_iter->is_valid ||
963 !muxer_upstream_notif_iter->notif_iter) {
964 goto end;
965 }
966
967 /* muxer_upstream_notif_iter_next() logs details/errors */
968 status = muxer_upstream_notif_iter_next(muxer_upstream_notif_iter);
969
970 end:
971 return status;
972 }
973
974 static
975 enum bt_notification_iterator_status validate_muxer_upstream_notif_iters(
976 struct muxer_notif_iter *muxer_notif_iter)
977 {
978 enum bt_notification_iterator_status status =
979 BT_NOTIFICATION_ITERATOR_STATUS_OK;
980 size_t i;
981
982 BT_LOGV("Validating muxer's upstream notification iterator wrappers: "
983 "muxer-notif-iter-addr=%p", muxer_notif_iter);
984
985 for (i = 0; i < muxer_notif_iter->muxer_upstream_notif_iters->len; i++) {
986 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter =
987 g_ptr_array_index(
988 muxer_notif_iter->muxer_upstream_notif_iters,
989 i);
990
991 status = validate_muxer_upstream_notif_iter(
992 muxer_upstream_notif_iter);
993 if (status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
994 if (status < 0) {
995 BT_LOGE("Cannot validate muxer's upstream notification iterator wrapper: "
996 "muxer-notif-iter-addr=%p, "
997 "muxer-upstream-notif-iter-wrap-addr=%p",
998 muxer_notif_iter,
999 muxer_upstream_notif_iter);
1000 } else {
1001 BT_LOGV("Cannot validate muxer's upstream notification iterator wrapper: "
1002 "muxer-notif-iter-addr=%p, "
1003 "muxer-upstream-notif-iter-wrap-addr=%p",
1004 muxer_notif_iter,
1005 muxer_upstream_notif_iter);
1006 }
1007
1008 goto end;
1009 }
1010
1011 /*
1012 * Remove this muxer upstream notification iterator
1013 * if it's ended or canceled.
1014 */
1015 if (!muxer_upstream_notif_iter->notif_iter) {
1016 /*
1017 * Use g_ptr_array_remove_fast() because the
1018 * order of those elements is not important.
1019 */
1020 BT_LOGV("Removing muxer's upstream notification iterator wrapper: ended or canceled: "
1021 "muxer-notif-iter-addr=%p, "
1022 "muxer-upstream-notif-iter-wrap-addr=%p",
1023 muxer_notif_iter, muxer_upstream_notif_iter);
1024 g_ptr_array_remove_index_fast(
1025 muxer_notif_iter->muxer_upstream_notif_iters,
1026 i);
1027 i--;
1028 }
1029 }
1030
1031 end:
1032 return status;
1033 }
1034
1035 static
1036 struct bt_notification_iterator_next_return muxer_notif_iter_do_next(
1037 struct muxer_comp *muxer_comp,
1038 struct muxer_notif_iter *muxer_notif_iter)
1039 {
1040 struct muxer_upstream_notif_iter *muxer_upstream_notif_iter = NULL;
1041 struct bt_notification_iterator_next_return next_return = {
1042 .notification = NULL,
1043 .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
1044 };
1045 int64_t next_return_ts;
1046
1047 while (true) {
1048 int ret = muxer_notif_iter_handle_newly_connected_ports(
1049 muxer_notif_iter);
1050
1051 if (ret) {
1052 BT_LOGE("Cannot handle newly connected input ports for muxer's notification iterator: "
1053 "muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1054 "ret=%d",
1055 muxer_comp, muxer_notif_iter, ret);
1056 next_return.status =
1057 BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1058 goto end;
1059 }
1060
1061 next_return.status =
1062 validate_muxer_upstream_notif_iters(muxer_notif_iter);
1063 if (next_return.status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
1064 /* validate_muxer_upstream_notif_iters() logs details */
1065 goto end;
1066 }
1067
1068 /*
1069 * At this point, we know that all the existing upstream
1070 * notification iterators are valid. However the
1071 * operations to validate them (during
1072 * validate_muxer_upstream_notif_iters()) may have
1073 * connected new ports. If no ports were connected
1074 * during this operation, exit the loop.
1075 */
1076 if (!muxer_notif_iter->newly_connected_priv_ports) {
1077 BT_LOGV("Not breaking this loop: muxer's notification iterator still has newly connected input ports to handle: "
1078 "muxer-comp-addr=%p", muxer_comp);
1079 break;
1080 }
1081 }
1082
1083 assert(!muxer_notif_iter->newly_connected_priv_ports);
1084
1085 /*
1086 * At this point we know that all the existing upstream
1087 * notification iterators are valid. We can find the one,
1088 * amongst those, of which the current notification is the
1089 * youngest.
1090 */
1091 next_return.status =
1092 muxer_notif_iter_youngest_upstream_notif_iter(muxer_comp,
1093 muxer_notif_iter, &muxer_upstream_notif_iter,
1094 &next_return_ts);
1095 if (next_return.status < 0 ||
1096 next_return.status == BT_NOTIFICATION_ITERATOR_STATUS_END ||
1097 next_return.status == BT_NOTIFICATION_ITERATOR_STATUS_CANCELED) {
1098 if (next_return.status < 0) {
1099 BT_LOGE("Cannot find the youngest upstream notification iterator wrapper: "
1100 "status=%s",
1101 bt_notification_iterator_status_string(next_return.status));
1102 } else {
1103 BT_LOGV("Cannot find the youngest upstream notification iterator wrapper: "
1104 "status=%s",
1105 bt_notification_iterator_status_string(next_return.status));
1106 }
1107
1108 goto end;
1109 }
1110
1111 if (next_return_ts < muxer_notif_iter->last_returned_ts_ns) {
1112 BT_LOGE("Youngest upstream notification iterator wrapper's timestamp is less than muxer's notification iterator's last returned timestamp: "
1113 "muxer-notif-iter-addr=%p, ts=%" PRId64 ", "
1114 "last-returned-ts=%" PRId64,
1115 muxer_notif_iter, next_return_ts,
1116 muxer_notif_iter->last_returned_ts_ns);
1117 next_return.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1118 goto end;
1119 }
1120
1121 BT_LOGV("Found youngest upstream notification iterator wrapper: "
1122 "muxer-notif-iter-addr=%p, "
1123 "muxer-upstream-notif-iter-wrap-addr=%p, "
1124 "ts=%" PRId64,
1125 muxer_notif_iter, muxer_upstream_notif_iter, next_return_ts);
1126 assert(next_return.status == BT_NOTIFICATION_ITERATOR_STATUS_OK);
1127 assert(muxer_upstream_notif_iter);
1128 next_return.notification = bt_notification_iterator_get_notification(
1129 muxer_upstream_notif_iter->notif_iter);
1130 assert(next_return.notification);
1131
1132 /*
1133 * We invalidate the upstream notification iterator so that, the
1134 * next time this function is called,
1135 * validate_muxer_upstream_notif_iters() will make it valid.
1136 */
1137 muxer_upstream_notif_iter->is_valid = false;
1138 muxer_notif_iter->last_returned_ts_ns = next_return_ts;
1139
1140 end:
1141 return next_return;
1142 }
1143
1144 static
1145 void destroy_muxer_notif_iter(struct muxer_notif_iter *muxer_notif_iter)
1146 {
1147 if (!muxer_notif_iter) {
1148 return;
1149 }
1150
1151 BT_LOGD("Destroying muxer component's notification iterator: "
1152 "muxer-notif-iter-addr=%p", muxer_notif_iter);
1153
1154 if (muxer_notif_iter->muxer_upstream_notif_iters) {
1155 BT_LOGD_STR("Destroying muxer's upstream notification iterator wrappers.");
1156 g_ptr_array_free(
1157 muxer_notif_iter->muxer_upstream_notif_iters, TRUE);
1158 }
1159
1160 g_list_free(muxer_notif_iter->newly_connected_priv_ports);
1161 g_free(muxer_notif_iter);
1162 }
1163
1164 static
1165 int muxer_notif_iter_init_newly_connected_ports(struct muxer_comp *muxer_comp,
1166 struct muxer_notif_iter *muxer_notif_iter)
1167 {
1168 struct bt_component *comp;
1169 int64_t count;
1170 int64_t i;
1171 int ret = 0;
1172
1173 /*
1174 * Add the connected input ports to this muxer notification
1175 * iterator's list of newly connected ports. They will be
1176 * handled by muxer_notif_iter_handle_newly_connected_ports().
1177 */
1178 comp = bt_component_from_private_component(muxer_comp->priv_comp);
1179 assert(comp);
1180 count = bt_component_filter_get_input_port_count(comp);
1181 if (count < 0) {
1182 BT_LOGD("No input port to initialize for muxer component's notification iterator: "
1183 "muxer-comp-addr=%p, muxer-notif-iter-addr=%p",
1184 muxer_comp, muxer_notif_iter);
1185 goto end;
1186 }
1187
1188 for (i = 0; i < count; i++) {
1189 struct bt_private_port *priv_port =
1190 bt_private_component_filter_get_input_private_port_by_index(
1191 muxer_comp->priv_comp, i);
1192 struct bt_port *port;
1193
1194 assert(priv_port);
1195 port = bt_port_from_private_port(priv_port);
1196 assert(port);
1197
1198 if (!bt_port_is_connected(port)) {
1199 BT_LOGD("Skipping input port: not connected: "
1200 "muxer-comp-addr=%p, port-addr=%p, port-name\"%s\"",
1201 muxer_comp, port, bt_port_get_name(port));
1202 bt_put(priv_port);
1203 bt_put(port);
1204 continue;
1205 }
1206
1207 bt_put(port);
1208 bt_put(priv_port);
1209 muxer_notif_iter->newly_connected_priv_ports =
1210 g_list_append(
1211 muxer_notif_iter->newly_connected_priv_ports,
1212 priv_port);
1213 if (!muxer_notif_iter->newly_connected_priv_ports) {
1214 BT_LOGE("Cannot append port to muxer's notification iterator list of newly connected input ports: "
1215 "port-addr=%p, port-name=\"%s\", "
1216 "muxer-notif-iter-addr=%p", port,
1217 bt_port_get_name(port), muxer_notif_iter);
1218 ret = -1;
1219 goto end;
1220 }
1221
1222 BT_LOGD("Appended port to muxer's notification iterator list of newly connected input ports: "
1223 "port-addr=%p, port-name=\"%s\", "
1224 "muxer-notif-iter-addr=%p", port,
1225 bt_port_get_name(port), muxer_notif_iter);
1226 }
1227
1228 end:
1229 bt_put(comp);
1230 return ret;
1231 }
1232
1233 BT_HIDDEN
1234 enum bt_notification_iterator_status muxer_notif_iter_init(
1235 struct bt_private_notification_iterator *priv_notif_iter,
1236 struct bt_private_port *output_priv_port)
1237 {
1238 struct muxer_comp *muxer_comp = NULL;
1239 struct muxer_notif_iter *muxer_notif_iter = NULL;
1240 struct bt_private_component *priv_comp = NULL;
1241 enum bt_notification_iterator_status status =
1242 BT_NOTIFICATION_ITERATOR_STATUS_OK;
1243 int ret;
1244
1245 priv_comp = bt_private_notification_iterator_get_private_component(
1246 priv_notif_iter);
1247 assert(priv_comp);
1248 muxer_comp = bt_private_component_get_user_data(priv_comp);
1249 assert(muxer_comp);
1250 BT_LOGD("Initializing muxer component's notification iterator: "
1251 "comp-addr=%p, muxer-comp-addr=%p, notif-iter-addr=%p",
1252 priv_comp, muxer_comp, priv_notif_iter);
1253
1254 if (muxer_comp->initializing_muxer_notif_iter) {
1255 /*
1256 * Weird, unhandled situation detected: downstream
1257 * creates a muxer notification iterator while creating
1258 * another muxer notification iterator (same component).
1259 */
1260 BT_LOGE("Recursive initialization of muxer component's notification iterator: "
1261 "comp-addr=%p, muxer-comp-addr=%p, notif-iter-addr=%p",
1262 priv_comp, muxer_comp, priv_notif_iter);
1263 goto error;
1264 }
1265
1266 muxer_comp->initializing_muxer_notif_iter = true;
1267 muxer_notif_iter = g_new0(struct muxer_notif_iter, 1);
1268 if (!muxer_notif_iter) {
1269 BT_LOGE_STR("Failed to allocate one muxer component's notification iterator.");
1270 goto error;
1271 }
1272
1273 muxer_notif_iter->last_returned_ts_ns = INT64_MIN;
1274 muxer_notif_iter->muxer_upstream_notif_iters =
1275 g_ptr_array_new_with_free_func(
1276 (GDestroyNotify) destroy_muxer_upstream_notif_iter);
1277 if (!muxer_notif_iter->muxer_upstream_notif_iters) {
1278 BT_LOGE_STR("Failed to allocate a GPtrArray.");
1279 goto error;
1280 }
1281
1282 /*
1283 * Add the muxer notification iterator to the component's array
1284 * of muxer notification iterators here because
1285 * muxer_notif_iter_init_newly_connected_ports() can cause
1286 * muxer_port_connected() to be called, which adds the newly
1287 * connected port to each muxer notification iterator's list of
1288 * newly connected ports.
1289 */
1290 g_ptr_array_add(muxer_comp->muxer_notif_iters, muxer_notif_iter);
1291 ret = muxer_notif_iter_init_newly_connected_ports(muxer_comp,
1292 muxer_notif_iter);
1293 if (ret) {
1294 BT_LOGE("Cannot initialize newly connected input ports for muxer component's notification iterator: "
1295 "comp-addr=%p, muxer-comp-addr=%p, "
1296 "muxer-notif-iter-addr=%p, notif-iter-addr=%p, ret=%d",
1297 priv_comp, muxer_comp, muxer_notif_iter,
1298 priv_notif_iter, ret);
1299 goto error;
1300 }
1301
1302 ret = bt_private_notification_iterator_set_user_data(priv_notif_iter,
1303 muxer_notif_iter);
1304 assert(ret == 0);
1305 BT_LOGD("Initialized muxer component's notification iterator: "
1306 "comp-addr=%p, muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1307 "notif-iter-addr=%p",
1308 priv_comp, muxer_comp, muxer_notif_iter, priv_notif_iter);
1309 goto end;
1310
1311 error:
1312 if (g_ptr_array_index(muxer_comp->muxer_notif_iters,
1313 muxer_comp->muxer_notif_iters->len - 1) == muxer_notif_iter) {
1314 g_ptr_array_remove_index(muxer_comp->muxer_notif_iters,
1315 muxer_comp->muxer_notif_iters->len - 1);
1316 }
1317
1318 destroy_muxer_notif_iter(muxer_notif_iter);
1319 ret = bt_private_notification_iterator_set_user_data(priv_notif_iter,
1320 NULL);
1321 assert(ret == 0);
1322 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1323
1324 end:
1325 muxer_comp->initializing_muxer_notif_iter = false;
1326 bt_put(priv_comp);
1327 return status;
1328 }
1329
1330 BT_HIDDEN
1331 void muxer_notif_iter_finalize(
1332 struct bt_private_notification_iterator *priv_notif_iter)
1333 {
1334 struct muxer_notif_iter *muxer_notif_iter =
1335 bt_private_notification_iterator_get_user_data(priv_notif_iter);
1336 struct bt_private_component *priv_comp = NULL;
1337 struct muxer_comp *muxer_comp = NULL;
1338
1339 priv_comp = bt_private_notification_iterator_get_private_component(
1340 priv_notif_iter);
1341 assert(priv_comp);
1342 muxer_comp = bt_private_component_get_user_data(priv_comp);
1343 BT_LOGD("Finalizing muxer component's notification iterator: "
1344 "comp-addr=%p, muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1345 "notif-iter-addr=%p",
1346 priv_comp, muxer_comp, muxer_notif_iter, priv_notif_iter);
1347
1348 if (muxer_comp) {
1349 (void) g_ptr_array_remove_fast(muxer_comp->muxer_notif_iters,
1350 muxer_notif_iter);
1351 destroy_muxer_notif_iter(muxer_notif_iter);
1352 }
1353
1354 bt_put(priv_comp);
1355 }
1356
1357 BT_HIDDEN
1358 struct bt_notification_iterator_next_return muxer_notif_iter_next(
1359 struct bt_private_notification_iterator *priv_notif_iter)
1360 {
1361 struct bt_notification_iterator_next_return next_ret;
1362 struct muxer_notif_iter *muxer_notif_iter =
1363 bt_private_notification_iterator_get_user_data(priv_notif_iter);
1364 struct bt_private_component *priv_comp = NULL;
1365 struct muxer_comp *muxer_comp = NULL;
1366
1367 assert(muxer_notif_iter);
1368 priv_comp = bt_private_notification_iterator_get_private_component(
1369 priv_notif_iter);
1370 assert(priv_comp);
1371 muxer_comp = bt_private_component_get_user_data(priv_comp);
1372 assert(muxer_comp);
1373
1374 BT_LOGV("Muxer component's notification iterator's \"next\" method called: "
1375 "comp-addr=%p, muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1376 "notif-iter-addr=%p",
1377 priv_comp, muxer_comp, muxer_notif_iter, priv_notif_iter);
1378
1379 /* Are we in an error state set elsewhere? */
1380 if (unlikely(muxer_comp->error)) {
1381 BT_LOGE("Muxer component is already in an error state: returning BT_NOTIFICATION_ITERATOR_STATUS_ERROR: "
1382 "comp-addr=%p, muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1383 "notif-iter-addr=%p",
1384 priv_comp, muxer_comp, muxer_notif_iter, priv_notif_iter);
1385 next_ret.notification = NULL;
1386 next_ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1387 goto end;
1388 }
1389
1390 next_ret = muxer_notif_iter_do_next(muxer_comp, muxer_notif_iter);
1391 if (next_ret.status < 0) {
1392 BT_LOGE("Cannot get next notification: "
1393 "comp-addr=%p, muxer-comp-addr=%p, muxer-notif-iter-addr=%p, "
1394 "notif-iter-addr=%p, status=%s",
1395 priv_comp, muxer_comp, muxer_notif_iter, priv_notif_iter,
1396 bt_notification_iterator_status_string(next_ret.status));
1397 } else {
1398 BT_LOGV("Returning from muxer component's notification iterator's \"next\" method: "
1399 "status=%s, notif-addr=%p",
1400 bt_notification_iterator_status_string(next_ret.status),
1401 next_ret.notification);
1402 }
1403
1404 end:
1405 bt_put(priv_comp);
1406 return next_ret;
1407 }
1408
1409 BT_HIDDEN
1410 void muxer_port_connected(
1411 struct bt_private_component *priv_comp,
1412 struct bt_private_port *self_private_port,
1413 struct bt_port *other_port)
1414 {
1415 struct bt_port *self_port =
1416 bt_port_from_private_port(self_private_port);
1417 struct muxer_comp *muxer_comp =
1418 bt_private_component_get_user_data(priv_comp);
1419 size_t i;
1420 int ret;
1421
1422 assert(self_port);
1423 assert(muxer_comp);
1424 BT_LOGD("Port connected: "
1425 "comp-addr=%p, muxer-comp-addr=%p, "
1426 "port-addr=%p, port-name=\"%s\", "
1427 "other-port-addr=%p, other-port-name=\"%s\"",
1428 priv_comp, muxer_comp, self_port, bt_port_get_name(self_port),
1429 other_port, bt_port_get_name(other_port));
1430
1431 if (bt_port_get_type(self_port) == BT_PORT_TYPE_OUTPUT) {
1432 goto end;
1433 }
1434
1435 for (i = 0; i < muxer_comp->muxer_notif_iters->len; i++) {
1436 struct muxer_notif_iter *muxer_notif_iter =
1437 g_ptr_array_index(muxer_comp->muxer_notif_iters, i);
1438
1439 /*
1440 * Add this port to the list of newly connected ports
1441 * for this muxer notification iterator. We append at
1442 * the end of this list while
1443 * muxer_notif_iter_handle_newly_connected_ports()
1444 * removes the nodes from the beginning.
1445 */
1446 muxer_notif_iter->newly_connected_priv_ports =
1447 g_list_append(
1448 muxer_notif_iter->newly_connected_priv_ports,
1449 self_private_port);
1450 if (!muxer_notif_iter->newly_connected_priv_ports) {
1451 BT_LOGE("Cannot append port to muxer's notification iterator list of newly connected input ports: "
1452 "port-addr=%p, port-name=\"%s\", "
1453 "muxer-notif-iter-addr=%p", self_port,
1454 bt_port_get_name(self_port), muxer_notif_iter);
1455 muxer_comp->error = true;
1456 goto end;
1457 }
1458
1459 BT_LOGD("Appended port to muxer's notification iterator list of newly connected input ports: "
1460 "port-addr=%p, port-name=\"%s\", "
1461 "muxer-notif-iter-addr=%p", self_port,
1462 bt_port_get_name(self_port), muxer_notif_iter);
1463 }
1464
1465 /* One less available input port */
1466 muxer_comp->available_input_ports--;
1467 ret = ensure_available_input_port(priv_comp);
1468 if (ret) {
1469 /*
1470 * Only way to report an error later since this
1471 * method does not return anything.
1472 */
1473 BT_LOGE("Cannot ensure that at least one muxer component's input port is available: "
1474 "muxer-comp-addr=%p, status=%s",
1475 muxer_comp, bt_component_status_string(ret));
1476 muxer_comp->error = true;
1477 goto end;
1478 }
1479
1480 end:
1481 bt_put(self_port);
1482 }
1483
1484 BT_HIDDEN
1485 void muxer_port_disconnected(struct bt_private_component *priv_comp,
1486 struct bt_private_port *priv_port)
1487 {
1488 struct bt_port *port = bt_port_from_private_port(priv_port);
1489 struct muxer_comp *muxer_comp =
1490 bt_private_component_get_user_data(priv_comp);
1491
1492 assert(port);
1493 assert(muxer_comp);
1494 BT_LOGD("Port disconnected: "
1495 "comp-addr=%p, muxer-comp-addr=%p, port-addr=%p, "
1496 "port-name=\"%s\"", priv_comp, muxer_comp,
1497 port, bt_port_get_name(port));
1498
1499 /*
1500 * There's nothing special to do when a port is disconnected
1501 * because this component deals with upstream notification
1502 * iterators which were already created thanks to connected
1503 * ports. The fact that the port is disconnected does not cancel
1504 * the upstream notification iterators created using its
1505 * connection: they still exist, even if the connection is dead.
1506 * The only way to remove an upstream notification iterator is
1507 * for its "next" operation to return
1508 * BT_NOTIFICATION_ITERATOR_STATUS_END.
1509 */
1510 if (bt_port_get_type(port) == BT_PORT_TYPE_INPUT) {
1511 /* One more available input port */
1512 muxer_comp->available_input_ports++;
1513 BT_LOGD("Leaving disconnected input port available for future connections: "
1514 "comp-addr=%p, muxer-comp-addr=%p, port-addr=%p, "
1515 "port-name=\"%s\", avail-input-port-count=%zu",
1516 priv_comp, muxer_comp, port, bt_port_get_name(port),
1517 muxer_comp->available_input_ports);
1518 }
1519
1520 bt_put(port);
1521 }
This page took 0.062487 seconds and 3 git commands to generate.