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