Update notification iterator's "init" function signature
[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
f60c8b34 29#include <babeltrace/component/component-internal.h>
7d55361f
JG
30#include <babeltrace/component/graph-internal.h>
31#include <babeltrace/component/connection-internal.h>
f60c8b34
JG
32#include <babeltrace/component/component-sink-internal.h>
33#include <babeltrace/component/component-source.h>
34#include <babeltrace/component/component-filter.h>
7d55361f 35#include <babeltrace/component/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
69 if (graph->listeners.port_connected) {
70 g_array_free(graph->listeners.port_connected, TRUE);
71 }
72
73 if (graph->listeners.port_disconnected) {
74 g_array_free(graph->listeners.port_disconnected, TRUE);
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
131 ret = init_listeners_array(&graph->listeners.port_connected);
132 if (ret) {
133 goto error;
134 }
135
136 ret = init_listeners_array(&graph->listeners.port_disconnected);
137 if (ret) {
138 goto error;
139 }
140
c0418dd9
JG
141end:
142 return graph;
143error:
144 BT_PUT(graph);
145 goto end;
146}
147
f60c8b34
JG
148struct bt_connection *bt_graph_connect(struct bt_graph *graph,
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 */
273 bt_graph_notify_port_connected(graph, upstream_port);
274 bt_graph_notify_port_connected(graph, downstream_port);
275
f60c8b34
JG
276end:
277 bt_put(upstream_graph);
278 bt_put(downstream_graph);
3eeacbb9
JG
279 bt_put(upstream_component);
280 bt_put(downstream_component);
f60c8b34 281 return connection;
3eeacbb9
JG
282error_rollback:
283 /*
284 * Remove newly-added components from the graph, being careful
285 * not to remove a component that was already present in the graph
286 * and is connected to other components.
287 */
288 components_to_remove += upstream_was_already_in_graph ? 0 : 1;
289 components_to_remove += downstream_was_already_in_graph ? 0 : 1;
290
291 if (!downstream_was_already_in_graph) {
f60c8b34
JG
292 if (bt_component_get_class_type(downstream_component) ==
293 BT_COMPONENT_CLASS_TYPE_SINK) {
294 g_queue_pop_tail(graph->sinks_to_consume);
295 }
3eeacbb9
JG
296 }
297 /* Remove newly created connection. */
298 g_ptr_array_set_size(graph->connections,
299 graph->connections->len - 1);
300
301 /*
302 * Remove newly added components.
303 *
304 * Note that this is a tricky situation. The graph, being the parent
305 * of the components, does not hold a reference to them. Normally,
306 * components are destroyed right away when the graph is released since
307 * the graph, being their parent, bounds their lifetime
308 * (see doc/ref-counting.md).
309 *
310 * In this particular case, we must take a number of steps:
311 * 1) unset the components' parent to rollback the initial state of
312 * the components being connected.
313 * Note that the reference taken by the component on its graph is
314 * released by the set_parent call.
315 * 2) set the pointer in the components array to NULL so that the
316 * destruction function called on the array's resize in invoked on
317 * NULL (no effect),
318 *
319 * NOTE: Point #1 assumes that *something* holds a reference to both
320 * components being connected. The fact that a reference is being
321 * held to a component means that it must hold a reference to its
322 * parent to prevent the parent from being destroyed (again, refer
323 * to doc/red-counting.md). This reference to a component is
324 * most likely being held *transitively* by the caller which holds
325 * a reference to both ports (a port has its component as a
326 * parent).
327 *
328 * This assumes that a graph is not connecting components by
329 * itself while not holding a reference to the ports/components
330 * being connected (i.e. "cheating" by using internal APIs).
331 */
332 for (i = 0; i < components_to_remove; i++) {
333 struct bt_component *component = g_ptr_array_index(
334 graph->components, graph->components->len - 1);
335
336 bt_component_set_graph(component, NULL);
337 g_ptr_array_index(graph->components,
338 graph->components->len - 1) = NULL;
f60c8b34 339 g_ptr_array_set_size(graph->components,
3eeacbb9 340 graph->components->len - 1);
f60c8b34 341 }
3eeacbb9
JG
342 /* NOTE: Resizing the ptr_arrays invokes the destruction of the elements. */
343 goto end;
344error:
345 BT_PUT(upstream_component);
346 BT_PUT(downstream_component);
f60c8b34
JG
347 goto end;
348}
349
350static
346df6cf
JG
351enum bt_component_status get_component_port_counts(
352 struct bt_component *component, uint64_t *input_count,
353 uint64_t *output_count)
f60c8b34 354{
346df6cf 355 enum bt_component_status ret;
f60c8b34
JG
356
357 switch (bt_component_get_class_type(component)) {
358 case BT_COMPONENT_CLASS_TYPE_SOURCE:
346df6cf
JG
359 ret = bt_component_source_get_output_port_count(component,
360 output_count);
361 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
362 goto end;
363 }
f60c8b34
JG
364 break;
365 case BT_COMPONENT_CLASS_TYPE_FILTER:
346df6cf
JG
366 ret = bt_component_filter_get_output_port_count(component,
367 output_count);
368 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
369 goto end;
370 }
346df6cf
JG
371 ret = bt_component_filter_get_input_port_count(component,
372 input_count);
373 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
374 goto end;
375 }
f60c8b34
JG
376 break;
377 case BT_COMPONENT_CLASS_TYPE_SINK:
346df6cf
JG
378 ret = bt_component_sink_get_input_port_count(component,
379 input_count);
380 if (ret != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
381 goto end;
382 }
f60c8b34
JG
383 break;
384 default:
385 assert(false);
386 break;
387 }
346df6cf 388 ret = BT_COMPONENT_STATUS_OK;
f60c8b34
JG
389end:
390 return ret;
391}
392
f60c8b34
JG
393enum bt_graph_status bt_graph_add_component_as_sibling(struct bt_graph *graph,
394 struct bt_component *origin,
c0418dd9
JG
395 struct bt_component *new_component)
396{
346df6cf
JG
397 uint64_t origin_input_port_count = 0;
398 uint64_t origin_output_port_count = 0;
399 uint64_t new_input_port_count = 0;
400 uint64_t new_output_port_count = 0;
f60c8b34
JG
401 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
402 struct bt_graph *origin_graph = NULL;
403 struct bt_graph *new_graph = NULL;
404 struct bt_port *origin_port = NULL;
405 struct bt_port *new_port = NULL;
406 struct bt_port *upstream_port = NULL;
407 struct bt_port *downstream_port = NULL;
408 struct bt_connection *origin_connection = NULL;
409 struct bt_connection *new_connection = NULL;
410 int port_index;
411
412 if (!graph || !origin || !new_component) {
413 status = BT_GRAPH_STATUS_INVALID;
414 goto end;
415 }
416
417 if (bt_component_get_class_type(origin) !=
418 bt_component_get_class_type(new_component)) {
419 status = BT_GRAPH_STATUS_INVALID;
420 goto end;
421 }
422
423 origin_graph = bt_component_get_graph(origin);
424 if (!origin_graph || (origin_graph != graph)) {
425 status = BT_GRAPH_STATUS_INVALID;
426 goto end;
427 }
428
429 new_graph = bt_component_get_graph(new_component);
430 if (new_graph) {
431 status = BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH;
432 goto end;
433 }
434
435 if (get_component_port_counts(origin, &origin_input_port_count,
346df6cf 436 &origin_output_port_count) != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
437 status = BT_GRAPH_STATUS_INVALID;
438 goto end;
439 }
440 if (get_component_port_counts(new_component, &new_input_port_count,
346df6cf 441 &new_output_port_count) != BT_COMPONENT_STATUS_OK) {
f60c8b34
JG
442 status = BT_GRAPH_STATUS_INVALID;
443 goto end;
444 }
445
446 if (origin_input_port_count != new_input_port_count ||
447 origin_output_port_count != new_output_port_count) {
448 status = BT_GRAPH_STATUS_INVALID;
449 goto end;
450 }
451
452 /* Replicate input connections. */
453 for (port_index = 0; port_index< origin_input_port_count; port_index++) {
72b913fb
PP
454 origin_port = bt_component_get_input_port_at_index(origin,
455 port_index);
f60c8b34
JG
456 if (!origin_port) {
457 status = BT_GRAPH_STATUS_ERROR;
458 goto error_disconnect;
459 }
f60c8b34 460
72b913fb
PP
461 new_port = bt_component_get_input_port_at_index(new_component,
462 port_index);
463 if (!new_port) {
f60c8b34
JG
464 status = BT_GRAPH_STATUS_ERROR;
465 goto error_disconnect;
466 }
467
72b913fb
PP
468 origin_connection = bt_port_get_connection(origin_port);
469 if (origin_connection) {
470 upstream_port = bt_connection_get_upstream_port(
471 origin_connection);
f60c8b34
JG
472 if (!upstream_port) {
473 goto error_disconnect;
474 }
475
476 new_connection = bt_graph_connect(graph, upstream_port,
477 new_port);
478 if (!new_connection) {
479 goto error_disconnect;
480 }
f60c8b34 481 }
72b913fb
PP
482
483 BT_PUT(upstream_port);
484 BT_PUT(origin_connection);
485 BT_PUT(new_connection);
f60c8b34
JG
486 BT_PUT(origin_port);
487 BT_PUT(new_port);
488 }
489
490 /* Replicate output connections. */
72b913fb
PP
491 for (port_index = 0; port_index < origin_output_port_count; port_index++) {
492 origin_port = bt_component_get_output_port_at_index(origin,
493 port_index);
f60c8b34
JG
494 if (!origin_port) {
495 status = BT_GRAPH_STATUS_ERROR;
496 goto error_disconnect;
497 }
72b913fb
PP
498 new_port = bt_component_get_output_port_at_index(new_component,
499 port_index);
f60c8b34
JG
500 if (!new_port) {
501 status = BT_GRAPH_STATUS_ERROR;
502 goto error_disconnect;
503 }
504
72b913fb
PP
505 origin_connection = bt_port_get_connection(origin_port);
506 if (origin_connection) {
507 downstream_port = bt_connection_get_downstream_port(
f60c8b34
JG
508 origin_connection);
509 if (!downstream_port) {
510 goto error_disconnect;
511 }
512
513 new_connection = bt_graph_connect(graph, new_port,
514 downstream_port);
515 if (!new_connection) {
516 goto error_disconnect;
517 }
f60c8b34 518 }
72b913fb
PP
519
520 BT_PUT(downstream_port);
521 BT_PUT(origin_connection);
522 BT_PUT(new_connection);
f60c8b34
JG
523 BT_PUT(origin_port);
524 BT_PUT(new_port);
525 }
526end:
527 bt_put(origin_graph);
528 bt_put(new_graph);
529 bt_put(origin_port);
530 bt_put(new_port);
531 bt_put(upstream_port);
532 bt_put(downstream_port);
533 bt_put(origin_connection);
534 bt_put(new_connection);
535 return status;
536error_disconnect:
537 /* Destroy all connections of the new component. */
538 /* FIXME. */
539 goto end;
c0418dd9
JG
540}
541
72b913fb 542enum bt_graph_status bt_graph_consume(struct bt_graph *graph)
c0418dd9 543{
f60c8b34 544 struct bt_component *sink;
72b913fb
PP
545 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
546 enum bt_component_status comp_status;
f60c8b34
JG
547 GList *current_node;
548
549 if (!graph) {
72b913fb 550 status = BT_GRAPH_STATUS_INVALID;
f60c8b34
JG
551 goto end;
552 }
553
554 if (g_queue_is_empty(graph->sinks_to_consume)) {
72b913fb 555 status = BT_GRAPH_STATUS_END;
f60c8b34
JG
556 goto end;
557 }
558
559 current_node = g_queue_pop_head_link(graph->sinks_to_consume);
560 sink = current_node->data;
72b913fb
PP
561 comp_status = bt_component_sink_consume(sink);
562 switch (comp_status) {
563 case BT_COMPONENT_STATUS_OK:
564 break;
565 case BT_COMPONENT_STATUS_END:
566 status = BT_GRAPH_STATUS_END;
567 break;
568 case BT_COMPONENT_STATUS_AGAIN:
569 status = BT_GRAPH_STATUS_AGAIN;
570 break;
571 case BT_COMPONENT_STATUS_INVALID:
572 status = BT_GRAPH_STATUS_INVALID;
573 break;
574 default:
575 status = BT_GRAPH_STATUS_ERROR;
576 break;
577 }
578
579 if (status != BT_GRAPH_STATUS_END) {
f60c8b34
JG
580 g_queue_push_tail_link(graph->sinks_to_consume, current_node);
581 goto end;
582 }
583
584 /* End reached, the node is not added back to the queue and free'd. */
585 g_queue_delete_link(graph->sinks_to_consume, current_node);
586
587 /* Don't forward an END status if there are sinks left to consume. */
588 if (!g_queue_is_empty(graph->sinks_to_consume)) {
589 status = BT_GRAPH_STATUS_OK;
590 goto end;
591 }
592end:
593 return status;
c0418dd9
JG
594}
595
72b913fb 596enum bt_graph_status bt_graph_run(struct bt_graph *graph)
f60c8b34 597{
72b913fb 598 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
f60c8b34
JG
599
600 if (!graph) {
72b913fb 601 status = BT_GRAPH_STATUS_INVALID;
f60c8b34
JG
602 goto error;
603 }
604
605 do {
72b913fb
PP
606 status = bt_graph_consume(graph);
607 if (status == BT_GRAPH_STATUS_AGAIN) {
f60c8b34
JG
608 /*
609 * If AGAIN is received and there are multiple sinks,
610 * go ahead and consume from the next sink.
611 *
612 * However, in the case where a single sink is left,
613 * the caller can decide to busy-wait and call
614 * bt_graph_run continuously until the source is ready
615 * or it can decide to sleep for an arbitrary amount of
616 * time.
617 */
618 if (graph->sinks_to_consume->length > 1) {
72b913fb 619 status = BT_GRAPH_STATUS_OK;
f60c8b34
JG
620 }
621 }
72b913fb 622 } while (status == BT_GRAPH_STATUS_OK);
f60c8b34
JG
623
624 if (g_queue_is_empty(graph->sinks_to_consume)) {
72b913fb 625 status = BT_GRAPH_STATUS_END;
f60c8b34
JG
626 }
627error:
72b913fb 628 return status;
f60c8b34 629}
1bf957a0
PP
630
631static
632void add_listener(GArray *listeners, void *func, void *data)
633{
634 struct bt_graph_listener listener = {
635 .func = func,
636 .data = data,
637 };
638
639 g_array_append_val(listeners, listener);
640}
641
642enum bt_graph_status bt_graph_add_port_added_listener(
643 struct bt_graph *graph,
644 bt_graph_port_added_listener listener, void *data)
645{
646 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
647
648 if (!graph || !listener) {
649 status = BT_GRAPH_STATUS_INVALID;
650 goto end;
651 }
652
653 add_listener(graph->listeners.port_added, listener, data);
654
655end:
656 return status;
657}
658
659enum bt_graph_status bt_graph_add_port_removed_listener(
660 struct bt_graph *graph,
661 bt_graph_port_removed_listener listener, void *data)
662{
663 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
664
665 if (!graph || !listener) {
666 status = BT_GRAPH_STATUS_INVALID;
667 goto end;
668 }
669
670 add_listener(graph->listeners.port_removed, listener, data);
671
672end:
673 return status;
674}
675
676enum bt_graph_status bt_graph_add_port_connected_listener(
677 struct bt_graph *graph,
678 bt_graph_port_connected_listener listener, void *data)
679{
680 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
681
682 if (!graph || !listener) {
683 status = BT_GRAPH_STATUS_INVALID;
684 goto end;
685 }
686
687 add_listener(graph->listeners.port_connected, listener, data);
688
689end:
690 return status;
691}
692
693enum bt_graph_status bt_graph_add_port_disconnected_listener(
694 struct bt_graph *graph,
695 bt_graph_port_disconnected_listener listener, void *data)
696{
697 enum bt_graph_status status = BT_GRAPH_STATUS_OK;
698
699 if (!graph || !listener) {
700 status = BT_GRAPH_STATUS_INVALID;
701 goto end;
702 }
703
704 add_listener(graph->listeners.port_disconnected, listener, data);
705
706end:
707 return status;
708}
709
710BT_HIDDEN
711void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port)
712{
713 size_t i;
714
715 for (i = 0; i < graph->listeners.port_added->len; i++) {
716 struct bt_graph_listener listener =
717 g_array_index(graph->listeners.port_added,
718 struct bt_graph_listener, i);
719 bt_graph_port_added_listener func = listener.func;
720
721 assert(func);
722 func(port, listener.data);
723 }
724}
725
726BT_HIDDEN
727void bt_graph_notify_port_removed(struct bt_graph *graph,
728 struct bt_component *comp, struct bt_port *port)
729{
730 size_t i;
731
732 for (i = 0; i < graph->listeners.port_removed->len; i++) {
733 struct bt_graph_listener listener =
734 g_array_index(graph->listeners.port_removed,
735 struct bt_graph_listener, i);
736 bt_graph_port_removed_listener func = listener.func;
737
738 assert(func);
739 func(comp, port, listener.data);
740 }
741}
742
743BT_HIDDEN
744void bt_graph_notify_port_connected(struct bt_graph *graph,
745 struct bt_port *port)
746{
747 size_t i;
748
749 for (i = 0; i < graph->listeners.port_connected->len; i++) {
750 struct bt_graph_listener listener =
751 g_array_index(graph->listeners.port_connected,
752 struct bt_graph_listener, i);
753 bt_graph_port_connected_listener func = listener.func;
754
755 assert(func);
756 func(port, listener.data);
757 }
758}
759
760BT_HIDDEN
761void bt_graph_notify_port_disconnected(struct bt_graph *graph,
762 struct bt_component *comp, struct bt_port *port)
763{
764 size_t i;
765
766 for (i = 0; i < graph->listeners.port_disconnected->len; i++) {
767 struct bt_graph_listener listener =
768 g_array_index(graph->listeners.port_disconnected,
769 struct bt_graph_listener, i);
770 bt_graph_port_disconnected_listener func = listener.func;
771
772 assert(func);
773 func(comp, port, listener.data);
774 }
775}
This page took 0.057457 seconds and 4 git commands to generate.