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