From 1bf957a039dfe5a1cd00659779fdb004aacd706b Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Sat, 25 Mar 2017 01:27:24 -0400 Subject: [PATCH] Add graph event listeners MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit With this patch you can add event listeners to a graph: * Port added to a graph's component. Note that this is only called when the component belongs to a graph. It is not called for existing ports when the component becomes part of a graph (with bt_graph_connect()). * Port removed from a graph's component. * Graph component's port connected. * Graph component's port disconnected. All those listeners return `void` because they cannot "fail". In the worst case they should just abort. Another way would be to set a flag at some place and read it once you have called bt_graph_run() or bt_graph_consume(). Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- include/babeltrace/component/graph-internal.h | 25 ++ include/babeltrace/component/graph.h | 26 +++ lib/component/component.c | 21 +- lib/component/connection.c | 19 +- lib/component/graph.c | 215 ++++++++++++++++++ 5 files changed, 304 insertions(+), 2 deletions(-) diff --git a/include/babeltrace/component/graph-internal.h b/include/babeltrace/component/graph-internal.h index 7da6255f..0084628a 100644 --- a/include/babeltrace/component/graph-internal.h +++ b/include/babeltrace/component/graph-internal.h @@ -32,6 +32,9 @@ #include #include +struct bt_component; +struct bt_port; + struct bt_graph { /** * A component graph contains components and point-to-point connection @@ -51,6 +54,28 @@ struct bt_graph { GPtrArray *components; /* Queue of pointers (weak references) to sink bt_components. */ GQueue *sinks_to_consume; + + struct { + GArray *port_added; + GArray *port_removed; + GArray *port_connected; + GArray *port_disconnected; + } listeners; }; +BT_HIDDEN +void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port); + +BT_HIDDEN +void bt_graph_notify_port_removed(struct bt_graph *graph, + struct bt_component *comp, struct bt_port *port); + +BT_HIDDEN +void bt_graph_notify_port_connected(struct bt_graph *graph, + struct bt_port *port); + +BT_HIDDEN +void bt_graph_notify_port_disconnected(struct bt_graph *graph, + struct bt_component *comp, struct bt_port *port); + #endif /* BABELTRACE_COMPONENT_COMPONENT_GRAPH_INTERNAL_H */ diff --git a/include/babeltrace/component/graph.h b/include/babeltrace/component/graph.h index 4524be35..2d62484f 100644 --- a/include/babeltrace/component/graph.h +++ b/include/babeltrace/component/graph.h @@ -54,6 +54,16 @@ enum bt_graph_status { BT_GRAPH_STATUS_ERROR = -5, }; +typedef void (*bt_graph_port_added_listener)(struct bt_port *port, + void *data); +typedef void (*bt_graph_port_removed_listener)(struct bt_component *component, + struct bt_port *port, void *data); +typedef void (*bt_graph_port_connected_listener)(struct bt_port *port, + void *data); +typedef void (*bt_graph_port_disconnected_listener)( + struct bt_component *component, struct bt_port *port, + void *data); + extern struct bt_graph *bt_graph_create(void); /** @@ -88,6 +98,22 @@ extern enum bt_graph_status bt_graph_run(struct bt_graph *graph); */ extern enum bt_graph_status bt_graph_consume(struct bt_graph *graph); +extern enum bt_graph_status bt_graph_add_port_added_listener( + struct bt_graph *graph, + bt_graph_port_added_listener listener, void *data); + +extern enum bt_graph_status bt_graph_add_port_removed_listener( + struct bt_graph *graph, + bt_graph_port_removed_listener listener, void *data); + +extern enum bt_graph_status bt_graph_add_port_connected_listener( + struct bt_graph *graph, + bt_graph_port_connected_listener listener, void *data); + +extern enum bt_graph_status bt_graph_add_port_disconnected_listener( + struct bt_graph *graph, + bt_graph_port_disconnected_listener listener, void *data); + #ifdef __cplusplus } #endif diff --git a/lib/component/component.c b/lib/component/component.c index 7a72fe79..d55526c8 100644 --- a/lib/component/component.c +++ b/lib/component/component.c @@ -187,6 +187,7 @@ struct bt_port *bt_component_add_port( { size_t i; struct bt_port *new_port = NULL; + struct bt_graph *graph = NULL; if (!name || strlen(name) == 0) { goto end; @@ -221,6 +222,16 @@ struct bt_port *bt_component_add_port( * is now protected by the component's own lifetime. */ g_ptr_array_add(ports, new_port); + + /* + * Notify the graph's creator that a new port was added. + */ + graph = bt_component_get_graph(component); + if (graph) { + bt_graph_notify_port_added(graph, new_port); + BT_PUT(graph); + } + end: return new_port; } @@ -515,6 +526,7 @@ void bt_component_remove_port_at_index(struct bt_component *component, GPtrArray *ports, size_t index) { struct bt_port *port; + struct bt_graph *graph; assert(ports); assert(index < ports->len); @@ -531,7 +543,14 @@ void bt_component_remove_port_at_index(struct bt_component *component, /* Detach port from its component parent */ BT_PUT(port->base.parent); - // TODO: notify graph user: component's port removed + /* + * Notify the graph's creator that a port is removed. + */ + graph = bt_component_get_graph(component); + if (graph) { + bt_graph_notify_port_removed(graph, component, port); + BT_PUT(graph); + } } BT_HIDDEN diff --git a/lib/component/connection.c b/lib/component/connection.c index 88f26af4..702db81d 100644 --- a/lib/component/connection.c +++ b/lib/component/connection.c @@ -112,7 +112,24 @@ void bt_connection_disconnect_ports(struct bt_connection *conn, bt_component_port_disconnected(upstream_comp, upstream_port); } - // TODO: notify graph user: component's port disconnected + if (upstream_comp) { + struct bt_graph *graph = bt_component_get_graph(upstream_comp); + + assert(graph); + bt_graph_notify_port_disconnected(graph, upstream_comp, + upstream_port); + bt_put(graph); + } + + if (downstream_comp) { + struct bt_graph *graph = + bt_component_get_graph(downstream_comp); + + assert(graph); + bt_graph_notify_port_disconnected(graph, downstream_comp, + downstream_port); + bt_put(graph); + } bt_put(downstream_comp); bt_put(upstream_comp); diff --git a/lib/component/graph.c b/lib/component/graph.c index 8b2bed44..8e21e1a3 100644 --- a/lib/component/graph.c +++ b/lib/component/graph.c @@ -35,6 +35,12 @@ #include #include #include +#include + +struct bt_graph_listener { + void *func; + void *data; +}; static void bt_graph_destroy(struct bt_object *obj) @@ -51,12 +57,46 @@ void bt_graph_destroy(struct bt_object *obj) if (graph->sinks_to_consume) { g_queue_free(graph->sinks_to_consume); } + + if (graph->listeners.port_added) { + g_array_free(graph->listeners.port_added, TRUE); + } + + if (graph->listeners.port_removed) { + g_array_free(graph->listeners.port_removed, TRUE); + } + + if (graph->listeners.port_connected) { + g_array_free(graph->listeners.port_connected, TRUE); + } + + if (graph->listeners.port_disconnected) { + g_array_free(graph->listeners.port_disconnected, TRUE); + } + g_free(graph); } +static +int init_listeners_array(GArray **listeners) +{ + int ret = 0; + + assert(listeners); + *listeners = g_array_new(FALSE, TRUE, sizeof(struct bt_graph_listener)); + if (!*listeners) { + ret = -1; + goto end; + } + +end: + return ret; +} + struct bt_graph *bt_graph_create(void) { struct bt_graph *graph; + int ret; graph = g_new0(struct bt_graph, 1); if (!graph) { @@ -77,6 +117,27 @@ struct bt_graph *bt_graph_create(void) if (!graph->sinks_to_consume) { goto error; } + + ret = init_listeners_array(&graph->listeners.port_added); + if (ret) { + goto error; + } + + ret = init_listeners_array(&graph->listeners.port_removed); + if (ret) { + goto error; + } + + ret = init_listeners_array(&graph->listeners.port_connected); + if (ret) { + goto error; + } + + ret = init_listeners_array(&graph->listeners.port_disconnected); + if (ret) { + goto error; + } + end: return graph; error: @@ -204,6 +265,14 @@ struct bt_connection *bt_graph_connect(struct bt_graph *graph, if (component_status != BT_COMPONENT_STATUS_OK) { goto error_rollback; } + + /* + * Both components accepted the connection. Notify the graph's + * creator that both ports are connected. + */ + bt_graph_notify_port_connected(graph, upstream_port); + bt_graph_notify_port_connected(graph, downstream_port); + end: bt_put(upstream_graph); bt_put(downstream_graph); @@ -558,3 +627,149 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph) error: return status; } + +static +void add_listener(GArray *listeners, void *func, void *data) +{ + struct bt_graph_listener listener = { + .func = func, + .data = data, + }; + + g_array_append_val(listeners, listener); +} + +enum bt_graph_status bt_graph_add_port_added_listener( + struct bt_graph *graph, + bt_graph_port_added_listener listener, void *data) +{ + enum bt_graph_status status = BT_GRAPH_STATUS_OK; + + if (!graph || !listener) { + status = BT_GRAPH_STATUS_INVALID; + goto end; + } + + add_listener(graph->listeners.port_added, listener, data); + +end: + return status; +} + +enum bt_graph_status bt_graph_add_port_removed_listener( + struct bt_graph *graph, + bt_graph_port_removed_listener listener, void *data) +{ + enum bt_graph_status status = BT_GRAPH_STATUS_OK; + + if (!graph || !listener) { + status = BT_GRAPH_STATUS_INVALID; + goto end; + } + + add_listener(graph->listeners.port_removed, listener, data); + +end: + return status; +} + +enum bt_graph_status bt_graph_add_port_connected_listener( + struct bt_graph *graph, + bt_graph_port_connected_listener listener, void *data) +{ + enum bt_graph_status status = BT_GRAPH_STATUS_OK; + + if (!graph || !listener) { + status = BT_GRAPH_STATUS_INVALID; + goto end; + } + + add_listener(graph->listeners.port_connected, listener, data); + +end: + return status; +} + +enum bt_graph_status bt_graph_add_port_disconnected_listener( + struct bt_graph *graph, + bt_graph_port_disconnected_listener listener, void *data) +{ + enum bt_graph_status status = BT_GRAPH_STATUS_OK; + + if (!graph || !listener) { + status = BT_GRAPH_STATUS_INVALID; + goto end; + } + + add_listener(graph->listeners.port_disconnected, listener, data); + +end: + return status; +} + +BT_HIDDEN +void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port) +{ + size_t i; + + for (i = 0; i < graph->listeners.port_added->len; i++) { + struct bt_graph_listener listener = + g_array_index(graph->listeners.port_added, + struct bt_graph_listener, i); + bt_graph_port_added_listener func = listener.func; + + assert(func); + func(port, listener.data); + } +} + +BT_HIDDEN +void bt_graph_notify_port_removed(struct bt_graph *graph, + struct bt_component *comp, struct bt_port *port) +{ + size_t i; + + for (i = 0; i < graph->listeners.port_removed->len; i++) { + struct bt_graph_listener listener = + g_array_index(graph->listeners.port_removed, + struct bt_graph_listener, i); + bt_graph_port_removed_listener func = listener.func; + + assert(func); + func(comp, port, listener.data); + } +} + +BT_HIDDEN +void bt_graph_notify_port_connected(struct bt_graph *graph, + struct bt_port *port) +{ + size_t i; + + for (i = 0; i < graph->listeners.port_connected->len; i++) { + struct bt_graph_listener listener = + g_array_index(graph->listeners.port_connected, + struct bt_graph_listener, i); + bt_graph_port_connected_listener func = listener.func; + + assert(func); + func(port, listener.data); + } +} + +BT_HIDDEN +void bt_graph_notify_port_disconnected(struct bt_graph *graph, + struct bt_component *comp, struct bt_port *port) +{ + size_t i; + + for (i = 0; i < graph->listeners.port_disconnected->len; i++) { + struct bt_graph_listener listener = + g_array_index(graph->listeners.port_disconnected, + struct bt_graph_listener, i); + bt_graph_port_disconnected_listener func = listener.func; + + assert(func); + func(comp, port, listener.data); + } +} -- 2.34.1