lib: bt_object_{get,put}_ref(): accept a `const` parameter
[babeltrace.git] / lib / graph / graph.c
CommitLineData
c0418dd9 1/*
f60c8b34 2 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
262e5473 3 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
c0418dd9
JG
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
262e5473
PP
24#define BT_LOG_TAG "GRAPH"
25#include <babeltrace/lib-logging-internal.h>
26
b2e0c907 27#include <babeltrace/graph/component-internal.h>
a2d06fd5 28#include <babeltrace/graph/private-graph.h>
b2e0c907
PP
29#include <babeltrace/graph/graph-internal.h>
30#include <babeltrace/graph/connection-internal.h>
31#include <babeltrace/graph/component-sink-internal.h>
32#include <babeltrace/graph/component-source.h>
33#include <babeltrace/graph/component-filter.h>
34#include <babeltrace/graph/port.h>
5c563278
PP
35#include <babeltrace/graph/notification-internal.h>
36#include <babeltrace/graph/notification-event-internal.h>
37#include <babeltrace/graph/notification-packet-internal.h>
3d9990ac 38#include <babeltrace/compiler-internal.h>
da91b29a 39#include <babeltrace/common-internal.h>
c55a9f58 40#include <babeltrace/types.h>
36712f1d 41#include <babeltrace/values.h>
da91b29a 42#include <babeltrace/private-values.h>
36712f1d 43#include <babeltrace/values-internal.h>
d94d92ac 44#include <babeltrace/object.h>
f6ccaed9
PP
45#include <babeltrace/assert-internal.h>
46#include <babeltrace/assert-pre-internal.h>
f60c8b34 47#include <unistd.h>
1bf957a0
PP
48#include <glib.h>
49
d94d92ac
PP
50typedef void (*port_added_func_t)(void *, void *, void *);
51typedef void (*port_removed_func_t)(void *, void *, void *);
52typedef void (*ports_connected_func_t)(void *, void *, void *, void *, void *);
53typedef void (*ports_disconnected_func_t)(void *, void *, void *, void *, void *);
54typedef enum bt_self_component_status (*comp_init_method_t)(void *, void *, void *);
55
1bf957a0 56struct bt_graph_listener {
a2d06fd5 57 bt_private_graph_listener_removed removed;
1bf957a0
PP
58 void *data;
59};
c0418dd9 60
d94d92ac
PP
61struct bt_graph_listener_port_added {
62 struct bt_graph_listener base;
63 port_added_func_t func;
64};
8cc092c9 65
d94d92ac
PP
66struct bt_graph_listener_port_removed {
67 struct bt_graph_listener base;
68 port_removed_func_t func;
69};
8cc092c9 70
d94d92ac
PP
71struct bt_graph_listener_ports_connected {
72 struct bt_graph_listener base;
73 ports_connected_func_t func;
74};
8cc092c9 75
d94d92ac
PP
76struct bt_graph_listener_ports_disconnected {
77 struct bt_graph_listener base;
78 ports_disconnected_func_t func;
79};
8cc092c9 80
d94d92ac
PP
81#define INIT_LISTENERS_ARRAY(_type, _listeners) \
82 do { \
83 _listeners = g_array_new(FALSE, TRUE, sizeof(_type)); \
84 if (!(_listeners)) { \
85 BT_LOGE_STR("Failed to allocate one GArray."); \
86 } \
87 } while (0)
88
89#define CALL_REMOVE_LISTENERS(_type, _listeners) \
90 do { \
91 size_t i; \
92 \
93 for (i = 0; i < (_listeners)->len; i++) { \
94 _type *listener = \
95 &g_array_index((_listeners), _type, i); \
96 \
97 if (listener->base.removed) { \
98 listener->base.removed(listener->base.data); \
99 } \
100 } \
101 } while (0)
8cc092c9 102
f60c8b34 103static
d94d92ac 104void destroy_graph(struct bt_object *obj)
c0418dd9 105{
f60c8b34
JG
106 struct bt_graph *graph = container_of(obj,
107 struct bt_graph, base);
c0418dd9 108
bd14d768
PP
109 /*
110 * The graph's reference count is 0 if we're here. Increment
111 * it to avoid a double-destroy (possibly infinitely recursive)
112 * in this situation:
113 *
114 * 1. We put and destroy a connection.
115 * 2. This connection's destructor finalizes its active
116 * notification iterators.
117 * 3. A notification iterator's finalization function gets a
118 * new reference on its component (reference count goes from
119 * 0 to 1).
120 * 4. Since this component's reference count goes to 1, it takes
121 * a reference on its parent (this graph). This graph's
122 * reference count goes from 0 to 1.
123 * 5. The notification iterator's finalization function puts its
124 * component reference (reference count goes from 1 to 0).
125 * 6. Since this component's reference count goes from 1 to 0,
126 * it puts its parent (this graph). This graph's reference
127 * count goes from 1 to 0.
128 * 7. Since this graph's reference count goes from 1 to 0,
129 * its destructor is called (this function).
130 *
131 * With the incrementation below, the graph's reference count at
132 * step 4 goes from 1 to 2, and from 2 to 1 at step 6. This
133 * ensures that this function is not called two times.
134 */
d94d92ac 135 BT_LIB_LOGD("Destroying graph: %!+g", graph);
3fea54f6 136 obj->ref_count++;
bd14d768 137
49682acd
PP
138 /*
139 * Cancel the graph to disallow some operations, like creating
140 * notification iterators and adding ports to components.
141 */
a2d06fd5 142 (void) bt_private_graph_cancel((void *) graph);
49682acd 143
8cc092c9 144 /* Call all remove listeners */
d94d92ac
PP
145 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
146 graph->listeners.source_output_port_added);
147 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
148 graph->listeners.filter_output_port_added);
149 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
150 graph->listeners.filter_input_port_added);
151 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
152 graph->listeners.sink_input_port_added);
153 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_removed,
154 graph->listeners.source_output_port_removed);
155 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_removed,
156 graph->listeners.filter_output_port_removed);
157 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_removed,
158 graph->listeners.filter_input_port_removed);
159 CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_removed,
160 graph->listeners.sink_input_port_removed);
161 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
162 graph->listeners.source_filter_ports_connected);
163 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
164 graph->listeners.source_sink_ports_connected);
165 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
166 graph->listeners.filter_sink_ports_connected);
167 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_disconnected,
168 graph->listeners.source_filter_ports_disconnected);
169 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_disconnected,
170 graph->listeners.source_sink_ports_disconnected);
171 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_disconnected,
172 graph->listeners.filter_sink_ports_disconnected);
8cc092c9 173
5c563278
PP
174 if (graph->notifications) {
175 g_ptr_array_free(graph->notifications, TRUE);
d94d92ac 176 graph->notifications = NULL;
5c563278
PP
177 }
178
c0418dd9 179 if (graph->connections) {
262e5473 180 BT_LOGD_STR("Destroying connections.");
c0418dd9 181 g_ptr_array_free(graph->connections, TRUE);
d94d92ac 182 graph->connections = NULL;
c0418dd9 183 }
5c563278 184
bd14d768 185 if (graph->components) {
262e5473 186 BT_LOGD_STR("Destroying components.");
bd14d768 187 g_ptr_array_free(graph->components, TRUE);
d94d92ac 188 graph->components = NULL;
bd14d768 189 }
5c563278 190
f60c8b34
JG
191 if (graph->sinks_to_consume) {
192 g_queue_free(graph->sinks_to_consume);
d94d92ac
PP
193 graph->sinks_to_consume = NULL;
194 }
195
196 if (graph->listeners.source_output_port_added) {
197 g_array_free(graph->listeners.source_output_port_added, TRUE);
198 graph->listeners.source_output_port_added = NULL;
199 }
200
201 if (graph->listeners.filter_output_port_added) {
202 g_array_free(graph->listeners.filter_output_port_added, TRUE);
203 graph->listeners.filter_output_port_added = NULL;
204 }
205
206 if (graph->listeners.filter_input_port_added) {
207 g_array_free(graph->listeners.filter_input_port_added, TRUE);
208 graph->listeners.filter_input_port_added = NULL;
c0418dd9 209 }
1bf957a0 210
d94d92ac
PP
211 if (graph->listeners.sink_input_port_added) {
212 g_array_free(graph->listeners.sink_input_port_added, TRUE);
213 graph->listeners.sink_input_port_added = NULL;
1bf957a0
PP
214 }
215
d94d92ac
PP
216 if (graph->listeners.source_output_port_removed) {
217 g_array_free(graph->listeners.source_output_port_removed, TRUE);
218 graph->listeners.source_output_port_removed = NULL;
1bf957a0
PP
219 }
220
d94d92ac
PP
221 if (graph->listeners.filter_output_port_removed) {
222 g_array_free(graph->listeners.filter_output_port_removed, TRUE);
223 graph->listeners.filter_output_port_removed = NULL;
1bf957a0
PP
224 }
225
d94d92ac
PP
226 if (graph->listeners.filter_input_port_removed) {
227 g_array_free(graph->listeners.filter_input_port_removed, TRUE);
228 graph->listeners.filter_input_port_removed = NULL;
229 }
230
231 if (graph->listeners.sink_input_port_removed) {
232 g_array_free(graph->listeners.sink_input_port_removed, TRUE);
233 graph->listeners.sink_input_port_removed = NULL;
234 }
235
236 if (graph->listeners.source_filter_ports_connected) {
237 g_array_free(graph->listeners.source_filter_ports_connected,
238 TRUE);
239 graph->listeners.source_filter_ports_connected = NULL;
240 }
241
242 if (graph->listeners.source_sink_ports_connected) {
243 g_array_free(graph->listeners.source_sink_ports_connected,
244 TRUE);
245 graph->listeners.source_sink_ports_connected = NULL;
246 }
247
248 if (graph->listeners.filter_sink_ports_connected) {
249 g_array_free(graph->listeners.filter_sink_ports_connected,
250 TRUE);
251 graph->listeners.filter_sink_ports_connected = NULL;
252 }
253
254 if (graph->listeners.source_filter_ports_disconnected) {
255 g_array_free(graph->listeners.source_filter_ports_disconnected,
256 TRUE);
257 graph->listeners.source_filter_ports_disconnected = NULL;
258 }
259
260 if (graph->listeners.source_sink_ports_disconnected) {
261 g_array_free(graph->listeners.source_sink_ports_disconnected,
262 TRUE);
263 graph->listeners.source_sink_ports_disconnected = NULL;
264 }
265
266 if (graph->listeners.filter_sink_ports_disconnected) {
267 g_array_free(graph->listeners.filter_sink_ports_disconnected,
268 TRUE);
269 graph->listeners.filter_sink_ports_disconnected = NULL;
1bf957a0
PP
270 }
271
5c563278
PP
272 bt_object_pool_finalize(&graph->event_notif_pool);
273 bt_object_pool_finalize(&graph->packet_begin_notif_pool);
274 bt_object_pool_finalize(&graph->packet_end_notif_pool);
c0418dd9
JG
275 g_free(graph);
276}
277
5c563278
PP
278static
279void destroy_notification_event(struct bt_notification *notif,
280 struct bt_graph *graph)
281{
282 bt_notification_event_destroy(notif);
283}
284
285static
286void destroy_notification_packet_begin(struct bt_notification *notif,
287 struct bt_graph *graph)
288{
289 bt_notification_packet_begin_destroy(notif);
290}
291
292static
293void destroy_notification_packet_end(struct bt_notification *notif,
294 struct bt_graph *graph)
295{
296 bt_notification_packet_end_destroy(notif);
297}
298
299static
300void notify_notification_graph_is_destroyed(struct bt_notification *notif)
301{
302 bt_notification_unlink_graph(notif);
303}
304
a2d06fd5 305struct bt_private_graph *bt_private_graph_create(void)
c0418dd9 306{
f60c8b34 307 struct bt_graph *graph;
1bf957a0 308 int ret;
c0418dd9 309
262e5473 310 BT_LOGD_STR("Creating graph object.");
f60c8b34 311 graph = g_new0(struct bt_graph, 1);
c0418dd9 312 if (!graph) {
262e5473 313 BT_LOGE_STR("Failed to allocate one graph.");
c0418dd9
JG
314 goto end;
315 }
316
d94d92ac 317 bt_object_init_shared(&graph->base, destroy_graph);
3fea54f6
PP
318 graph->connections = g_ptr_array_new_with_free_func(
319 (GDestroyNotify) bt_object_try_spec_release);
c0418dd9 320 if (!graph->connections) {
262e5473 321 BT_LOGE_STR("Failed to allocate one GPtrArray.");
c0418dd9
JG
322 goto error;
323 }
3fea54f6
PP
324 graph->components = g_ptr_array_new_with_free_func(
325 (GDestroyNotify) bt_object_try_spec_release);
f60c8b34 326 if (!graph->components) {
262e5473 327 BT_LOGE_STR("Failed to allocate one GPtrArray.");
f60c8b34
JG
328 goto error;
329 }
330 graph->sinks_to_consume = g_queue_new();
331 if (!graph->sinks_to_consume) {
262e5473 332 BT_LOGE_STR("Failed to allocate one GQueue.");
c0418dd9
JG
333 goto error;
334 }
1bf957a0 335
d94d92ac
PP
336 bt_graph_set_can_consume(graph, true);
337 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
338 graph->listeners.source_output_port_added);
339
340 if (!graph->listeners.source_output_port_added) {
341 ret = -1;
1bf957a0
PP
342 goto error;
343 }
344
d94d92ac
PP
345 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
346 graph->listeners.filter_output_port_added);
347
348 if (!graph->listeners.filter_output_port_added) {
349 ret = -1;
1bf957a0
PP
350 goto error;
351 }
352
d94d92ac
PP
353 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
354 graph->listeners.filter_input_port_added);
355
356 if (!graph->listeners.filter_input_port_added) {
357 ret = -1;
1bf957a0
PP
358 goto error;
359 }
360
d94d92ac
PP
361 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
362 graph->listeners.sink_input_port_added);
363
364 if (!graph->listeners.sink_input_port_added) {
365 ret = -1;
366 goto error;
367 }
368
369 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_removed,
370 graph->listeners.source_output_port_removed);
371
372 if (!graph->listeners.source_output_port_removed) {
373 ret = -1;
374 goto error;
375 }
376
377 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_removed,
378 graph->listeners.filter_output_port_removed);
379
380 if (!graph->listeners.filter_output_port_removed) {
381 ret = -1;
382 goto error;
383 }
384
385 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_removed,
386 graph->listeners.filter_input_port_removed);
387
388 if (!graph->listeners.filter_input_port_removed) {
389 ret = -1;
390 goto error;
391 }
392
393 INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_removed,
394 graph->listeners.sink_input_port_removed);
395
396 if (!graph->listeners.sink_input_port_removed) {
397 ret = -1;
398 goto error;
399 }
400
401 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
402 graph->listeners.source_filter_ports_connected);
403
404 if (!graph->listeners.source_filter_ports_connected) {
405 ret = -1;
406 goto error;
407 }
408
409 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
410 graph->listeners.source_sink_ports_connected);
411
412 if (!graph->listeners.source_sink_ports_connected) {
413 ret = -1;
414 goto error;
415 }
416
417 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
418 graph->listeners.filter_sink_ports_connected);
419
420 if (!graph->listeners.filter_sink_ports_connected) {
421 ret = -1;
422 goto error;
423 }
424
425 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_disconnected,
426 graph->listeners.source_filter_ports_disconnected);
427
428 if (!graph->listeners.source_filter_ports_disconnected) {
429 ret = -1;
430 goto error;
431 }
432
433 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_disconnected,
434 graph->listeners.source_sink_ports_disconnected);
435
436 if (!graph->listeners.source_sink_ports_disconnected) {
437 ret = -1;
438 goto error;
439 }
440
441 INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_disconnected,
442 graph->listeners.filter_sink_ports_disconnected);
443
444 if (!graph->listeners.filter_sink_ports_disconnected) {
445 ret = -1;
1bf957a0
PP
446 goto error;
447 }
448
5c563278
PP
449 ret = bt_object_pool_initialize(&graph->event_notif_pool,
450 (bt_object_pool_new_object_func) bt_notification_event_new,
451 (bt_object_pool_destroy_object_func) destroy_notification_event,
452 graph);
453 if (ret) {
454 BT_LOGE("Failed to initialize event notification pool: ret=%d",
455 ret);
456 goto error;
457 }
458
459 ret = bt_object_pool_initialize(&graph->packet_begin_notif_pool,
460 (bt_object_pool_new_object_func) bt_notification_packet_begin_new,
461 (bt_object_pool_destroy_object_func) destroy_notification_packet_begin,
462 graph);
463 if (ret) {
464 BT_LOGE("Failed to initialize packet beginning notification pool: ret=%d",
465 ret);
466 goto error;
467 }
468
469 ret = bt_object_pool_initialize(&graph->packet_end_notif_pool,
470 (bt_object_pool_new_object_func) bt_notification_packet_end_new,
471 (bt_object_pool_destroy_object_func) destroy_notification_packet_end,
472 graph);
473 if (ret) {
474 BT_LOGE("Failed to initialize packet end notification pool: ret=%d",
475 ret);
476 goto error;
477 }
478
479 graph->notifications = g_ptr_array_new_with_free_func(
480 (GDestroyNotify) notify_notification_graph_is_destroyed);
d94d92ac 481 BT_LIB_LOGD("Created graph object: %!+g", graph);
262e5473 482
c0418dd9 483end:
a2d06fd5 484 return (void *) graph;
d94d92ac 485
c0418dd9 486error:
65300d60 487 BT_OBJECT_PUT_REF_AND_RESET(graph);
c0418dd9
JG
488 goto end;
489}
490
a2d06fd5
PP
491enum bt_graph_status bt_private_graph_connect_ports(
492 struct bt_private_graph *priv_graph,
d94d92ac
PP
493 struct bt_port_output *upstream_port_out,
494 struct bt_port_input *downstream_port_in,
a256a42d 495 struct bt_connection **user_connection)
f60c8b34 496{
a2d06fd5 497 struct bt_graph *graph = (void *) priv_graph;
a256a42d 498 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
f60c8b34 499 struct bt_connection *connection = NULL;
d94d92ac
PP
500 struct bt_port *upstream_port = (void *) upstream_port_out;
501 struct bt_port *downstream_port = (void *) downstream_port_in;
f60c8b34
JG
502 struct bt_component *upstream_component = NULL;
503 struct bt_component *downstream_component = NULL;
d94d92ac
PP
504 enum bt_self_component_status component_status;
505 bool init_can_consume;
f60c8b34 506
d94d92ac
PP
507 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
508 BT_ASSERT_PRE_NON_NULL(upstream_port, "Upstream port");
509 BT_ASSERT_PRE_NON_NULL(downstream_port, "Downstream port port");
510 BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
511 BT_ASSERT_PRE(!bt_port_is_connected(upstream_port),
512 "Upstream port is already connected: %!+p", upstream_port);
513 BT_ASSERT_PRE(!bt_port_is_connected(downstream_port),
514 "Downstream port is already connected: %!+p", downstream_port);
515 BT_ASSERT_PRE(bt_port_borrow_component((void *) upstream_port),
516 "Upstream port does not belong to a component: %!+p",
517 upstream_port);
518 BT_ASSERT_PRE(bt_port_borrow_component((void *) downstream_port),
519 "Downstream port does not belong to a component: %!+p",
520 downstream_port);
4aa7981f 521 init_can_consume = graph->can_consume;
d94d92ac
PP
522 BT_LIB_LOGD("Connecting component ports within graph: "
523 "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
524 graph, upstream_port, downstream_port);
525 bt_graph_set_can_consume(graph, false);
526 upstream_component = bt_port_borrow_component(
527 (void *) upstream_port);
528 downstream_component = bt_port_borrow_component(
529 (void *) downstream_port);
262e5473 530
0d8b4d8e
PP
531 /*
532 * At this point the ports are not connected yet. Both
533 * components need to accept an eventual connection to their
534 * port by the other port before we continue.
535 */
d94d92ac
PP
536 BT_LIB_LOGD("Asking upstream component to accept the connection: "
537 "%![comp-]+c", upstream_component);
0d8b4d8e 538 component_status = bt_component_accept_port_connection(
d94d92ac
PP
539 upstream_component, (void *) upstream_port,
540 (void *) downstream_port);
541 if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
542 if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
262e5473
PP
543 BT_LOGD_STR("Upstream component refused the connection.");
544 } else {
545 BT_LOGW("Cannot ask upstream component to accept the connection: "
d94d92ac 546 "status=%s", bt_self_component_status_string(component_status));
262e5473
PP
547 }
548
d94d92ac 549 status = (int) component_status;
a256a42d 550 goto end;
0d8b4d8e 551 }
262e5473 552
d94d92ac
PP
553 BT_LIB_LOGD("Asking downstream component to accept the connection: "
554 "%![comp-]+c", downstream_component);
0d8b4d8e 555 component_status = bt_component_accept_port_connection(
d94d92ac
PP
556 downstream_component, (void *) downstream_port,
557 (void *) upstream_port);
558 if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
559 if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
262e5473
PP
560 BT_LOGD_STR("Downstream component refused the connection.");
561 } else {
562 BT_LOGW("Cannot ask downstream component to accept the connection: "
d94d92ac 563 "status=%s", bt_self_component_status_string(component_status));
262e5473
PP
564 }
565
d94d92ac 566 status = (int) component_status;
a256a42d 567 goto end;
0d8b4d8e
PP
568 }
569
262e5473 570 BT_LOGD_STR("Creating connection.");
d94d92ac
PP
571 connection = bt_connection_create(graph, (void *) upstream_port,
572 (void *) downstream_port);
f60c8b34 573 if (!connection) {
262e5473 574 BT_LOGW("Cannot create connection object.");
a256a42d
PP
575 status = BT_GRAPH_STATUS_NOMEM;
576 goto end;
f60c8b34
JG
577 }
578
d94d92ac 579 BT_LIB_LOGD("Connection object created: %!+x", connection);
262e5473 580
f60c8b34 581 /*
72b913fb
PP
582 * Ownership of upstream_component/downstream_component and of
583 * the connection object is transferred to the graph.
f60c8b34
JG
584 */
585 g_ptr_array_add(graph->connections, connection);
ffeb0eed 586
f60c8b34 587 /*
0d8b4d8e 588 * Notify both components that their port is connected.
f60c8b34 589 */
d94d92ac
PP
590 BT_LIB_LOGD("Notifying upstream component that its port is connected: "
591 "%![comp-]+c, %![port-]+p", upstream_component, upstream_port);
bf55043c 592 component_status = bt_component_port_connected(upstream_component,
d94d92ac
PP
593 (void *) upstream_port, (void *) downstream_port);
594 if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
595 BT_LIB_LOGW("Error while notifying upstream component that its port is connected: "
596 "status=%s, %![graph-]+g, %![up-comp-]+c, "
597 "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
598 bt_self_component_status_string(component_status),
599 graph, upstream_component, downstream_component,
600 upstream_port, downstream_port);
bf55043c 601 bt_connection_end(connection, true);
d94d92ac 602 status = (int) component_status;
bf55043c
PP
603 goto end;
604 }
605
606 connection->notified_upstream_port_connected = true;
d94d92ac
PP
607 BT_LIB_LOGD("Notifying downstream component that its port is connected: "
608 "%![comp-]+c, %![port-]+p", downstream_component,
609 downstream_port);
bf55043c 610 component_status = bt_component_port_connected(downstream_component,
d94d92ac
PP
611 (void *) downstream_port, (void *) upstream_port);
612 if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
613 BT_LIB_LOGW("Error while notifying downstream component that its port is connected: "
614 "status=%s, %![graph-]+g, %![up-comp-]+c, "
615 "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
616 bt_self_component_status_string(component_status),
617 graph, upstream_component, downstream_component,
618 upstream_port, downstream_port);
bf55043c 619 bt_connection_end(connection, true);
d94d92ac 620 status = (int) component_status;
bf55043c
PP
621 goto end;
622 }
623
624 connection->notified_downstream_port_connected = true;
1bf957a0
PP
625
626 /*
0d8b4d8e 627 * Notify the graph's creator that both ports are connected.
1bf957a0 628 */
262e5473 629 BT_LOGD_STR("Notifying graph's user that new component ports are connected.");
f345f8bb 630 bt_graph_notify_ports_connected(graph, upstream_port, downstream_port);
bf55043c 631 connection->notified_graph_ports_connected = true;
d94d92ac
PP
632 BT_LIB_LOGD("Connected component ports within graph: "
633 "%![graph-]+g, %![up-comp-]+c, %![down-comp-]+c, "
634 "%![up-port-]+p, %![down-port-]+p",
635 graph, upstream_component, downstream_component,
636 upstream_port, downstream_port);
1bf957a0 637
a256a42d 638 if (user_connection) {
1a6a376a
PP
639 /* Move reference to user */
640 *user_connection = connection;
641 connection = NULL;
a256a42d
PP
642 }
643
f60c8b34 644end:
65300d60 645 bt_object_put_ref(connection);
d94d92ac
PP
646 (void) init_can_consume;
647 bt_graph_set_can_consume(graph, init_can_consume);
a256a42d 648 return status;
f60c8b34
JG
649}
650
ad847455 651static inline
d94d92ac 652enum bt_graph_status consume_graph_sink(struct bt_component_sink *comp)
c0418dd9 653{
d94d92ac
PP
654 enum bt_self_component_status comp_status;
655 struct bt_component_class_sink *sink_class = NULL;
656
657 BT_ASSERT(comp);
658 sink_class = (void *) comp->parent.class;
659 BT_ASSERT(sink_class->methods.consume);
660 BT_LIB_LOGD("Calling user's consume method: %!+c", comp);
661 comp_status = sink_class->methods.consume((void *) comp);
662 BT_LOGD("User method returned: status=%s",
663 bt_self_component_status_string(comp_status));
664 BT_ASSERT_PRE(comp_status == BT_SELF_COMPONENT_STATUS_OK ||
665 comp_status == BT_SELF_COMPONENT_STATUS_END ||
666 comp_status == BT_SELF_COMPONENT_STATUS_AGAIN ||
667 comp_status == BT_SELF_COMPONENT_STATUS_ERROR ||
668 comp_status == BT_SELF_COMPONENT_STATUS_NOMEM,
669 "Invalid component status returned by consuming method: "
670 "status=%s", bt_self_component_status_string(comp_status));
671 if (comp_status < 0) {
672 BT_LOGW_STR("Consume method failed.");
673 goto end;
674 }
675
676 BT_LIB_LOGV("Consumed from sink: %![comp-]+c, status=%s",
677 comp, bt_self_component_status_string(comp_status));
678
679end:
680 return (int) comp_status;
8ed535b5
PP
681}
682
683/*
684 * `node` is removed from the queue of sinks to consume when passed to
685 * this function. This function adds it back to the queue if there's
686 * still something to consume afterwards.
687 */
ad847455 688static inline
d94d92ac 689enum bt_graph_status consume_sink_node(struct bt_graph *graph, GList *node)
8ed535b5
PP
690{
691 enum bt_graph_status status;
d94d92ac 692 struct bt_component_sink *sink;
8ed535b5
PP
693
694 sink = node->data;
695 status = consume_graph_sink(sink);
ad847455 696 if (unlikely(status != BT_GRAPH_STATUS_END)) {
8ed535b5 697 g_queue_push_tail_link(graph->sinks_to_consume, node);
f60c8b34
JG
698 goto end;
699 }
700
701 /* End reached, the node is not added back to the queue and free'd. */
8ed535b5 702 g_queue_delete_link(graph->sinks_to_consume, node);
f60c8b34
JG
703
704 /* Don't forward an END status if there are sinks left to consume. */
705 if (!g_queue_is_empty(graph->sinks_to_consume)) {
706 status = BT_GRAPH_STATUS_OK;
707 goto end;
708 }
8ed535b5
PP
709
710end:
d94d92ac
PP
711 BT_LIB_LOGV("Consumed sink node: %![comp-]+c, status=%s",
712 sink, bt_graph_status_string(status));
8ed535b5
PP
713 return status;
714}
715
716BT_HIDDEN
717enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
d94d92ac 718 struct bt_component_sink *sink)
8ed535b5
PP
719{
720 enum bt_graph_status status;
721 GList *sink_node;
722 int index;
723
d94d92ac
PP
724 BT_LIB_LOGV("Making specific sink consume: %![comp-]+c", sink);
725 BT_ASSERT(bt_component_borrow_graph((void *) sink) == graph);
8ed535b5
PP
726
727 if (g_queue_is_empty(graph->sinks_to_consume)) {
728 BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
729 status = BT_GRAPH_STATUS_END;
730 goto end;
731 }
732
733 index = g_queue_index(graph->sinks_to_consume, sink);
734 if (index < 0) {
735 BT_LOGV_STR("Sink is not marked as consumable: sink is ended.");
736 status = BT_GRAPH_STATUS_END;
737 goto end;
738 }
739
740 sink_node = g_queue_pop_nth_link(graph->sinks_to_consume, index);
f6ccaed9 741 BT_ASSERT(sink_node);
8ed535b5
PP
742 status = consume_sink_node(graph, sink_node);
743
744end:
745 return status;
746}
747
ad847455 748static inline
d94d92ac 749enum bt_graph_status consume_no_check(struct bt_graph *graph)
8ed535b5
PP
750{
751 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
752 struct bt_component *sink;
753 GList *current_node;
754
f6ccaed9
PP
755 BT_ASSERT_PRE(graph->has_sink,
756 "Graph has no sink component: %!+g", graph);
d94d92ac 757 BT_LIB_LOGV("Making next sink consume: %![graph-]+g", graph);
8ed535b5 758
ad847455 759 if (unlikely(g_queue_is_empty(graph->sinks_to_consume))) {
8ed535b5
PP
760 BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
761 status = BT_GRAPH_STATUS_END;
762 goto end;
763 }
764
765 current_node = g_queue_pop_head_link(graph->sinks_to_consume);
766 sink = current_node->data;
d94d92ac 767 BT_LIB_LOGV("Chose next sink to consume: %!+c", sink);
8ed535b5
PP
768 status = consume_sink_node(graph, current_node);
769
f60c8b34
JG
770end:
771 return status;
c0418dd9
JG
772}
773
a2d06fd5
PP
774enum bt_graph_status bt_private_graph_consume(
775 struct bt_private_graph *priv_graph)
851b70bd 776{
a2d06fd5 777 struct bt_graph *graph = (void *) priv_graph;
f6ccaed9 778 enum bt_graph_status status;
1d915789 779
f6ccaed9
PP
780 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
781 BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
782 BT_ASSERT_PRE(graph->can_consume,
783 "Cannot consume graph in its current state: %!+g", graph);
ad847455 784 bt_graph_set_can_consume(graph, BT_FALSE);
d94d92ac 785 status = consume_no_check(graph);
ad847455 786 bt_graph_set_can_consume(graph, BT_TRUE);
26a15756 787 return status;
851b70bd
PP
788}
789
d94d92ac 790enum bt_graph_status bt_private_graph_run(struct bt_private_graph *priv_graph)
f60c8b34 791{
a2d06fd5 792 struct bt_graph *graph = (void *) priv_graph;
72b913fb 793 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
f60c8b34 794
d94d92ac
PP
795 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
796 BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
ad847455
PP
797 BT_ASSERT_PRE(graph->can_consume,
798 "Cannot consume graph in its current state: %!+g", graph);
799 bt_graph_set_can_consume(graph, BT_FALSE);
d94d92ac 800 BT_LIB_LOGV("Running graph: %!+g", graph);
262e5473 801
f60c8b34 802 do {
851b70bd
PP
803 /*
804 * Check if the graph is canceled at each iteration. If
805 * the graph was canceled by another thread or by a
d94d92ac
PP
806 * signal handler, this is not a warning nor an error,
807 * it was intentional: log with a DEBUG level only.
851b70bd 808 */
ad847455 809 if (unlikely(graph->canceled)) {
d94d92ac
PP
810 BT_LIB_LOGD("Stopping the graph: graph is canceled: "
811 "%!+g", graph);
851b70bd
PP
812 status = BT_GRAPH_STATUS_CANCELED;
813 goto end;
814 }
815
d94d92ac 816 status = consume_no_check(graph);
ad847455 817 if (unlikely(status == BT_GRAPH_STATUS_AGAIN)) {
f60c8b34 818 /*
202a3a13
PP
819 * If AGAIN is received and there are multiple
820 * sinks, go ahead and consume from the next
821 * sink.
f60c8b34 822 *
202a3a13
PP
823 * However, in the case where a single sink is
824 * left, the caller can decide to busy-wait and
d94d92ac
PP
825 * call bt_private_graph_run() continuously
826 * until the source is ready or it can decide to
827 * sleep for an arbitrary amount of time.
f60c8b34
JG
828 */
829 if (graph->sinks_to_consume->length > 1) {
72b913fb 830 status = BT_GRAPH_STATUS_OK;
f60c8b34 831 }
2de524b3
PP
832 } else if (status == BT_GRAPH_STATUS_NO_SINK) {
833 goto end;
f60c8b34 834 }
72b913fb 835 } while (status == BT_GRAPH_STATUS_OK);
f60c8b34
JG
836
837 if (g_queue_is_empty(graph->sinks_to_consume)) {
72b913fb 838 status = BT_GRAPH_STATUS_END;
f60c8b34 839 }
262e5473 840
202a3a13 841end:
d94d92ac
PP
842 BT_LIB_LOGV("Graph ran: %![graph-]+g, status=%s", graph,
843 bt_graph_status_string(status));
844 bt_graph_set_can_consume(graph, BT_TRUE);
72b913fb 845 return status;
f60c8b34 846}
1bf957a0 847
d94d92ac
PP
848enum bt_graph_status
849bt_private_graph_add_source_component_output_port_added_listener(
850 struct bt_private_graph *priv_graph,
851 bt_private_graph_source_component_output_port_added_listener func,
852 bt_private_graph_listener_removed listener_removed, void *data,
853 int *out_listener_id)
1bf957a0 854{
d94d92ac
PP
855 struct bt_graph *graph = (void *) priv_graph;
856 struct bt_graph_listener_port_added listener = {
857 .base = {
858 .removed = listener_removed,
859 .data = data,
860 },
861 .func = (port_added_func_t) func,
1bf957a0 862 };
d94d92ac 863 int listener_id;
1bf957a0 864
d94d92ac
PP
865 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
866 BT_ASSERT_PRE_NON_NULL(func, "Listener");
867 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
868 BT_ASSERT_PRE(!graph->in_remove_listener,
869 "Graph currently executing a \"listener removed\" listener: "
870 "%!+g", graph);
871 g_array_append_val(graph->listeners.source_output_port_added, listener);
872 listener_id = graph->listeners.source_output_port_added->len - 1;
873 BT_LIB_LOGV("Added \"source component output port added\" listener to graph: "
874 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
875 listener_id);
876
877 if (listener_id) {
878 *out_listener_id = listener_id;
879 }
880
881 return BT_GRAPH_STATUS_OK;
1bf957a0
PP
882}
883
d94d92ac
PP
884enum bt_graph_status
885bt_private_graph_add_filter_component_output_port_added_listener(
a2d06fd5 886 struct bt_private_graph *priv_graph,
d94d92ac
PP
887 bt_private_graph_filter_component_output_port_added_listener func,
888 bt_private_graph_listener_removed listener_removed, void *data,
889 int *out_listener_id)
1bf957a0 890{
a2d06fd5 891 struct bt_graph *graph = (void *) priv_graph;
d94d92ac
PP
892 struct bt_graph_listener_port_added listener = {
893 .base = {
894 .removed = listener_removed,
895 .data = data,
896 },
897 .func = (port_added_func_t) func,
898 };
899 int listener_id;
1bf957a0 900
d94d92ac
PP
901 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
902 BT_ASSERT_PRE_NON_NULL(func, "Listener");
903 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
904 BT_ASSERT_PRE(!graph->in_remove_listener,
905 "Graph currently executing a \"listener removed\" listener: "
906 "%!+g", graph);
907 g_array_append_val(graph->listeners.filter_output_port_added, listener);
908 listener_id = graph->listeners.filter_output_port_added->len - 1;
909 BT_LIB_LOGV("Added \"filter component output port added\" listener to graph: "
910 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
911 listener_id);
912
913 if (listener_id) {
914 *out_listener_id = listener_id;
915 }
916
917 return BT_GRAPH_STATUS_OK;
918}
262e5473 919
d94d92ac
PP
920enum bt_graph_status
921bt_private_graph_add_filter_component_input_port_added_listener(
922 struct bt_private_graph *priv_graph,
923 bt_private_graph_filter_component_input_port_added_listener func,
924 bt_private_graph_listener_removed listener_removed, void *data,
925 int *out_listener_id)
926{
927 struct bt_graph *graph = (void *) priv_graph;
928 struct bt_graph_listener_port_added listener = {
929 .base = {
930 .removed = listener_removed,
931 .data = data,
932 },
933 .func = (port_added_func_t) func,
934 };
935 int listener_id;
8cc092c9 936
d94d92ac
PP
937 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
938 BT_ASSERT_PRE_NON_NULL(func, "Listener");
939 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
940 BT_ASSERT_PRE(!graph->in_remove_listener,
941 "Graph currently executing a \"listener removed\" listener: "
942 "%!+g", graph);
943 g_array_append_val(graph->listeners.filter_input_port_added, listener);
944 listener_id = graph->listeners.filter_input_port_added->len - 1;
945 BT_LIB_LOGV("Added \"filter component input port added\" listener to graph: "
946 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
947 listener_id);
948
949 if (listener_id) {
950 *out_listener_id = listener_id;
951 }
952
953 return BT_GRAPH_STATUS_OK;
954}
1bf957a0 955
d94d92ac
PP
956enum bt_graph_status
957bt_private_graph_add_sink_component_input_port_added_listener(
958 struct bt_private_graph *priv_graph,
959 bt_private_graph_sink_component_input_port_added_listener func,
960 bt_private_graph_listener_removed listener_removed, void *data,
961 int *out_listener_id)
962{
963 struct bt_graph *graph = (void *) priv_graph;
964 struct bt_graph_listener_port_added listener = {
965 .base = {
966 .removed = listener_removed,
967 .data = data,
968 },
969 .func = (port_added_func_t) func,
970 };
971 int listener_id;
1bf957a0 972
d94d92ac
PP
973 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
974 BT_ASSERT_PRE_NON_NULL(func, "Listener");
975 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
976 BT_ASSERT_PRE(!graph->in_remove_listener,
977 "Graph currently executing a \"listener removed\" listener: "
978 "%!+g", graph);
979 g_array_append_val(graph->listeners.sink_input_port_added, listener);
980 listener_id = graph->listeners.sink_input_port_added->len - 1;
981 BT_LIB_LOGV("Added \"sink component input port added\" listener to graph: "
982 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
983 listener_id);
984
985 if (listener_id) {
986 *out_listener_id = listener_id;
987 }
988
989 return BT_GRAPH_STATUS_OK;
1bf957a0
PP
990}
991
d94d92ac
PP
992enum bt_graph_status
993bt_private_graph_add_source_component_output_port_removed_listener(
a2d06fd5 994 struct bt_private_graph *priv_graph,
d94d92ac
PP
995 bt_private_graph_source_component_output_port_removed_listener func,
996 bt_private_graph_listener_removed listener_removed, void *data,
997 int *out_listener_id)
1bf957a0 998{
a2d06fd5 999 struct bt_graph *graph = (void *) priv_graph;
d94d92ac
PP
1000 struct bt_graph_listener_port_removed listener = {
1001 .base = {
1002 .removed = listener_removed,
1003 .data = data,
1004 },
1005 .func = (port_removed_func_t) func,
1006 };
1007 int listener_id;
1bf957a0 1008
d94d92ac
PP
1009 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1010 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1011 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1012 BT_ASSERT_PRE(!graph->in_remove_listener,
1013 "Graph currently executing a \"listener removed\" listener: "
1014 "%!+g", graph);
1015 g_array_append_val(graph->listeners.source_output_port_removed, listener);
1016 listener_id = graph->listeners.source_output_port_removed->len - 1;
1017 BT_LIB_LOGV("Added \"source component output port removed\" listener to graph: "
1018 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1019 listener_id);
1020
1021 if (listener_id) {
1022 *out_listener_id = listener_id;
1023 }
1024
1025 return BT_GRAPH_STATUS_OK;
1026}
262e5473 1027
d94d92ac
PP
1028enum bt_graph_status
1029bt_private_graph_add_filter_component_output_port_removed_listener(
1030 struct bt_private_graph *priv_graph,
1031 bt_private_graph_filter_component_output_port_removed_listener func,
1032 bt_private_graph_listener_removed listener_removed, void *data,
1033 int *out_listener_id)
1034{
1035 struct bt_graph *graph = (void *) priv_graph;
1036 struct bt_graph_listener_port_removed listener = {
1037 .base = {
1038 .removed = listener_removed,
1039 .data = data,
1040 },
1041 .func = (port_removed_func_t) func,
1042 };
1043 int listener_id;
8cc092c9 1044
d94d92ac
PP
1045 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1046 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1047 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1048 BT_ASSERT_PRE(!graph->in_remove_listener,
1049 "Graph currently executing a \"listener removed\" listener: "
1050 "%!+g", graph);
1051 g_array_append_val(graph->listeners.filter_output_port_removed, listener);
1052 listener_id = graph->listeners.filter_output_port_removed->len - 1;
1053 BT_LIB_LOGV("Added \"filter component output port removed\" listener to graph: "
1054 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1055 listener_id);
1056
1057 if (listener_id) {
1058 *out_listener_id = listener_id;
1059 }
1060
1061 return BT_GRAPH_STATUS_OK;
1062}
1bf957a0 1063
d94d92ac
PP
1064enum bt_graph_status
1065bt_private_graph_add_filter_component_input_port_removed_listener(
1066 struct bt_private_graph *priv_graph,
1067 bt_private_graph_filter_component_input_port_removed_listener func,
1068 bt_private_graph_listener_removed listener_removed, void *data,
1069 int *out_listener_id)
1070{
1071 struct bt_graph *graph = (void *) priv_graph;
1072 struct bt_graph_listener_port_removed listener = {
1073 .base = {
1074 .removed = listener_removed,
1075 .data = data,
1076 },
1077 .func = (port_removed_func_t) func,
1078 };
1079 int listener_id;
1bf957a0 1080
d94d92ac
PP
1081 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1082 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1083 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1084 BT_ASSERT_PRE(!graph->in_remove_listener,
1085 "Graph currently executing a \"listener removed\" listener: "
1086 "%!+g", graph);
1087 g_array_append_val(graph->listeners.filter_input_port_removed, listener);
1088 listener_id = graph->listeners.filter_input_port_removed->len - 1;
1089 BT_LIB_LOGV("Added \"filter component input port removed\" listener to graph: "
1090 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1091 listener_id);
1092
1093 if (listener_id) {
1094 *out_listener_id = listener_id;
1095 }
1096
1097 return BT_GRAPH_STATUS_OK;
1bf957a0
PP
1098}
1099
d94d92ac
PP
1100enum bt_graph_status
1101bt_private_graph_add_sink_component_input_port_removed_listener(
a2d06fd5 1102 struct bt_private_graph *priv_graph,
d94d92ac
PP
1103 bt_private_graph_sink_component_input_port_removed_listener func,
1104 bt_private_graph_listener_removed listener_removed, void *data,
1105 int *out_listener_id)
1bf957a0 1106{
a2d06fd5 1107 struct bt_graph *graph = (void *) priv_graph;
d94d92ac
PP
1108 struct bt_graph_listener_port_removed listener = {
1109 .base = {
1110 .removed = listener_removed,
1111 .data = data,
1112 },
1113 .func = (port_removed_func_t) func,
1114 };
1115 int listener_id;
1bf957a0 1116
d94d92ac
PP
1117 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1118 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1119 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1120 BT_ASSERT_PRE(!graph->in_remove_listener,
1121 "Graph currently executing a \"listener removed\" listener: "
1122 "%!+g", graph);
1123 g_array_append_val(graph->listeners.sink_input_port_removed, listener);
1124 listener_id = graph->listeners.sink_input_port_removed->len - 1;
1125 BT_LIB_LOGV("Added \"sink component input port removed\" listener to graph: "
1126 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1127 listener_id);
1128
1129 if (listener_id) {
1130 *out_listener_id = listener_id;
1131 }
1132
1133 return BT_GRAPH_STATUS_OK;
1134}
262e5473 1135
d94d92ac
PP
1136enum bt_graph_status
1137bt_private_graph_add_source_filter_component_ports_connected_listener(
1138 struct bt_private_graph *priv_graph,
1139 bt_private_graph_source_filter_component_ports_connected_listener func,
1140 bt_private_graph_listener_removed listener_removed, void *data,
1141 int *out_listener_id)
1142{
1143 struct bt_graph *graph = (void *) priv_graph;
1144 struct bt_graph_listener_ports_connected listener = {
1145 .base = {
1146 .removed = listener_removed,
1147 .data = data,
1148 },
1149 .func = (ports_connected_func_t) func,
1150 };
1151 int listener_id;
8cc092c9 1152
d94d92ac
PP
1153 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1154 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1155 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1156 BT_ASSERT_PRE(!graph->in_remove_listener,
1157 "Graph currently executing a \"listener removed\" listener: "
1158 "%!+g", graph);
1159 g_array_append_val(graph->listeners.source_filter_ports_connected,
1160 listener);
1161 listener_id = graph->listeners.source_filter_ports_connected->len - 1;
1162 BT_LIB_LOGV("Added \"source to filter component ports connected\" listener to graph: "
1163 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1164 listener_id);
1165
1166 if (listener_id) {
1167 *out_listener_id = listener_id;
1168 }
1169
1170 return BT_GRAPH_STATUS_OK;
1171}
1bf957a0 1172
d94d92ac
PP
1173enum bt_graph_status
1174bt_private_graph_add_source_sink_component_ports_connected_listener(
1175 struct bt_private_graph *priv_graph,
1176 bt_private_graph_source_sink_component_ports_connected_listener func,
1177 bt_private_graph_listener_removed listener_removed, void *data,
1178 int *out_listener_id)
1179{
1180 struct bt_graph *graph = (void *) priv_graph;
1181 struct bt_graph_listener_ports_connected listener = {
1182 .base = {
1183 .removed = listener_removed,
1184 .data = data,
1185 },
1186 .func = (ports_connected_func_t) func,
1187 };
1188 int listener_id;
1bf957a0 1189
d94d92ac
PP
1190 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1191 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1192 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1193 BT_ASSERT_PRE(!graph->in_remove_listener,
1194 "Graph currently executing a \"listener removed\" listener: "
1195 "%!+g", graph);
1196 g_array_append_val(graph->listeners.source_sink_ports_connected,
1197 listener);
1198 listener_id = graph->listeners.source_sink_ports_connected->len - 1;
1199 BT_LIB_LOGV("Added \"source to sink component ports connected\" listener to graph: "
1200 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1201 listener_id);
1202
1203 if (listener_id) {
1204 *out_listener_id = listener_id;
1205 }
1206
1207 return BT_GRAPH_STATUS_OK;
1bf957a0
PP
1208}
1209
d94d92ac
PP
1210enum bt_graph_status
1211bt_private_graph_add_filter_sink_component_ports_connected_listener(
a2d06fd5 1212 struct bt_private_graph *priv_graph,
d94d92ac
PP
1213 bt_private_graph_filter_sink_component_ports_connected_listener func,
1214 bt_private_graph_listener_removed listener_removed, void *data,
1215 int *out_listener_id)
1bf957a0 1216{
a2d06fd5 1217 struct bt_graph *graph = (void *) priv_graph;
d94d92ac
PP
1218 struct bt_graph_listener_ports_connected listener = {
1219 .base = {
1220 .removed = listener_removed,
1221 .data = data,
1222 },
1223 .func = (ports_connected_func_t) func,
1224 };
1225 int listener_id;
1bf957a0 1226
d94d92ac
PP
1227 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1228 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1229 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1230 BT_ASSERT_PRE(!graph->in_remove_listener,
1231 "Graph currently executing a \"listener removed\" listener: "
1232 "%!+g", graph);
1233 g_array_append_val(graph->listeners.filter_sink_ports_connected,
1234 listener);
1235 listener_id = graph->listeners.filter_sink_ports_connected->len - 1;
1236 BT_LIB_LOGV("Added \"filter to sink component ports connected\" listener to graph: "
1237 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1238 listener_id);
1239
1240 if (listener_id) {
1241 *out_listener_id = listener_id;
1242 }
1243
1244 return BT_GRAPH_STATUS_OK;
1245}
262e5473 1246
d94d92ac
PP
1247enum bt_graph_status
1248bt_private_graph_add_source_filter_component_ports_disconnected_listener(
1249 struct bt_private_graph *priv_graph,
1250 bt_private_graph_source_filter_component_ports_disconnected_listener func,
1251 bt_private_graph_listener_removed listener_removed, void *data,
1252 int *out_listener_id)
1253{
1254 struct bt_graph *graph = (void *) priv_graph;
1255 struct bt_graph_listener_ports_disconnected listener = {
1256 .base = {
1257 .removed = listener_removed,
1258 .data = data,
1259 },
1260 .func = (ports_disconnected_func_t) func,
1261 };
1262 int listener_id;
8cc092c9 1263
d94d92ac
PP
1264 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1265 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1266 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1267 BT_ASSERT_PRE(!graph->in_remove_listener,
1268 "Graph currently executing a \"listener removed\" listener: "
1269 "%!+g", graph);
1270 g_array_append_val(graph->listeners.source_filter_ports_disconnected,
1271 listener);
1272 listener_id = graph->listeners.source_filter_ports_disconnected->len - 1;
1273 BT_LIB_LOGV("Added \"source to filter component ports disconnected\" listener to graph: "
1274 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1275 listener_id);
1276
1277 if (listener_id) {
1278 *out_listener_id = listener_id;
1279 }
1280
1281 return BT_GRAPH_STATUS_OK;
1282}
1bf957a0 1283
d94d92ac
PP
1284enum bt_graph_status
1285bt_private_graph_add_source_sink_component_ports_disconnected_listener(
1286 struct bt_private_graph *priv_graph,
1287 bt_private_graph_source_sink_component_ports_disconnected_listener func,
1288 bt_private_graph_listener_removed listener_removed, void *data,
1289 int *out_listener_id)
1290{
1291 struct bt_graph *graph = (void *) priv_graph;
1292 struct bt_graph_listener_ports_disconnected listener = {
1293 .base = {
1294 .removed = listener_removed,
1295 .data = data,
1296 },
1297 .func = (ports_disconnected_func_t) func,
1298 };
1299 int listener_id;
1bf957a0 1300
d94d92ac
PP
1301 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1302 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1303 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1304 BT_ASSERT_PRE(!graph->in_remove_listener,
1305 "Graph currently executing a \"listener removed\" listener: "
1306 "%!+g", graph);
1307 g_array_append_val(graph->listeners.source_sink_ports_disconnected,
1308 listener);
1309 listener_id = graph->listeners.source_sink_ports_disconnected->len - 1;
1310 BT_LIB_LOGV("Added \"source to sink component ports disconnected\" listener to graph: "
1311 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1312 listener_id);
1313
1314 if (listener_id) {
1315 *out_listener_id = listener_id;
1316 }
1317
1318 return BT_GRAPH_STATUS_OK;
1319}
1320
1321enum bt_graph_status
1322bt_private_graph_add_filter_sink_component_ports_disconnected_listener(
1323 struct bt_private_graph *priv_graph,
1324 bt_private_graph_filter_sink_component_ports_disconnected_listener func,
1325 bt_private_graph_listener_removed listener_removed, void *data,
1326 int *out_listener_id)
1327{
1328 struct bt_graph *graph = (void *) priv_graph;
1329 struct bt_graph_listener_ports_disconnected listener = {
1330 .base = {
1331 .removed = listener_removed,
1332 .data = data,
1333 },
1334 .func = (ports_disconnected_func_t) func,
1335 };
1336 int listener_id;
1337
1338 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1339 BT_ASSERT_PRE_NON_NULL(func, "Listener");
1340 BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
1341 BT_ASSERT_PRE(!graph->in_remove_listener,
1342 "Graph currently executing a \"listener removed\" listener: "
1343 "%!+g", graph);
1344 g_array_append_val(graph->listeners.filter_sink_ports_disconnected,
1345 listener);
1346 listener_id = graph->listeners.filter_sink_ports_disconnected->len - 1;
1347 BT_LIB_LOGV("Added \"filter to sink component ports disconnected\" listener to graph: "
1348 "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
1349 listener_id);
1350
1351 if (listener_id) {
1352 *out_listener_id = listener_id;
1353 }
1354
1355 return BT_GRAPH_STATUS_OK;
1bf957a0
PP
1356}
1357
1358BT_HIDDEN
1359void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port)
1360{
d94d92ac
PP
1361 uint64_t i;
1362 GArray *listeners;
1363 struct bt_component *comp;
1bf957a0 1364
d94d92ac
PP
1365 BT_ASSERT(graph);
1366 BT_ASSERT(port);
1367 BT_LIB_LOGV("Notifying graph listeners that a port was added: "
1368 "%![graph-]+g, %![port-]+p", graph, port);
1369 comp = bt_port_borrow_component(port);
1370 BT_ASSERT(comp);
1371
1372 switch (comp->class->type) {
1373 case BT_COMPONENT_CLASS_TYPE_SOURCE:
1374 {
1375 switch (port->type) {
1376 case BT_PORT_TYPE_OUTPUT:
1377 listeners = graph->listeners.source_output_port_added;
1378 break;
1379 default:
1380 abort();
1381 }
1382
1383 break;
1384 }
1385 case BT_COMPONENT_CLASS_TYPE_FILTER:
1386 {
1387 switch (port->type) {
1388 case BT_PORT_TYPE_INPUT:
1389 listeners = graph->listeners.filter_input_port_added;
1390 break;
1391 case BT_PORT_TYPE_OUTPUT:
1392 listeners = graph->listeners.filter_output_port_added;
1393 break;
1394 default:
1395 abort();
1396 }
262e5473 1397
d94d92ac
PP
1398 break;
1399 }
1400 case BT_COMPONENT_CLASS_TYPE_SINK:
1401 {
1402 switch (port->type) {
1403 case BT_PORT_TYPE_INPUT:
1404 listeners = graph->listeners.sink_input_port_added;
1405 break;
1406 default:
1407 abort();
1408 }
1bf957a0 1409
d94d92ac
PP
1410 break;
1411 }
1412 default:
1413 abort();
1414 }
1415
1416 for (i = 0; i < listeners->len; i++) {
1417 struct bt_graph_listener_port_added *listener =
1418 &g_array_index(listeners,
1419 struct bt_graph_listener_port_added, i);
1420
1421 BT_ASSERT(listener->func);
1422 listener->func(comp, port, listener->base.data);
1bf957a0
PP
1423 }
1424}
1425
1426BT_HIDDEN
1427void bt_graph_notify_port_removed(struct bt_graph *graph,
1428 struct bt_component *comp, struct bt_port *port)
1429{
d94d92ac
PP
1430 uint64_t i;
1431 GArray *listeners;
1432
1433 BT_ASSERT(graph);
1434 BT_ASSERT(port);
1435 BT_LIB_LOGV("Notifying graph listeners that a port was removed: "
1436 "%![graph-]+g, %![comp-]+c, %![port-]+p", graph, comp, port);
1437
1438 switch (comp->class->type) {
1439 case BT_COMPONENT_CLASS_TYPE_SOURCE:
1440 {
1441 switch (port->type) {
1442 case BT_PORT_TYPE_OUTPUT:
1443 listeners = graph->listeners.source_output_port_removed;
1444 break;
1445 default:
1446 abort();
1447 }
1448
1449 break;
1450 }
1451 case BT_COMPONENT_CLASS_TYPE_FILTER:
1452 {
1453 switch (port->type) {
1454 case BT_PORT_TYPE_INPUT:
1455 listeners = graph->listeners.filter_input_port_removed;
1456 break;
1457 case BT_PORT_TYPE_OUTPUT:
1458 listeners = graph->listeners.filter_output_port_removed;
1459 break;
1460 default:
1461 abort();
1462 }
1463
1464 break;
1465 }
1466 case BT_COMPONENT_CLASS_TYPE_SINK:
1467 {
1468 switch (port->type) {
1469 case BT_PORT_TYPE_INPUT:
1470 listeners = graph->listeners.sink_input_port_removed;
1471 break;
1472 default:
1473 abort();
1474 }
1bf957a0 1475
d94d92ac
PP
1476 break;
1477 }
1478 default:
1479 abort();
1480 }
262e5473 1481
d94d92ac
PP
1482 for (i = 0; i < listeners->len; i++) {
1483 struct bt_graph_listener_port_removed *listener =
1484 &g_array_index(listeners,
1485 struct bt_graph_listener_port_removed, i);
1bf957a0 1486
d94d92ac
PP
1487 BT_ASSERT(listener->func);
1488 listener->func(comp, port, listener->base.data);
1bf957a0
PP
1489 }
1490}
1491
1492BT_HIDDEN
f345f8bb
PP
1493void bt_graph_notify_ports_connected(struct bt_graph *graph,
1494 struct bt_port *upstream_port, struct bt_port *downstream_port)
1bf957a0 1495{
d94d92ac
PP
1496 uint64_t i;
1497 GArray *listeners;
1498 struct bt_component *upstream_comp;
1499 struct bt_component *downstream_comp;
1bf957a0 1500
d94d92ac
PP
1501 BT_ASSERT(graph);
1502 BT_ASSERT(upstream_port);
1503 BT_ASSERT(downstream_port);
1504 BT_LIB_LOGV("Notifying graph listeners that ports were connected: "
1505 "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
1506 graph, upstream_port, downstream_port);
1507 upstream_comp = bt_port_borrow_component(upstream_port);
1508 BT_ASSERT(upstream_comp);
1509 downstream_comp = bt_port_borrow_component(downstream_port);
1510 BT_ASSERT(downstream_comp);
1511
1512 switch (upstream_comp->class->type) {
1513 case BT_COMPONENT_CLASS_TYPE_SOURCE:
1514 {
1515 switch (downstream_comp->class->type) {
1516 case BT_COMPONENT_CLASS_TYPE_FILTER:
1517 listeners =
1518 graph->listeners.source_filter_ports_connected;
1519 break;
1520 case BT_COMPONENT_CLASS_TYPE_SINK:
1521 listeners =
1522 graph->listeners.source_sink_ports_connected;
1523 break;
1524 default:
1525 abort();
1526 }
262e5473 1527
d94d92ac
PP
1528 break;
1529 }
1530 case BT_COMPONENT_CLASS_TYPE_FILTER:
1531 {
1532 switch (downstream_comp->class->type) {
1533 case BT_COMPONENT_CLASS_TYPE_SINK:
1534 listeners =
1535 graph->listeners.filter_sink_ports_connected;
1536 break;
1537 default:
1538 abort();
1539 }
1bf957a0 1540
d94d92ac
PP
1541 break;
1542 }
1543 default:
1544 abort();
1545 }
1546
1547 for (i = 0; i < listeners->len; i++) {
1548 struct bt_graph_listener_ports_connected *listener =
1549 &g_array_index(listeners,
1550 struct bt_graph_listener_ports_connected, i);
1551
1552 BT_ASSERT(listener->func);
1553 listener->func(upstream_comp, downstream_comp,
1554 upstream_port, downstream_port, listener->base.data);
1bf957a0
PP
1555 }
1556}
1557
1558BT_HIDDEN
f345f8bb
PP
1559void bt_graph_notify_ports_disconnected(struct bt_graph *graph,
1560 struct bt_component *upstream_comp,
1561 struct bt_component *downstream_comp,
d94d92ac
PP
1562 struct bt_port *upstream_port,
1563 struct bt_port *downstream_port)
1bf957a0 1564{
d94d92ac
PP
1565 uint64_t i;
1566 GArray *listeners;
1567
1568 BT_ASSERT(graph);
1569 BT_ASSERT(upstream_comp);
1570 BT_ASSERT(downstream_comp);
1571 BT_ASSERT(upstream_port);
1572 BT_ASSERT(downstream_port);
1573 BT_LIB_LOGV("Notifying graph listeners that ports were disconnected: "
1574 "%![graph-]+g, %![up-port-]+p, %![down-port-]+p, "
1575 "%![up-comp-]+c, %![down-comp-]+c",
1576 graph, upstream_port, downstream_port, upstream_comp,
1577 downstream_comp);
1578
1579 switch (upstream_comp->class->type) {
1580 case BT_COMPONENT_CLASS_TYPE_SOURCE:
1581 {
1582 switch (downstream_comp->class->type) {
1583 case BT_COMPONENT_CLASS_TYPE_FILTER:
1584 listeners =
1585 graph->listeners.source_filter_ports_disconnected;
1586 break;
1587 case BT_COMPONENT_CLASS_TYPE_SINK:
1588 listeners =
1589 graph->listeners.source_sink_ports_disconnected;
1590 break;
1591 default:
1592 abort();
1593 }
1bf957a0 1594
d94d92ac
PP
1595 break;
1596 }
1597 case BT_COMPONENT_CLASS_TYPE_FILTER:
1598 {
1599 switch (downstream_comp->class->type) {
1600 case BT_COMPONENT_CLASS_TYPE_SINK:
1601 listeners =
1602 graph->listeners.filter_sink_ports_disconnected;
1603 break;
1604 default:
1605 abort();
1606 }
1607
1608 break;
1609 }
1610 default:
1611 abort();
1612 }
262e5473 1613
d94d92ac
PP
1614 for (i = 0; i < listeners->len; i++) {
1615 struct bt_graph_listener_ports_disconnected *listener =
1616 &g_array_index(listeners,
1617 struct bt_graph_listener_ports_disconnected, i);
1bf957a0 1618
d94d92ac
PP
1619 BT_ASSERT(listener->func);
1620 listener->func(upstream_comp, downstream_comp,
1621 upstream_port, downstream_port, listener->base.data);
1bf957a0
PP
1622 }
1623}
202a3a13 1624
a2d06fd5
PP
1625enum bt_graph_status bt_private_graph_cancel(
1626 struct bt_private_graph *priv_graph)
202a3a13 1627{
a2d06fd5 1628 struct bt_graph *graph = (void *) priv_graph;
202a3a13 1629
d94d92ac
PP
1630 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1631 graph->canceled = true;
1632 BT_LIB_LOGV("Canceled graph: %!+i", graph);
1633 return BT_GRAPH_STATUS_OK;
202a3a13
PP
1634}
1635
c7eee084 1636bt_bool bt_graph_is_canceled(struct bt_graph *graph)
202a3a13 1637{
d94d92ac
PP
1638 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1639 return graph->canceled ? BT_TRUE : BT_FALSE;
202a3a13 1640}
f167d3c0
PP
1641
1642BT_HIDDEN
1643void bt_graph_remove_connection(struct bt_graph *graph,
1644 struct bt_connection *connection)
1645{
f6ccaed9
PP
1646 BT_ASSERT(graph);
1647 BT_ASSERT(connection);
d94d92ac 1648 BT_LIB_LOGV("Removing graph's connection: %![graph-]+g, %![conn-]+x",
262e5473 1649 graph, connection);
f167d3c0
PP
1650 g_ptr_array_remove(graph->connections, connection);
1651}
36712f1d 1652
d94d92ac
PP
1653BT_ASSERT_PRE_FUNC
1654static inline
1655bool component_name_exists(struct bt_graph *graph, const char *name)
1656{
1657 bool exists = false;
1658 uint64_t i;
1659
1660 for (i = 0; i < graph->components->len; i++) {
1661 struct bt_component *other_comp = graph->components->pdata[i];
1662
1663 if (strcmp(name, bt_component_get_name(other_comp)) == 0) {
1664 BT_ASSERT_PRE_MSG("Another component with the same name already exists in the graph: "
1665 "%![other-comp-]+c, name=\"%s\"",
1666 other_comp, name);
1667 exists = true;
1668 goto end;
1669 }
1670 }
1671
1672end:
1673 return exists;
1674}
1675
1676static
1677enum bt_graph_status add_component_with_init_method_data(
a2d06fd5 1678 struct bt_private_graph *priv_graph,
d94d92ac
PP
1679 struct bt_component_class *comp_cls,
1680 comp_init_method_t init_method,
36712f1d 1681 const char *name, struct bt_value *params,
d94d92ac 1682 void *init_method_data, struct bt_component **user_component)
36712f1d 1683{
a2d06fd5 1684 struct bt_graph *graph = (void *) priv_graph;
36712f1d 1685 enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
d94d92ac 1686 enum bt_self_component_status comp_status;
36712f1d 1687 struct bt_component *component = NULL;
d94d92ac
PP
1688 int ret;
1689 bool init_can_consume;
36712f1d 1690
d94d92ac
PP
1691 BT_ASSERT(comp_cls);
1692 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1693 BT_ASSERT_PRE_NON_NULL(name, "Name");
1694 BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
1695 BT_ASSERT_PRE(!component_name_exists(graph, name),
1696 "Duplicate component name: %!+g, name=\"%s\"", graph, name);
1697 BT_ASSERT_PRE(!params || bt_value_is_map(params),
1698 "Parameter value is not a map value: %!+v", params);
65300d60 1699 bt_object_get_ref(params);
4aa7981f 1700 init_can_consume = graph->can_consume;
d94d92ac
PP
1701 bt_graph_set_can_consume(graph, false);
1702 BT_LIB_LOGD("Adding component to graph: "
1703 "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
36712f1d 1704 "init-method-data-addr=%p",
d94d92ac 1705 graph, comp_cls, name, params, init_method_data);
36712f1d 1706
d94d92ac 1707 if (!params) {
707b7d35 1708 params = bt_private_value_as_value(
da91b29a 1709 bt_private_value_map_create());
36712f1d
PP
1710 if (!params) {
1711 BT_LOGE_STR("Cannot create map value object.");
1712 graph_status = BT_GRAPH_STATUS_NOMEM;
1713 goto end;
1714 }
1715 }
1716
d94d92ac
PP
1717 ret = bt_component_create(comp_cls, name, &component);
1718 if (ret) {
1719 BT_LOGE("Cannot create empty component object: ret=%d",
1720 ret);
1721 graph_status = BT_GRAPH_STATUS_NOMEM;
36712f1d
PP
1722 goto end;
1723 }
1724
1725 /*
1726 * The user's initialization method needs to see that this
1727 * component is part of the graph. If the user method fails, we
1728 * immediately remove the component from the graph's components.
1729 */
1730 g_ptr_array_add(graph->components, component);
1731 bt_component_set_graph(component, graph);
1732
d94d92ac 1733 if (init_method) {
36712f1d 1734 BT_LOGD_STR("Calling user's initialization method.");
d94d92ac 1735 comp_status = init_method(component, params, init_method_data);
36712f1d 1736 BT_LOGD("User method returned: status=%s",
d94d92ac
PP
1737 bt_self_component_status_string(comp_status));
1738 if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
36712f1d 1739 BT_LOGW_STR("Initialization method failed.");
d94d92ac 1740 graph_status = (int) comp_status;
36712f1d
PP
1741 bt_component_set_graph(component, NULL);
1742 g_ptr_array_remove_fast(graph->components, component);
1743 goto end;
1744 }
1745 }
1746
1747 /*
1748 * Mark the component as initialized so that its finalization
1749 * method is called when it is destroyed.
1750 */
1751 component->initialized = true;
1752
1753 /*
1754 * If it's a sink component, it needs to be part of the graph's
1755 * sink queue to be consumed by bt_graph_consume().
1756 */
1757 if (bt_component_is_sink(component)) {
d94d92ac 1758 graph->has_sink = true;
36712f1d
PP
1759 g_queue_push_tail(graph->sinks_to_consume, component);
1760 }
1761
1762 /*
1763 * Freeze the component class now that it's instantiated at
1764 * least once.
1765 */
1766 BT_LOGD_STR("Freezing component class.");
d94d92ac
PP
1767 bt_component_class_freeze(comp_cls);
1768 BT_LIB_LOGD("Added component to graph: "
1769 "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
1770 "init-method-data-addr=%p, %![comp-]+c",
1771 graph, comp_cls, name, params, init_method_data, component);
36712f1d
PP
1772
1773 if (user_component) {
1774 /* Move reference to user */
1775 *user_component = component;
1776 component = NULL;
1777 }
1778
1779end:
65300d60
PP
1780 bt_object_put_ref(component);
1781 bt_object_put_ref(params);
d94d92ac
PP
1782 (void) init_can_consume;
1783 bt_graph_set_can_consume(graph, init_can_consume);
36712f1d
PP
1784 return graph_status;
1785}
1786
d94d92ac
PP
1787enum bt_graph_status
1788bt_private_graph_add_source_component_with_init_method_data(
1789 struct bt_private_graph *graph,
1790 struct bt_component_class_source *comp_cls,
1791 const char *name, struct bt_value *params,
1792 void *init_method_data, struct bt_component_source **component)
1793{
1794 BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
1795 return add_component_with_init_method_data(graph,
1796 (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
1797 name, params, init_method_data, (void *) component);
1798}
1799
1800enum bt_graph_status bt_private_graph_add_source_component(
1801 struct bt_private_graph *graph,
1802 struct bt_component_class_source *comp_cls,
1803 const char *name, struct bt_value *params,
1804 struct bt_component_source **component)
1805{
1806 return bt_private_graph_add_source_component_with_init_method_data(
1807 graph, comp_cls, name, params, NULL, component);
1808}
1809
1810enum bt_graph_status
1811bt_private_graph_add_filter_component_with_init_method_data(
1812 struct bt_private_graph *graph,
1813 struct bt_component_class_filter *comp_cls,
1814 const char *name, struct bt_value *params,
1815 void *init_method_data, struct bt_component_filter **component)
1816{
1817 BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
1818 return add_component_with_init_method_data(graph,
1819 (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
1820 name, params, init_method_data, (void *) component);
1821}
1822
1823enum bt_graph_status bt_private_graph_add_filter_component(
1824 struct bt_private_graph *graph,
1825 struct bt_component_class_filter *comp_cls,
1826 const char *name, struct bt_value *params,
1827 struct bt_component_filter **component)
1828{
1829 return bt_private_graph_add_filter_component_with_init_method_data(
1830 graph, comp_cls, name, params, NULL, component);
1831}
1832
1833enum bt_graph_status
1834bt_private_graph_add_sink_component_with_init_method_data(
a2d06fd5 1835 struct bt_private_graph *graph,
d94d92ac 1836 struct bt_component_class_sink *comp_cls,
36712f1d 1837 const char *name, struct bt_value *params,
d94d92ac 1838 void *init_method_data, struct bt_component_sink **component)
36712f1d 1839{
d94d92ac
PP
1840 BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
1841 return add_component_with_init_method_data(graph,
1842 (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
1843 name, params, init_method_data, (void *) component);
1844}
1845
1846enum bt_graph_status bt_private_graph_add_sink_component(
1847 struct bt_private_graph *graph,
1848 struct bt_component_class_sink *comp_cls,
1849 const char *name, struct bt_value *params,
1850 struct bt_component_sink **component)
1851{
1852 return bt_private_graph_add_sink_component_with_init_method_data(
1853 graph, comp_cls, name, params, NULL, component);
36712f1d 1854}
8ed535b5
PP
1855
1856BT_HIDDEN
1857int bt_graph_remove_unconnected_component(struct bt_graph *graph,
1858 struct bt_component *component)
1859{
d94d92ac
PP
1860 bool init_can_consume;
1861 uint64_t count;
8ed535b5
PP
1862 uint64_t i;
1863 int ret = 0;
1864
f6ccaed9
PP
1865 BT_ASSERT(graph);
1866 BT_ASSERT(component);
3fea54f6 1867 BT_ASSERT(component->base.ref_count == 0);
f6ccaed9 1868 BT_ASSERT(bt_component_borrow_graph(component) == graph);
8ed535b5 1869
4aa7981f 1870 init_can_consume = graph->can_consume;
8ed535b5
PP
1871 count = bt_component_get_input_port_count(component);
1872
1873 for (i = 0; i < count; i++) {
d94d92ac
PP
1874 struct bt_port *port = (void *)
1875 bt_component_borrow_input_port_by_index(component, i);
8ed535b5 1876
f6ccaed9 1877 BT_ASSERT(port);
8ed535b5
PP
1878
1879 if (bt_port_is_connected(port)) {
d94d92ac 1880 BT_LIB_LOGW("Cannot remove component from graph: "
8ed535b5 1881 "an input port is connected: "
d94d92ac
PP
1882 "%![graph-]+g, %![comp-]+c, %![port-]+p",
1883 graph, component, port);
8ed535b5
PP
1884 goto error;
1885 }
1886 }
1887
1888 count = bt_component_get_output_port_count(component);
1889
1890 for (i = 0; i < count; i++) {
d94d92ac
PP
1891 struct bt_port *port = (void *)
1892 bt_component_borrow_output_port_by_index(component, i);
8ed535b5 1893
f6ccaed9 1894 BT_ASSERT(port);
8ed535b5
PP
1895
1896 if (bt_port_is_connected(port)) {
d94d92ac 1897 BT_LIB_LOGW("Cannot remove component from graph: "
8ed535b5 1898 "an output port is connected: "
d94d92ac
PP
1899 "%![graph-]+g, %![comp-]+c, %![port-]+p",
1900 graph, component, port);
8ed535b5
PP
1901 goto error;
1902 }
1903 }
1904
d94d92ac 1905 bt_graph_set_can_consume(graph, false);
8ed535b5
PP
1906
1907 /* Possibly remove from sinks to consume */
1908 (void) g_queue_remove(graph->sinks_to_consume, component);
1909
1910 if (graph->sinks_to_consume->length == 0) {
d94d92ac 1911 graph->has_sink = false;
8ed535b5
PP
1912 }
1913
1914 /*
3fea54f6
PP
1915 * This calls bt_object_try_spec_release() on the component, and
1916 * since its reference count is 0, its destructor is called. Its
8ed535b5
PP
1917 * destructor calls the user's finalization method (if set).
1918 */
1919 g_ptr_array_remove(graph->components, component);
1920 goto end;
1921
1922error:
1923 ret = -1;
1924
1925end:
d94d92ac
PP
1926 (void) init_can_consume;
1927 bt_graph_set_can_consume(graph, init_can_consume);
8ed535b5
PP
1928 return ret;
1929}
5c563278
PP
1930
1931BT_HIDDEN
1932void bt_graph_add_notification(struct bt_graph *graph,
1933 struct bt_notification *notif)
1934{
1935 BT_ASSERT(graph);
1936 BT_ASSERT(notif);
1937
1938 /*
1939 * It's okay not to take a reference because, when a
1940 * notification's reference count drops to 0, either:
1941 *
1942 * * It is recycled back to one of this graph's pool.
1943 * * It is destroyed because it doesn't have any link to any
1944 * graph, which means the original graph is already destroyed.
1945 */
1946 g_ptr_array_add(graph->notifications, notif);
1947}
This page took 0.125716 seconds and 4 git commands to generate.