Add bt_version_get_*() functions to dynamically get the lib's version
[babeltrace.git] / lib / component / graph.c
CommitLineData
c0418dd9 1/*
7d55361f 2 * graph.c
c0418dd9
JG
3 *
4 * Babeltrace Plugin Component Graph
5 *
f60c8b34 6 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
c0418dd9
JG
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
b2e0c907
PP
29#include <babeltrace/graph/component-internal.h>
30#include <babeltrace/graph/graph-internal.h>
31#include <babeltrace/graph/connection-internal.h>
32#include <babeltrace/graph/component-sink-internal.h>
33#include <babeltrace/graph/component-source.h>
34#include <babeltrace/graph/component-filter.h>
35#include <babeltrace/graph/port.h>
c0418dd9 36#include <babeltrace/compiler.h>
f60c8b34 37#include <unistd.h>
1bf957a0
PP
38#include <glib.h>
39
40struct bt_graph_listener {
41 void *func;
42 void *data;
43};
c0418dd9 44
f60c8b34
JG
45static
46void bt_graph_destroy(struct bt_object *obj)
c0418dd9 47{
f60c8b34
JG
48 struct bt_graph *graph = container_of(obj,
49 struct bt_graph, base);
c0418dd9 50
f60c8b34
JG
51 if (graph->components) {
52 g_ptr_array_free(graph->components, TRUE);
53 }
c0418dd9
JG
54 if (graph->connections) {
55 g_ptr_array_free(graph->connections, TRUE);
56 }
f60c8b34
JG
57 if (graph->sinks_to_consume) {
58 g_queue_free(graph->sinks_to_consume);
c0418dd9 59 }
1bf957a0
PP
60
61 if (graph->listeners.port_added) {
62 g_array_free(graph->listeners.port_added, TRUE);
63 }
64
65 if (graph->listeners.port_removed) {
66 g_array_free(graph->listeners.port_removed, TRUE);
67 }
68
f345f8bb
PP
69 if (graph->listeners.ports_connected) {
70 g_array_free(graph->listeners.ports_connected, TRUE);
1bf957a0
PP
71 }
72
f345f8bb
PP
73 if (graph->listeners.ports_disconnected) {
74 g_array_free(graph->listeners.ports_disconnected, TRUE);
1bf957a0
PP
75 }
76
c0418dd9
JG
77 g_free(graph);
78}
79
1bf957a0
PP
80static
81int init_listeners_array(GArray **listeners)
82{
83 int ret = 0;
84
85 assert(listeners);
86 *listeners = g_array_new(FALSE, TRUE, sizeof(struct bt_graph_listener));
87 if (!*listeners) {
88 ret = -1;
89 goto end;
90 }
91
92end:
93 return ret;
94}
95
f60c8b34 96struct bt_graph *bt_graph_create(void)
c0418dd9 97{
f60c8b34 98 struct bt_graph *graph;
1bf957a0 99 int ret;
c0418dd9 100
f60c8b34 101 graph = g_new0(struct bt_graph, 1);
c0418dd9
JG
102 if (!graph) {
103 goto end;
104 }
105
f60c8b34 106 bt_object_init(graph, bt_graph_destroy);
c0418dd9 107
f60c8b34 108 graph->connections = g_ptr_array_new_with_free_func(bt_object_release);
c0418dd9
JG
109 if (!graph->connections) {
110 goto error;
111 }
f60c8b34
JG
112 graph->components = g_ptr_array_new_with_free_func(bt_object_release);
113 if (!graph->components) {
114 goto error;
115 }
116 graph->sinks_to_consume = g_queue_new();
117 if (!graph->sinks_to_consume) {
c0418dd9
JG
118 goto error;
119 }
1bf957a0
PP
120
121 ret = init_listeners_array(&graph->listeners.port_added);
122 if (ret) {
123 goto error;
124 }
125
126 ret = init_listeners_array(&graph->listeners.port_removed);
127 if (ret) {
128 goto error;
129 }
130
f345f8bb 131 ret = init_listeners_array(&graph->listeners.ports_connected);
1bf957a0
PP
132 if (ret) {
133 goto error;
134 }
135
f345f8bb 136 ret = init_listeners_array(&graph->listeners.ports_disconnected);
1bf957a0
PP
137 if (ret) {
138 goto error;
139 }
140
c0418dd9
JG
141end:
142 return graph;
143error:
144 BT_PUT(graph);
145 goto end;
146}
147
77a54f99 148struct bt_connection *bt_graph_connect_ports(struct bt_graph *graph,
f60c8b34
JG
149 struct bt_port *upstream_port,
150 struct bt_port *downstream_port)
151{
152 struct bt_connection *connection = NULL;
153 struct bt_graph *upstream_graph = NULL;
154 struct bt_graph *downstream_graph = NULL;
155 struct bt_component *upstream_component = NULL;
156 struct bt_component *downstream_component = NULL;
72b913fb 157 struct bt_connection *existing_conn = NULL;
f60c8b34 158 enum bt_component_status component_status;
ffeb0eed
JG
159 bool upstream_was_already_in_graph;
160 bool downstream_was_already_in_graph;
3eeacbb9
JG
161 int components_to_remove = 0;
162 int i;
f60c8b34
JG
163
164 if (!graph || !upstream_port || !downstream_port) {
165 goto end;
166 }
167
72b913fb 168 /* Ensure appropriate types for upstream and downstream ports. */
f60c8b34
JG
169 if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) {
170 goto end;
171 }
172 if (bt_port_get_type(downstream_port) != BT_PORT_TYPE_INPUT) {
173 goto end;
174 }
175
72b913fb
PP
176 /* Ensure that both ports are currently unconnected. */
177 existing_conn = bt_port_get_connection(upstream_port);
178 bt_put(existing_conn);
179 if (existing_conn) {
180 fprintf(stderr, "Upstream port is already connected\n");
181 goto end;
182 }
183
184 existing_conn = bt_port_get_connection(downstream_port);
185 bt_put(existing_conn);
186 if (existing_conn) {
187 fprintf(stderr, "Downstream port is already connected\n");
188 goto end;
189 }
190
191 /*
192 * Ensure that both ports are still attached to their creating
193 * component.
194 */
f60c8b34 195 upstream_component = bt_port_get_component(upstream_port);
72b913fb
PP
196 if (!upstream_component) {
197 fprintf(stderr, "Upstream port does not belong to a component\n");
198 goto end;
199 }
200
201 downstream_component = bt_port_get_component(downstream_port);
202 if (!downstream_component) {
203 fprintf(stderr, "Downstream port does not belong to a component\n");
204 goto end;
205 }
206
207 /* Ensure the components are not already part of another graph. */
f60c8b34
JG
208 upstream_graph = bt_component_get_graph(upstream_component);
209 if (upstream_graph && (graph != upstream_graph)) {
210 fprintf(stderr, "Upstream component is already part of another graph\n");
211 goto error;
212 }
ffeb0eed 213 upstream_was_already_in_graph = (graph == upstream_graph);
f60c8b34
JG
214 downstream_graph = bt_component_get_graph(downstream_component);
215 if (downstream_graph && (graph != downstream_graph)) {
216 fprintf(stderr, "Downstream component is already part of another graph\n");
217 goto error;
218 }
ffeb0eed 219 downstream_was_already_in_graph = (graph == downstream_graph);
f60c8b34
JG
220
221 connection = bt_connection_create(graph, upstream_port,
222 downstream_port);
223 if (!connection) {
224 goto error;
225 }
226
227 /*
72b913fb
PP
228 * Ownership of upstream_component/downstream_component and of
229 * the connection object is transferred to the graph.
f60c8b34
JG
230 */
231 g_ptr_array_add(graph->connections, connection);
ffeb0eed
JG
232
233 if (!upstream_was_already_in_graph) {
234 g_ptr_array_add(graph->components, upstream_component);
235 bt_component_set_graph(upstream_component, graph);
236 }
237 if (!downstream_was_already_in_graph) {
238 g_ptr_array_add(graph->components, downstream_component);
239 bt_component_set_graph(downstream_component, graph);
240 if (bt_component_get_class_type(downstream_component) ==
241 BT_COMPONENT_CLASS_TYPE_SINK) {
242 g_queue_push_tail(graph->sinks_to_consume,
243 downstream_component);
244 }
f60c8b34
JG
245 }
246
247 /*
248 * The graph is now the parent of these components which garantees their
249 * existence for the duration of the graph's lifetime.
250 */
f60c8b34
JG
251
252 /*
72b913fb
PP
253 * The components and connection are added to the graph before
254 * invoking the `accept_port_connection` method in order to make
255 * them visible to the components during the method's
256 * invocation.
f60c8b34 257 */
72b913fb 258 component_status = bt_component_accept_port_connection(
8f4799f7 259 upstream_component, upstream_port, downstream_port);
f60c8b34 260 if (component_status != BT_COMPONENT_STATUS_OK) {
3eeacbb9 261 goto error_rollback;
f60c8b34 262 }
72b913fb 263 component_status = bt_component_accept_port_connection(
8f4799f7 264 downstream_component, downstream_port, upstream_port);
f60c8b34 265 if (component_status != BT_COMPONENT_STATUS_OK) {
3eeacbb9 266 goto error_rollback;
f60c8b34 267 }
1bf957a0
PP
268
269 /*
270 * Both components accepted the connection. Notify the graph's
271 * creator that both ports are connected.
272 */
f345f8bb 273 bt_graph_notify_ports_connected(graph, upstream_port, downstream_port);
1bf957a0 274
f60c8b34
JG
275end:
276 bt_put(upstream_graph);
277 bt_put(downstream_graph);
3eeacbb9
JG
278 bt_put(upstream_component);
279 bt_put(downstream_component);
f60c8b34 280 return connection;
3eeacbb9
JG
281error_rollback:
282 /*
283 * Remove newly-added components from the graph, being careful
284 * not to remove a component that was already present in the graph
285 * and is connected to other components.
286 */
287 components_to_remove += upstream_was_already_in_graph ? 0 : 1;
288 components_to_remove += downstream_was_already_in_graph ? 0 : 1;
289
290 if (!downstream_was_already_in_graph) {
f60c8b34
JG
291 if (bt_component_get_class_type(downstream_component) ==
292 BT_COMPONENT_CLASS_TYPE_SINK) {
293 g_queue_pop_tail(graph->sinks_to_consume);
294 }
3eeacbb9
JG
295 }
296 /* Remove newly created connection. */
297 g_ptr_array_set_size(graph->connections,
298 graph->connections->len - 1);
299
300 /*
301 * Remove newly added components.
302 *
303 * Note that this is a tricky situation. The graph, being the parent
304 * of the components, does not hold a reference to them. Normally,
305 * components are destroyed right away when the graph is released since
306 * the graph, being their parent, bounds their lifetime
307 * (see doc/ref-counting.md).
308 *
309 * In this particular case, we must take a number of steps:
310 * 1) unset the components' parent to rollback the initial state of
311 * the components being connected.
312 * Note that the reference taken by the component on its graph is
313 * released by the set_parent call.
314 * 2) set the pointer in the components array to NULL so that the
315 * destruction function called on the array's resize in invoked on
316 * NULL (no effect),
317 *
318 * NOTE: Point #1 assumes that *something* holds a reference to both
319 * components being connected. The fact that a reference is being
320 * held to a component means that it must hold a reference to its
321 * parent to prevent the parent from being destroyed (again, refer
322 * to doc/red-counting.md). This reference to a component is
323 * most likely being held *transitively* by the caller which holds
324 * a reference to both ports (a port has its component as a
325 * parent).
326 *
327 * This assumes that a graph is not connecting components by
328 * itself while not holding a reference to the ports/components
329 * being connected (i.e. "cheating" by using internal APIs).
330 */
331 for (i = 0; i < components_to_remove; i++) {
332 struct bt_component *component = g_ptr_array_index(
333 graph->components, graph->components->len - 1);
334
335 bt_component_set_graph(component, NULL);
336 g_ptr_array_index(graph->components,
337 graph->components->len - 1) = NULL;
f60c8b34 338 g_ptr_array_set_size(graph->components,
3eeacbb9 339 graph->components->len - 1);
f60c8b34 340 }
3eeacbb9
JG
341 /* NOTE: Resizing the ptr_arrays invokes the destruction of the elements. */
342 goto end;
343error:
344 BT_PUT(upstream_component);
345 BT_PUT(downstream_component);
f60c8b34
JG
346 goto end;
347}
348
349static
346df6cf
JG
350enum bt_component_status get_component_port_counts(
351 struct bt_component *component, uint64_t *input_count,
352 uint64_t *output_count)
f60c8b34 353{
346df6cf 354 enum bt_component_status ret;
f60c8b34
JG
355
356 switch (bt_component_get_class_type(component)) {
357 case BT_COMPONENT_CLASS_TYPE_SOURCE:
346df6cf
JG
358 ret = bt_component_source_get_output_port_count(component,
359 output_count);
360 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
361 goto end;
362 }
f60c8b34
JG
363 break;
364 case BT_COMPONENT_CLASS_TYPE_FILTER:
346df6cf
JG
365 ret = bt_component_filter_get_output_port_count(component,
366 output_count);
367 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
368 goto end;
369 }
346df6cf
JG
370 ret = bt_component_filter_get_input_port_count(component,
371 input_count);
372 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
373 goto end;
374 }
f60c8b34
JG
375 break;
376 case BT_COMPONENT_CLASS_TYPE_SINK:
346df6cf
JG
377 ret = bt_component_sink_get_input_port_count(component,
378 input_count);
379 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
380 goto end;
381 }
f60c8b34
JG
382 break;
383 default:
384 assert(false);
385 break;
386 }
346df6cf 387 ret = BT_COMPONENT_STATUS_OK;
f60c8b34
JG
388end:
389 return ret;
390}
391
f60c8b34
JG
392enum bt_graph_status bt_graph_add_component_as_sibling(struct bt_graph *graph,
393 struct bt_component *origin,
c0418dd9
JG
394 struct bt_component *new_component)
395{
346df6cf
JG
396 uint64_t origin_input_port_count = 0;
397 uint64_t origin_output_port_count = 0;
398 uint64_t new_input_port_count = 0;
399 uint64_t new_output_port_count = 0;
f60c8b34
JG
400 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
401 struct bt_graph *origin_graph = NULL;
402 struct bt_graph *new_graph = NULL;
403 struct bt_port *origin_port = NULL;
404 struct bt_port *new_port = NULL;
405 struct bt_port *upstream_port = NULL;
406 struct bt_port *downstream_port = NULL;
407 struct bt_connection *origin_connection = NULL;
408 struct bt_connection *new_connection = NULL;
409 int port_index;
410
411 if (!graph || !origin || !new_component) {
412 status = BT_GRAPH_STATUS_INVALID;
413 goto end;
414 }
415
416 if (bt_component_get_class_type(origin) !=
417 bt_component_get_class_type(new_component)) {
418 status = BT_GRAPH_STATUS_INVALID;
419 goto end;
420 }
421
422 origin_graph = bt_component_get_graph(origin);
423 if (!origin_graph || (origin_graph != graph)) {
424 status = BT_GRAPH_STATUS_INVALID;
425 goto end;
426 }
427
428 new_graph = bt_component_get_graph(new_component);
429 if (new_graph) {
430 status = BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH;
431 goto end;
432 }
433
434 if (get_component_port_counts(origin, &origin_input_port_count,
346df6cf 435 &origin_output_port_count) != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
436 status = BT_GRAPH_STATUS_INVALID;
437 goto end;
438 }
439 if (get_component_port_counts(new_component, &new_input_port_count,
346df6cf 440 &new_output_port_count) != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
441 status = BT_GRAPH_STATUS_INVALID;
442 goto end;
443 }
444
445 if (origin_input_port_count != new_input_port_count ||
446 origin_output_port_count != new_output_port_count) {
447 status = BT_GRAPH_STATUS_INVALID;
448 goto end;
449 }
450
451 /* Replicate input connections. */
452 for (port_index = 0; port_index< origin_input_port_count; port_index++) {
72b913fb
PP
453 origin_port = bt_component_get_input_port_at_index(origin,
454 port_index);
f60c8b34
JG
455 if (!origin_port) {
456 status = BT_GRAPH_STATUS_ERROR;
457 goto error_disconnect;
458 }
f60c8b34 459
72b913fb
PP
460 new_port = bt_component_get_input_port_at_index(new_component,
461 port_index);
462 if (!new_port) {
f60c8b34
JG
463 status = BT_GRAPH_STATUS_ERROR;
464 goto error_disconnect;
465 }
466
72b913fb
PP
467 origin_connection = bt_port_get_connection(origin_port);
468 if (origin_connection) {
469 upstream_port = bt_connection_get_upstream_port(
470 origin_connection);
f60c8b34
JG
471 if (!upstream_port) {
472 goto error_disconnect;
473 }
474
77a54f99
PP
475 new_connection = bt_graph_connect_ports(graph,
476 upstream_port, new_port);
f60c8b34
JG
477 if (!new_connection) {
478 goto error_disconnect;
479 }
f60c8b34 480 }
72b913fb
PP
481
482 BT_PUT(upstream_port);
483 BT_PUT(origin_connection);
484 BT_PUT(new_connection);
f60c8b34
JG
485 BT_PUT(origin_port);
486 BT_PUT(new_port);
487 }
488
489 /* Replicate output connections. */
72b913fb
PP
490 for (port_index = 0; port_index < origin_output_port_count; port_index++) {
491 origin_port = bt_component_get_output_port_at_index(origin,
492 port_index);
f60c8b34
JG
493 if (!origin_port) {
494 status = BT_GRAPH_STATUS_ERROR;
495 goto error_disconnect;
496 }
72b913fb
PP
497 new_port = bt_component_get_output_port_at_index(new_component,
498 port_index);
f60c8b34
JG
499 if (!new_port) {
500 status = BT_GRAPH_STATUS_ERROR;
501 goto error_disconnect;
502 }
503
72b913fb
PP
504 origin_connection = bt_port_get_connection(origin_port);
505 if (origin_connection) {
506 downstream_port = bt_connection_get_downstream_port(
f60c8b34
JG
507 origin_connection);
508 if (!downstream_port) {
509 goto error_disconnect;
510 }
511
77a54f99
PP
512 new_connection = bt_graph_connect_ports(graph,
513 new_port, downstream_port);
f60c8b34
JG
514 if (!new_connection) {
515 goto error_disconnect;
516 }
f60c8b34 517 }
72b913fb
PP
518
519 BT_PUT(downstream_port);
520 BT_PUT(origin_connection);
521 BT_PUT(new_connection);
f60c8b34
JG
522 BT_PUT(origin_port);
523 BT_PUT(new_port);
524 }
525end:
526 bt_put(origin_graph);
527 bt_put(new_graph);
528 bt_put(origin_port);
529 bt_put(new_port);
530 bt_put(upstream_port);
531 bt_put(downstream_port);
532 bt_put(origin_connection);
533 bt_put(new_connection);
534 return status;
535error_disconnect:
536 /* Destroy all connections of the new component. */
537 /* FIXME. */
538 goto end;
c0418dd9
JG
539}
540
72b913fb 541enum bt_graph_status bt_graph_consume(struct bt_graph *graph)
c0418dd9 542{
f60c8b34 543 struct bt_component *sink;
72b913fb
PP
544 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
545 enum bt_component_status comp_status;
f60c8b34
JG
546 GList *current_node;
547
548 if (!graph) {
72b913fb 549 status = BT_GRAPH_STATUS_INVALID;
f60c8b34
JG
550 goto end;
551 }
552
553 if (g_queue_is_empty(graph->sinks_to_consume)) {
72b913fb 554 status = BT_GRAPH_STATUS_END;
f60c8b34
JG
555 goto end;
556 }
557
558 current_node = g_queue_pop_head_link(graph->sinks_to_consume);
559 sink = current_node->data;
72b913fb
PP
560 comp_status = bt_component_sink_consume(sink);
561 switch (comp_status) {
562 case BT_COMPONENT_STATUS_OK:
563 break;
564 case BT_COMPONENT_STATUS_END:
565 status = BT_GRAPH_STATUS_END;
566 break;
567 case BT_COMPONENT_STATUS_AGAIN:
568 status = BT_GRAPH_STATUS_AGAIN;
569 break;
570 case BT_COMPONENT_STATUS_INVALID:
571 status = BT_GRAPH_STATUS_INVALID;
572 break;
573 default:
574 status = BT_GRAPH_STATUS_ERROR;
575 break;
576 }
577
578 if (status != BT_GRAPH_STATUS_END) {
f60c8b34
JG
579 g_queue_push_tail_link(graph->sinks_to_consume, current_node);
580 goto end;
581 }
582
583 /* End reached, the node is not added back to the queue and free'd. */
584 g_queue_delete_link(graph->sinks_to_consume, current_node);
585
586 /* Don't forward an END status if there are sinks left to consume. */
587 if (!g_queue_is_empty(graph->sinks_to_consume)) {
588 status = BT_GRAPH_STATUS_OK;
589 goto end;
590 }
591end:
592 return status;
c0418dd9
JG
593}
594
72b913fb 595enum bt_graph_status bt_graph_run(struct bt_graph *graph)
f60c8b34 596{
72b913fb 597 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
f60c8b34
JG
598
599 if (!graph) {
72b913fb 600 status = BT_GRAPH_STATUS_INVALID;
f60c8b34
JG
601 goto error;
602 }
603
604 do {
72b913fb
PP
605 status = bt_graph_consume(graph);
606 if (status == BT_GRAPH_STATUS_AGAIN) {
f60c8b34
JG
607 /*
608 * If AGAIN is received and there are multiple sinks,
609 * go ahead and consume from the next sink.
610 *
611 * However, in the case where a single sink is left,
612 * the caller can decide to busy-wait and call
613 * bt_graph_run continuously until the source is ready
614 * or it can decide to sleep for an arbitrary amount of
615 * time.
616 */
617 if (graph->sinks_to_consume->length > 1) {
72b913fb 618 status = BT_GRAPH_STATUS_OK;
f60c8b34
JG
619 }
620 }
72b913fb 621 } while (status == BT_GRAPH_STATUS_OK);
f60c8b34
JG
622
623 if (g_queue_is_empty(graph->sinks_to_consume)) {
72b913fb 624 status = BT_GRAPH_STATUS_END;
f60c8b34
JG
625 }
626error:
72b913fb 627 return status;
f60c8b34 628}
1bf957a0
PP
629
630static
631void add_listener(GArray *listeners, void *func, void *data)
632{
633 struct bt_graph_listener listener = {
634 .func = func,
635 .data = data,
636 };
637
638 g_array_append_val(listeners, listener);
639}
640
641enum bt_graph_status bt_graph_add_port_added_listener(
642 struct bt_graph *graph,
643 bt_graph_port_added_listener listener, void *data)
644{
645 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
646
647 if (!graph || !listener) {
648 status = BT_GRAPH_STATUS_INVALID;
649 goto end;
650 }
651
652 add_listener(graph->listeners.port_added, listener, data);
653
654end:
655 return status;
656}
657
658enum bt_graph_status bt_graph_add_port_removed_listener(
659 struct bt_graph *graph,
660 bt_graph_port_removed_listener listener, void *data)
661{
662 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
663
664 if (!graph || !listener) {
665 status = BT_GRAPH_STATUS_INVALID;
666 goto end;
667 }
668
669 add_listener(graph->listeners.port_removed, listener, data);
670
671end:
672 return status;
673}
674
f345f8bb 675enum bt_graph_status bt_graph_add_ports_connected_listener(
1bf957a0 676 struct bt_graph *graph,
f345f8bb 677 bt_graph_ports_connected_listener listener, void *data)
1bf957a0
PP
678{
679 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
680
681 if (!graph || !listener) {
682 status = BT_GRAPH_STATUS_INVALID;
683 goto end;
684 }
685
f345f8bb 686 add_listener(graph->listeners.ports_connected, listener, data);
1bf957a0
PP
687
688end:
689 return status;
690}
691
f345f8bb 692enum bt_graph_status bt_graph_add_ports_disconnected_listener(
1bf957a0 693 struct bt_graph *graph,
f345f8bb 694 bt_graph_ports_disconnected_listener listener, void *data)
1bf957a0
PP
695{
696 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
697
698 if (!graph || !listener) {
699 status = BT_GRAPH_STATUS_INVALID;
700 goto end;
701 }
702
f345f8bb 703 add_listener(graph->listeners.ports_disconnected, listener, data);
1bf957a0
PP
704
705end:
706 return status;
707}
708
709BT_HIDDEN
710void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port)
711{
712 size_t i;
713
714 for (i = 0; i < graph->listeners.port_added->len; i++) {
715 struct bt_graph_listener listener =
716 g_array_index(graph->listeners.port_added,
717 struct bt_graph_listener, i);
718 bt_graph_port_added_listener func = listener.func;
719
720 assert(func);
721 func(port, listener.data);
722 }
723}
724
725BT_HIDDEN
726void bt_graph_notify_port_removed(struct bt_graph *graph,
727 struct bt_component *comp, struct bt_port *port)
728{
729 size_t i;
730
731 for (i = 0; i < graph->listeners.port_removed->len; i++) {
732 struct bt_graph_listener listener =
733 g_array_index(graph->listeners.port_removed,
734 struct bt_graph_listener, i);
735 bt_graph_port_removed_listener func = listener.func;
736
737 assert(func);
738 func(comp, port, listener.data);
739 }
740}
741
742BT_HIDDEN
f345f8bb
PP
743void bt_graph_notify_ports_connected(struct bt_graph *graph,
744 struct bt_port *upstream_port, struct bt_port *downstream_port)
1bf957a0
PP
745{
746 size_t i;
747
f345f8bb 748 for (i = 0; i < graph->listeners.ports_connected->len; i++) {
1bf957a0 749 struct bt_graph_listener listener =
f345f8bb 750 g_array_index(graph->listeners.ports_connected,
1bf957a0 751 struct bt_graph_listener, i);
f345f8bb 752 bt_graph_ports_connected_listener func = listener.func;
1bf957a0
PP
753
754 assert(func);
f345f8bb 755 func(upstream_port, downstream_port, listener.data);
1bf957a0
PP
756 }
757}
758
759BT_HIDDEN
f345f8bb
PP
760void bt_graph_notify_ports_disconnected(struct bt_graph *graph,
761 struct bt_component *upstream_comp,
762 struct bt_component *downstream_comp,
763 struct bt_port *upstream_port, struct bt_port *downstream_port)
1bf957a0
PP
764{
765 size_t i;
766
f345f8bb 767 for (i = 0; i < graph->listeners.ports_disconnected->len; i++) {
1bf957a0 768 struct bt_graph_listener listener =
f345f8bb 769 g_array_index(graph->listeners.ports_disconnected,
1bf957a0 770 struct bt_graph_listener, i);
f345f8bb 771 bt_graph_ports_disconnected_listener func = listener.func;
1bf957a0
PP
772
773 assert(func);
f345f8bb
PP
774 func(upstream_comp, downstream_comp, upstream_port,
775 downstream_port, listener.data);
1bf957a0
PP
776 }
777}
This page took 0.057858 seconds and 4 git commands to generate.