f28954188a3659764e3c04a6cc0c626ff57944e9
[babeltrace.git] / lib / graph / graph.c
1 /*
2 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
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
24 #define BT_LOG_TAG "GRAPH"
25 #include <babeltrace/lib-logging-internal.h>
26
27 #include <babeltrace/assert-internal.h>
28 #include <babeltrace/assert-pre-internal.h>
29 #include <babeltrace/graph/component-internal.h>
30 #include <babeltrace/graph/graph.h>
31 #include <babeltrace/graph/graph-const.h>
32 #include <babeltrace/graph/graph-internal.h>
33 #include <babeltrace/graph/connection-internal.h>
34 #include <babeltrace/graph/component-sink-internal.h>
35 #include <babeltrace/graph/component-source-const.h>
36 #include <babeltrace/graph/component-filter-const.h>
37 #include <babeltrace/graph/port-const.h>
38 #include <babeltrace/graph/message-internal.h>
39 #include <babeltrace/graph/message-event-internal.h>
40 #include <babeltrace/graph/message-packet-internal.h>
41 #include <babeltrace/compiler-internal.h>
42 #include <babeltrace/common-internal.h>
43 #include <babeltrace/types.h>
44 #include <babeltrace/value.h>
45 #include <babeltrace/value-const.h>
46 #include <babeltrace/value-internal.h>
47 #include <unistd.h>
48 #include <glib.h>
49
50 typedef void (*port_added_func_t)(const void *, const void *, void *);
51
52 typedef void (*port_removed_func_t)(const void *, const void *, void *);
53
54 typedef void (*ports_connected_func_t)(const void *, const void *, const void *,
55 const void *, void *);
56
57 typedef void (*ports_disconnected_func_t)(const void *, const void *,
58 const void *, const void *, void *);
59
60 typedef enum bt_self_component_status (*comp_init_method_t)(const void *,
61 const void *, void *);
62
63 struct bt_graph_listener {
64 bt_graph_listener_removed_func removed;
65 void *data;
66 };
67
68 struct bt_graph_listener_port_added {
69 struct bt_graph_listener base;
70 port_added_func_t func;
71 };
72
73 struct bt_graph_listener_port_removed {
74 struct bt_graph_listener base;
75 port_removed_func_t func;
76 };
77
78 struct bt_graph_listener_ports_connected {
79 struct bt_graph_listener base;
80 ports_connected_func_t func;
81 };
82
83 struct bt_graph_listener_ports_disconnected {
84 struct bt_graph_listener base;
85 ports_disconnected_func_t func;
86 };
87
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)
109
110 static
111 void destroy_graph(struct bt_object *obj)
112 {
113 struct bt_graph *graph = container_of(obj, struct bt_graph, base);
114
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.
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).
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.
129 * 5. The message iterator's finalization function puts its
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.
134 * 7. Since this graph's reference count goes from 1 to 0, its
135 * destructor is called (this function).
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 */
141 BT_LIB_LOGD("Destroying graph: %!+g", graph);
142 obj->ref_count++;
143
144 /*
145 * Cancel the graph to disallow some operations, like creating
146 * message iterators and adding ports to components.
147 */
148 (void) bt_graph_cancel((void *) graph);
149
150 /* Call all remove listeners */
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);
169 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
170 graph->listeners.filter_filter_ports_connected);
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);
177 CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_disconnected,
178 graph->listeners.filter_filter_ports_disconnected);
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);
183
184 if (graph->messages) {
185 g_ptr_array_free(graph->messages, TRUE);
186 graph->messages = NULL;
187 }
188
189 if (graph->connections) {
190 BT_LOGD_STR("Destroying connections.");
191 g_ptr_array_free(graph->connections, TRUE);
192 graph->connections = NULL;
193 }
194
195 if (graph->components) {
196 BT_LOGD_STR("Destroying components.");
197 g_ptr_array_free(graph->components, TRUE);
198 graph->components = NULL;
199 }
200
201 if (graph->sinks_to_consume) {
202 g_queue_free(graph->sinks_to_consume);
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;
219 }
220
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;
224 }
225
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;
229 }
230
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;
234 }
235
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
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
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
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
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;
292 }
293
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);
297 g_free(graph);
298 }
299
300 static
301 void destroy_message_event(struct bt_message *msg,
302 struct bt_graph *graph)
303 {
304 bt_message_event_destroy(msg);
305 }
306
307 static
308 void destroy_message_packet_begin(struct bt_message *msg,
309 struct bt_graph *graph)
310 {
311 bt_message_packet_beginning_destroy(msg);
312 }
313
314 static
315 void destroy_message_packet_end(struct bt_message *msg,
316 struct bt_graph *graph)
317 {
318 bt_message_packet_end_destroy(msg);
319 }
320
321 static
322 void notify_message_graph_is_destroyed(struct bt_message *msg)
323 {
324 bt_message_unlink_graph(msg);
325 }
326
327 struct bt_graph *bt_graph_create(void)
328 {
329 struct bt_graph *graph;
330 int ret;
331
332 BT_LOGD_STR("Creating graph object.");
333 graph = g_new0(struct bt_graph, 1);
334 if (!graph) {
335 BT_LOGE_STR("Failed to allocate one graph.");
336 goto end;
337 }
338
339 bt_object_init_shared(&graph->base, destroy_graph);
340 graph->connections = g_ptr_array_new_with_free_func(
341 (GDestroyNotify) bt_object_try_spec_release);
342 if (!graph->connections) {
343 BT_LOGE_STR("Failed to allocate one GPtrArray.");
344 goto error;
345 }
346 graph->components = g_ptr_array_new_with_free_func(
347 (GDestroyNotify) bt_object_try_spec_release);
348 if (!graph->components) {
349 BT_LOGE_STR("Failed to allocate one GPtrArray.");
350 goto error;
351 }
352 graph->sinks_to_consume = g_queue_new();
353 if (!graph->sinks_to_consume) {
354 BT_LOGE_STR("Failed to allocate one GQueue.");
355 goto error;
356 }
357
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;
364 goto error;
365 }
366
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;
372 goto error;
373 }
374
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;
380 goto error;
381 }
382
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
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
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
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
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;
484 goto error;
485 }
486
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,
490 graph);
491 if (ret) {
492 BT_LOGE("Failed to initialize event message pool: ret=%d",
493 ret);
494 goto error;
495 }
496
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,
500 graph);
501 if (ret) {
502 BT_LOGE("Failed to initialize packet beginning message pool: ret=%d",
503 ret);
504 goto error;
505 }
506
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,
510 graph);
511 if (ret) {
512 BT_LOGE("Failed to initialize packet end message pool: ret=%d",
513 ret);
514 goto error;
515 }
516
517 graph->messages = g_ptr_array_new_with_free_func(
518 (GDestroyNotify) notify_message_graph_is_destroyed);
519 BT_LIB_LOGD("Created graph object: %!+g", graph);
520
521 end:
522 return (void *) graph;
523
524 error:
525 BT_OBJECT_PUT_REF_AND_RESET(graph);
526 goto end;
527 }
528
529 enum 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)
534 {
535 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
536 struct bt_connection *connection = NULL;
537 struct bt_port *upstream_port = (void *) upstream_port_out;
538 struct bt_port *downstream_port = (void *) downstream_port_in;
539 struct bt_component *upstream_component = NULL;
540 struct bt_component *downstream_component = NULL;
541 enum bt_self_component_status component_status;
542 bool init_can_consume;
543
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);
552 BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) upstream_port),
553 "Upstream port does not belong to a component: %!+p",
554 upstream_port);
555 BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) downstream_port),
556 "Downstream port does not belong to a component: %!+p",
557 downstream_port);
558 init_can_consume = graph->can_consume;
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);
563 upstream_component = bt_port_borrow_component_inline(
564 (void *) upstream_port);
565 downstream_component = bt_port_borrow_component_inline(
566 (void *) downstream_port);
567
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 */
573 BT_LIB_LOGD("Asking upstream component to accept the connection: "
574 "%![comp-]+c", upstream_component);
575 component_status = bt_component_accept_port_connection(
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) {
580 BT_LOGD_STR("Upstream component refused the connection.");
581 } else {
582 BT_LOGW("Cannot ask upstream component to accept the connection: "
583 "status=%s", bt_self_component_status_string(component_status));
584 }
585
586 status = (int) component_status;
587 goto end;
588 }
589
590 BT_LIB_LOGD("Asking downstream component to accept the connection: "
591 "%![comp-]+c", downstream_component);
592 component_status = bt_component_accept_port_connection(
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) {
597 BT_LOGD_STR("Downstream component refused the connection.");
598 } else {
599 BT_LOGW("Cannot ask downstream component to accept the connection: "
600 "status=%s", bt_self_component_status_string(component_status));
601 }
602
603 status = (int) component_status;
604 goto end;
605 }
606
607 BT_LOGD_STR("Creating connection.");
608 connection = bt_connection_create(graph, (void *) upstream_port,
609 (void *) downstream_port);
610 if (!connection) {
611 BT_LOGW("Cannot create connection object.");
612 status = BT_GRAPH_STATUS_NOMEM;
613 goto end;
614 }
615
616 BT_LIB_LOGD("Connection object created: %!+x", connection);
617
618 /*
619 * Ownership of upstream_component/downstream_component and of
620 * the connection object is transferred to the graph.
621 */
622 g_ptr_array_add(graph->connections, connection);
623
624 /*
625 * Notify both components that their port is connected.
626 */
627 BT_LIB_LOGD("Notifying upstream component that its port is connected: "
628 "%![comp-]+c, %![port-]+p", upstream_component, upstream_port);
629 component_status = bt_component_port_connected(upstream_component,
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);
638 bt_connection_end(connection, true);
639 status = (int) component_status;
640 goto end;
641 }
642
643 connection->notified_upstream_port_connected = true;
644 BT_LIB_LOGD("Notifying downstream component that its port is connected: "
645 "%![comp-]+c, %![port-]+p", downstream_component,
646 downstream_port);
647 component_status = bt_component_port_connected(downstream_component,
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);
656 bt_connection_end(connection, true);
657 status = (int) component_status;
658 goto end;
659 }
660
661 connection->notified_downstream_port_connected = true;
662
663 /*
664 * Notify the graph's creator that both ports are connected.
665 */
666 BT_LOGD_STR("Notifying graph's user that new component ports are connected.");
667 bt_graph_notify_ports_connected(graph, upstream_port, downstream_port);
668 connection->notified_graph_ports_connected = true;
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);
674
675 if (user_connection) {
676 /* Move reference to user */
677 *user_connection = connection;
678 connection = NULL;
679 }
680
681 end:
682 bt_object_put_ref(connection);
683 (void) init_can_consume;
684 bt_graph_set_can_consume(graph, init_can_consume);
685 return status;
686 }
687
688 static inline
689 enum bt_graph_status consume_graph_sink(struct bt_component_sink *comp)
690 {
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
716 end:
717 return (int) comp_status;
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 */
725 static inline
726 enum bt_graph_status consume_sink_node(struct bt_graph *graph, GList *node)
727 {
728 enum bt_graph_status status;
729 struct bt_component_sink *sink;
730
731 sink = node->data;
732 status = consume_graph_sink(sink);
733 if (unlikely(status != BT_GRAPH_STATUS_END)) {
734 g_queue_push_tail_link(graph->sinks_to_consume, node);
735 goto end;
736 }
737
738 /* End reached, the node is not added back to the queue and free'd. */
739 g_queue_delete_link(graph->sinks_to_consume, node);
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 }
746
747 end:
748 BT_LIB_LOGV("Consumed sink node: %![comp-]+c, status=%s",
749 sink, bt_graph_status_string(status));
750 return status;
751 }
752
753 BT_HIDDEN
754 enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
755 struct bt_component_sink *sink)
756 {
757 enum bt_graph_status status;
758 GList *sink_node;
759 int index;
760
761 BT_LIB_LOGV("Making specific sink consume: %![comp-]+c", sink);
762 BT_ASSERT(bt_component_borrow_graph((void *) sink) == graph);
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);
778 BT_ASSERT(sink_node);
779 status = consume_sink_node(graph, sink_node);
780
781 end:
782 return status;
783 }
784
785 static inline
786 enum bt_graph_status consume_no_check(struct bt_graph *graph)
787 {
788 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
789 struct bt_component *sink;
790 GList *current_node;
791
792 BT_ASSERT_PRE(graph->has_sink,
793 "Graph has no sink component: %!+g", graph);
794 BT_LIB_LOGV("Making next sink consume: %![graph-]+g", graph);
795
796 if (unlikely(g_queue_is_empty(graph->sinks_to_consume))) {
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;
804 BT_LIB_LOGV("Chose next sink to consume: %!+c", sink);
805 status = consume_sink_node(graph, current_node);
806
807 end:
808 return status;
809 }
810
811 enum bt_graph_status bt_graph_consume(
812 struct bt_graph *graph)
813 {
814 enum bt_graph_status status;
815
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);
820 bt_graph_set_can_consume(graph, BT_FALSE);
821 status = consume_no_check(graph);
822 bt_graph_set_can_consume(graph, BT_TRUE);
823 return status;
824 }
825
826 enum bt_graph_status bt_graph_run(struct bt_graph *graph)
827 {
828 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
829
830 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
831 BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
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);
835 BT_LIB_LOGV("Running graph: %!+g", graph);
836
837 do {
838 /*
839 * Check if the graph is canceled at each iteration. If
840 * the graph was canceled by another thread or by a
841 * signal handler, this is not a warning nor an error,
842 * it was intentional: log with a DEBUG level only.
843 */
844 if (unlikely(graph->canceled)) {
845 BT_LIB_LOGD("Stopping the graph: graph is canceled: "
846 "%!+g", graph);
847 status = BT_GRAPH_STATUS_CANCELED;
848 goto end;
849 }
850
851 status = consume_no_check(graph);
852 if (unlikely(status == BT_GRAPH_STATUS_AGAIN)) {
853 /*
854 * If AGAIN is received and there are multiple
855 * sinks, go ahead and consume from the next
856 * sink.
857 *
858 * However, in the case where a single sink is
859 * left, the caller can decide to busy-wait and
860 * call bt_graph_run() continuously
861 * until the source is ready or it can decide to
862 * sleep for an arbitrary amount of time.
863 */
864 if (graph->sinks_to_consume->length > 1) {
865 status = BT_GRAPH_STATUS_OK;
866 }
867 } else if (status == BT_GRAPH_STATUS_NO_SINK) {
868 goto end;
869 }
870 } while (status == BT_GRAPH_STATUS_OK);
871
872 if (g_queue_is_empty(graph->sinks_to_consume)) {
873 status = BT_GRAPH_STATUS_END;
874 }
875
876 end:
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);
880 return status;
881 }
882
883 enum bt_graph_status
884 bt_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,
888 int *out_listener_id)
889 {
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,
896 };
897 int listener_id;
898
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;
916 }
917
918 enum bt_graph_status
919 bt_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,
923 int *out_listener_id)
924 {
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;
933
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 }
952
953 enum bt_graph_status
954 bt_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,
958 int *out_listener_id)
959 {
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;
968
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 }
987
988 enum bt_graph_status
989 bt_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,
993 int *out_listener_id)
994 {
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;
1003
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;
1021 }
1022
1023 enum bt_graph_status
1024 bt_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,
1028 int *out_listener_id)
1029 {
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;
1038
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 }
1057
1058 enum bt_graph_status
1059 bt_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,
1063 int *out_listener_id)
1064 {
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;
1073
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 }
1092
1093 enum bt_graph_status
1094 bt_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,
1098 int *out_listener_id)
1099 {
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;
1108
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;
1126 }
1127
1128 enum bt_graph_status
1129 bt_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,
1133 int *out_listener_id)
1134 {
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;
1143
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 }
1162
1163 enum bt_graph_status
1164 bt_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,
1168 int *out_listener_id)
1169 {
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;
1178
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 }
1198
1199 enum bt_graph_status
1200 bt_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,
1204 int *out_listener_id)
1205 {
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;
1214
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;
1233 }
1234
1235 enum bt_graph_status
1236 bt_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
1271 enum bt_graph_status
1272 bt_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,
1276 int *out_listener_id)
1277 {
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;
1286
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 }
1306
1307 enum bt_graph_status
1308 bt_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,
1312 int *out_listener_id)
1313 {
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;
1322
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 }
1342
1343 enum bt_graph_status
1344 bt_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,
1348 int *out_listener_id)
1349 {
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;
1358
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
1379 enum bt_graph_status
1380 bt_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
1415 enum bt_graph_status
1416 bt_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,
1420 int *out_listener_id)
1421 {
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;
1449 }
1450
1451 BT_HIDDEN
1452 void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port)
1453 {
1454 uint64_t i;
1455 GArray *listeners;
1456 struct bt_component *comp;
1457
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);
1462 comp = bt_port_borrow_component_inline(port);
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 }
1490
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 }
1502
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);
1516 }
1517 }
1518
1519 BT_HIDDEN
1520 void bt_graph_notify_port_removed(struct bt_graph *graph,
1521 struct bt_component *comp, struct bt_port *port)
1522 {
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 }
1568
1569 break;
1570 }
1571 default:
1572 abort();
1573 }
1574
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);
1579
1580 BT_ASSERT(listener->func);
1581 listener->func(comp, port, listener->base.data);
1582 }
1583 }
1584
1585 BT_HIDDEN
1586 void bt_graph_notify_ports_connected(struct bt_graph *graph,
1587 struct bt_port *upstream_port, struct bt_port *downstream_port)
1588 {
1589 uint64_t i;
1590 GArray *listeners;
1591 struct bt_component *upstream_comp;
1592 struct bt_component *downstream_comp;
1593
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);
1600 upstream_comp = bt_port_borrow_component_inline(upstream_port);
1601 BT_ASSERT(upstream_comp);
1602 downstream_comp = bt_port_borrow_component_inline(downstream_port);
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 }
1620
1621 break;
1622 }
1623 case BT_COMPONENT_CLASS_TYPE_FILTER:
1624 {
1625 switch (downstream_comp->class->type) {
1626 case BT_COMPONENT_CLASS_TYPE_FILTER:
1627 listeners =
1628 graph->listeners.filter_filter_ports_connected;
1629 break;
1630 case BT_COMPONENT_CLASS_TYPE_SINK:
1631 listeners =
1632 graph->listeners.filter_sink_ports_connected;
1633 break;
1634 default:
1635 abort();
1636 }
1637
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);
1652 }
1653 }
1654
1655 BT_HIDDEN
1656 void bt_graph_notify_ports_disconnected(struct bt_graph *graph,
1657 struct bt_component *upstream_comp,
1658 struct bt_component *downstream_comp,
1659 struct bt_port *upstream_port,
1660 struct bt_port *downstream_port)
1661 {
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 }
1691
1692 break;
1693 }
1694 case BT_COMPONENT_CLASS_TYPE_FILTER:
1695 {
1696 switch (downstream_comp->class->type) {
1697 case BT_COMPONENT_CLASS_TYPE_FILTER:
1698 listeners =
1699 graph->listeners.filter_filter_ports_disconnected;
1700 break;
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 }
1714
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);
1719
1720 BT_ASSERT(listener->func);
1721 listener->func(upstream_comp, downstream_comp,
1722 upstream_port, downstream_port, listener->base.data);
1723 }
1724 }
1725
1726 enum bt_graph_status bt_graph_cancel(
1727 struct bt_graph *graph)
1728 {
1729
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;
1734 }
1735
1736 bt_bool bt_graph_is_canceled(const struct bt_graph *graph)
1737 {
1738 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
1739 return graph->canceled ? BT_TRUE : BT_FALSE;
1740 }
1741
1742 BT_HIDDEN
1743 void bt_graph_remove_connection(struct bt_graph *graph,
1744 struct bt_connection *connection)
1745 {
1746 BT_ASSERT(graph);
1747 BT_ASSERT(connection);
1748 BT_LIB_LOGV("Removing graph's connection: %![graph-]+g, %![conn-]+x",
1749 graph, connection);
1750 g_ptr_array_remove(graph->connections, connection);
1751 }
1752
1753 BT_ASSERT_PRE_FUNC
1754 static inline
1755 bool 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
1772 end:
1773 return exists;
1774 }
1775
1776 static
1777 enum bt_graph_status add_component_with_init_method_data(
1778 struct bt_graph *graph,
1779 struct bt_component_class *comp_cls,
1780 comp_init_method_t init_method,
1781 const char *name, const struct bt_value *params,
1782 void *init_method_data, struct bt_component **user_component)
1783 {
1784 enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
1785 enum bt_self_component_status comp_status;
1786 struct bt_component *component = NULL;
1787 int ret;
1788 bool init_can_consume;
1789 struct bt_value *new_params = NULL;
1790
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);
1799 init_can_consume = graph->can_consume;
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, "
1803 "init-method-data-addr=%p",
1804 graph, comp_cls, name, params, init_method_data);
1805
1806 if (!params) {
1807 new_params = bt_value_map_create();
1808 if (!new_params) {
1809 BT_LOGE_STR("Cannot create map value object.");
1810 graph_status = BT_GRAPH_STATUS_NOMEM;
1811 goto end;
1812 }
1813
1814 params = new_params;
1815 }
1816
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;
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
1833 if (init_method) {
1834 BT_LOGD_STR("Calling user's initialization method.");
1835 comp_status = init_method(component, params, init_method_data);
1836 BT_LOGD("User method returned: status=%s",
1837 bt_self_component_status_string(comp_status));
1838 if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
1839 BT_LOGW_STR("Initialization method failed.");
1840 graph_status = (int) comp_status;
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)) {
1858 graph->has_sink = true;
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.");
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);
1872
1873 if (user_component) {
1874 /* Move reference to user */
1875 *user_component = component;
1876 component = NULL;
1877 }
1878
1879 end:
1880 bt_object_put_ref(component);
1881 bt_object_put_ref(new_params);
1882 (void) init_can_consume;
1883 bt_graph_set_can_consume(graph, init_can_consume);
1884 return graph_status;
1885 }
1886
1887 enum bt_graph_status
1888 bt_graph_add_source_component_with_init_method_data(
1889 struct bt_graph *graph,
1890 const struct bt_component_class_source *comp_cls,
1891 const char *name, const struct bt_value *params,
1892 void *init_method_data,
1893 const struct bt_component_source **component)
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
1901 enum bt_graph_status bt_graph_add_source_component(
1902 struct bt_graph *graph,
1903 const struct bt_component_class_source *comp_cls,
1904 const char *name, const struct bt_value *params,
1905 const struct bt_component_source **component)
1906 {
1907 return bt_graph_add_source_component_with_init_method_data(
1908 graph, comp_cls, name, params, NULL, component);
1909 }
1910
1911 enum bt_graph_status
1912 bt_graph_add_filter_component_with_init_method_data(
1913 struct bt_graph *graph,
1914 const struct bt_component_class_filter *comp_cls,
1915 const char *name, const struct bt_value *params,
1916 void *init_method_data,
1917 const struct bt_component_filter **component)
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
1925 enum bt_graph_status bt_graph_add_filter_component(
1926 struct bt_graph *graph,
1927 const struct bt_component_class_filter *comp_cls,
1928 const char *name, const struct bt_value *params,
1929 const struct bt_component_filter **component)
1930 {
1931 return bt_graph_add_filter_component_with_init_method_data(
1932 graph, comp_cls, name, params, NULL, component);
1933 }
1934
1935 enum bt_graph_status
1936 bt_graph_add_sink_component_with_init_method_data(
1937 struct bt_graph *graph,
1938 const struct bt_component_class_sink *comp_cls,
1939 const char *name, const struct bt_value *params,
1940 void *init_method_data,
1941 const struct bt_component_sink **component)
1942 {
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
1949 enum bt_graph_status bt_graph_add_sink_component(
1950 struct bt_graph *graph,
1951 const struct bt_component_class_sink *comp_cls,
1952 const char *name, const struct bt_value *params,
1953 const struct bt_component_sink **component)
1954 {
1955 return bt_graph_add_sink_component_with_init_method_data(
1956 graph, comp_cls, name, params, NULL, component);
1957 }
1958
1959 BT_HIDDEN
1960 int bt_graph_remove_unconnected_component(struct bt_graph *graph,
1961 struct bt_component *component)
1962 {
1963 bool init_can_consume;
1964 uint64_t count;
1965 uint64_t i;
1966 int ret = 0;
1967
1968 BT_ASSERT(graph);
1969 BT_ASSERT(component);
1970 BT_ASSERT(component->base.ref_count == 0);
1971 BT_ASSERT(bt_component_borrow_graph(component) == graph);
1972
1973 init_can_consume = graph->can_consume;
1974 count = bt_component_get_input_port_count(component);
1975
1976 for (i = 0; i < count; i++) {
1977 struct bt_port *port = (void *)
1978 bt_component_borrow_input_port_by_index(component, i);
1979
1980 BT_ASSERT(port);
1981
1982 if (bt_port_is_connected(port)) {
1983 BT_LIB_LOGW("Cannot remove component from graph: "
1984 "an input port is connected: "
1985 "%![graph-]+g, %![comp-]+c, %![port-]+p",
1986 graph, component, port);
1987 goto error;
1988 }
1989 }
1990
1991 count = bt_component_get_output_port_count(component);
1992
1993 for (i = 0; i < count; i++) {
1994 struct bt_port *port = (void *)
1995 bt_component_borrow_output_port_by_index(component, i);
1996
1997 BT_ASSERT(port);
1998
1999 if (bt_port_is_connected(port)) {
2000 BT_LIB_LOGW("Cannot remove component from graph: "
2001 "an output port is connected: "
2002 "%![graph-]+g, %![comp-]+c, %![port-]+p",
2003 graph, component, port);
2004 goto error;
2005 }
2006 }
2007
2008 bt_graph_set_can_consume(graph, false);
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) {
2014 graph->has_sink = false;
2015 }
2016
2017 /*
2018 * This calls bt_object_try_spec_release() on the component, and
2019 * since its reference count is 0, its destructor is called. Its
2020 * destructor calls the user's finalization method (if set).
2021 */
2022 g_ptr_array_remove(graph->components, component);
2023 goto end;
2024
2025 error:
2026 ret = -1;
2027
2028 end:
2029 (void) init_can_consume;
2030 bt_graph_set_can_consume(graph, init_can_consume);
2031 return ret;
2032 }
2033
2034 BT_HIDDEN
2035 void bt_graph_add_message(struct bt_graph *graph,
2036 struct bt_message *msg)
2037 {
2038 BT_ASSERT(graph);
2039 BT_ASSERT(msg);
2040
2041 /*
2042 * It's okay not to take a reference because, when a
2043 * message's reference count drops to 0, either:
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 */
2049 g_ptr_array_add(graph->messages, msg);
2050 }
2051
2052 void bt_graph_get_ref(const struct bt_graph *graph)
2053 {
2054 bt_object_get_ref(graph);
2055 }
2056
2057 void bt_graph_put_ref(const struct bt_graph *graph)
2058 {
2059 bt_object_put_ref(graph);
2060 }
This page took 0.112617 seconds and 3 git commands to generate.