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