From eb87cce75225fabacbfe5f6f9b7741f580e75bc0 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 21 Jul 2017 16:34:29 -0400 Subject: [PATCH] Graph: pass remove listeners when adding listeners MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit With this patch, when you call bt_graph_add_*_listener(), you can also provide a "remove listener" which is called when the added listener is removed when the graph object is destroyed. This is useful when you dynamically allocate data only for the listener to add and you are not the only owner of the graph object: the remove listener is where to free/release this data. Existing CLIs and tests are modified to match this change. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- cli/babeltrace.c | 8 +- include/babeltrace/graph/graph-internal.h | 1 + include/babeltrace/graph/graph.h | 13 ++- lib/graph/graph.c | 111 +++++++++++++++++----- tests/lib/test_graph_topo.c | 11 ++- tests/plugins/test-utils-muxer.c | 4 +- 6 files changed, 107 insertions(+), 41 deletions(-) diff --git a/cli/babeltrace.c b/cli/babeltrace.c index 6920aabc..215092fd 100644 --- a/cli/babeltrace.c +++ b/cli/babeltrace.c @@ -1840,28 +1840,28 @@ int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg) the_graph = ctx->graph; ret = bt_graph_add_port_added_listener(ctx->graph, - graph_port_added_listener, ctx); + graph_port_added_listener, NULL, ctx); if (ret < 0) { BT_LOGE_STR("Cannot add \"port added\" listener to graph."); goto error; } ret = bt_graph_add_port_removed_listener(ctx->graph, - graph_port_removed_listener, ctx); + graph_port_removed_listener, NULL, ctx); if (ret < 0) { BT_LOGE_STR("Cannot add \"port removed\" listener to graph."); goto error; } ret = bt_graph_add_ports_connected_listener(ctx->graph, - graph_ports_connected_listener, ctx); + graph_ports_connected_listener, NULL, ctx); if (ret < 0) { BT_LOGE_STR("Cannot add \"ports connected\" listener to graph."); goto error; } ret = bt_graph_add_ports_disconnected_listener(ctx->graph, - graph_ports_disconnected_listener, ctx); + graph_ports_disconnected_listener, NULL, ctx); if (ret < 0) { BT_LOGE_STR("Cannot add \"ports disconnected\" listener to graph."); goto error; diff --git a/include/babeltrace/graph/graph-internal.h b/include/babeltrace/graph/graph-internal.h index d4186425..1e8b1b79 100644 --- a/include/babeltrace/graph/graph-internal.h +++ b/include/babeltrace/graph/graph-internal.h @@ -58,6 +58,7 @@ struct bt_graph { GQueue *sinks_to_consume; bt_bool canceled; + bt_bool in_remove_listener; struct { GArray *port_added; diff --git a/include/babeltrace/graph/graph.h b/include/babeltrace/graph/graph.h index a5077c49..f790e449 100644 --- a/include/babeltrace/graph/graph.h +++ b/include/babeltrace/graph/graph.h @@ -66,6 +66,7 @@ typedef void (*bt_graph_ports_disconnected_listener)( struct bt_component *downstream_component, struct bt_port *upstream_port, struct bt_port *downstream_port, void *data); +typedef void (* bt_graph_listener_removed)(void *data); extern struct bt_graph *bt_graph_create(void); @@ -106,16 +107,20 @@ 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 int bt_graph_add_port_added_listener(struct bt_graph *graph, - bt_graph_port_added_listener listener, void *data); + bt_graph_port_added_listener listener, + bt_graph_listener_removed listener_removed, void *data); extern int bt_graph_add_port_removed_listener(struct bt_graph *graph, - bt_graph_port_removed_listener listener, void *data); + bt_graph_port_removed_listener listener, + bt_graph_listener_removed listener_removed, void *data); extern int bt_graph_add_ports_connected_listener(struct bt_graph *graph, - bt_graph_ports_connected_listener listener, void *data); + bt_graph_ports_connected_listener listener, + bt_graph_listener_removed listener_removed, void *data); extern int bt_graph_add_ports_disconnected_listener(struct bt_graph *graph, - bt_graph_ports_disconnected_listener listener, void *data); + bt_graph_ports_disconnected_listener listener, + bt_graph_listener_removed listener_removed, void *data); extern enum bt_graph_status bt_graph_cancel(struct bt_graph *graph); extern bt_bool bt_graph_is_canceled(struct bt_graph *graph); diff --git a/lib/graph/graph.c b/lib/graph/graph.c index e7f8db3f..747a2826 100644 --- a/lib/graph/graph.c +++ b/lib/graph/graph.c @@ -44,9 +44,42 @@ struct bt_graph_listener { void *func; + bt_graph_listener_removed removed; void *data; }; +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) { + BT_LOGE_STR("Failed to allocate one GArray."); + ret = -1; + goto end; + } + +end: + return ret; +} + +static +void call_remove_listeners(GArray *listeners) +{ + size_t i; + + for (i = 0; i < listeners->len; i++) { + struct bt_graph_listener listener = + g_array_index(listeners, struct bt_graph_listener, i); + + if (listener.removed) { + listener.removed(listener.data); + } + } +} + static void bt_graph_destroy(struct bt_object *obj) { @@ -88,6 +121,12 @@ void bt_graph_destroy(struct bt_object *obj) */ (void) bt_graph_cancel(graph); + /* Call all remove listeners */ + call_remove_listeners(graph->listeners.port_added); + call_remove_listeners(graph->listeners.port_removed); + call_remove_listeners(graph->listeners.ports_connected); + call_remove_listeners(graph->listeners.ports_disconnected); + if (graph->connections) { BT_LOGD_STR("Destroying connections."); g_ptr_array_free(graph->connections, TRUE); @@ -119,23 +158,6 @@ void bt_graph_destroy(struct bt_object *obj) 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) { - BT_LOGE_STR("Failed to allocate one GArray."); - ret = -1; - goto end; - } - -end: - return ret; -} - struct bt_graph *bt_graph_create(void) { struct bt_graph *graph; @@ -530,10 +552,11 @@ end: } static -int add_listener(GArray *listeners, void *func, void *data) +int add_listener(GArray *listeners, void *func, void *removed, void *data) { struct bt_graph_listener listener = { .func = func, + .removed = removed, .data = data, }; @@ -543,7 +566,8 @@ int add_listener(GArray *listeners, void *func, void *data) int bt_graph_add_port_added_listener( struct bt_graph *graph, - bt_graph_port_added_listener listener, void *data) + bt_graph_port_added_listener listener, + bt_graph_listener_removed listener_removed, void *data) { int ret; @@ -553,13 +577,21 @@ int bt_graph_add_port_added_listener( goto end; } + if (graph->in_remove_listener) { + BT_LOGW("Cannot call this function during the execution of a remove listener: " + "addr=%p", graph); + ret = -1; + goto end; + } + if (!listener) { BT_LOGW_STR("Invalid parameter: listener is NULL."); ret = -1; goto end; } - ret = add_listener(graph->listeners.port_added, listener, data); + ret = add_listener(graph->listeners.port_added, listener, + listener_removed, data); BT_LOGV("Added \"port added\" listener to graph: " "graph-addr=%p, listener-addr=%p, pos=%d", graph, listener, ret); @@ -570,7 +602,8 @@ end: int bt_graph_add_port_removed_listener( struct bt_graph *graph, - bt_graph_port_removed_listener listener, void *data) + bt_graph_port_removed_listener listener, + bt_graph_listener_removed listener_removed, void *data) { int ret; @@ -580,13 +613,21 @@ int bt_graph_add_port_removed_listener( goto end; } + if (graph->in_remove_listener) { + BT_LOGW("Cannot call this function during the execution of a remove listener: " + "addr=%p", graph); + ret = -1; + goto end; + } + if (!listener) { BT_LOGW_STR("Invalid parameter: listener is NULL."); ret = -1; goto end; } - ret = add_listener(graph->listeners.port_removed, listener, data); + ret = add_listener(graph->listeners.port_removed, listener, + listener_removed, data); BT_LOGV("Added \"port removed\" listener to graph: " "graph-addr=%p, listener-addr=%p, pos=%d", graph, listener, ret); @@ -597,7 +638,8 @@ end: int bt_graph_add_ports_connected_listener( struct bt_graph *graph, - bt_graph_ports_connected_listener listener, void *data) + bt_graph_ports_connected_listener listener, + bt_graph_listener_removed listener_removed, void *data) { int ret; @@ -607,13 +649,21 @@ int bt_graph_add_ports_connected_listener( goto end; } + if (graph->in_remove_listener) { + BT_LOGW("Cannot call this function during the execution of a remove listener: " + "addr=%p", graph); + ret = -1; + goto end; + } + if (!listener) { BT_LOGW_STR("Invalid parameter: listener is NULL."); ret = -1; goto end; } - ret = add_listener(graph->listeners.ports_connected, listener, data); + ret = add_listener(graph->listeners.ports_connected, listener, + listener_removed, data); BT_LOGV("Added \"port connected\" listener to graph: " "graph-addr=%p, listener-addr=%p, pos=%d", graph, listener, ret); @@ -624,7 +674,8 @@ end: int bt_graph_add_ports_disconnected_listener( struct bt_graph *graph, - bt_graph_ports_disconnected_listener listener, void *data) + bt_graph_ports_disconnected_listener listener, + bt_graph_listener_removed listener_removed, void *data) { int ret; @@ -634,13 +685,21 @@ int bt_graph_add_ports_disconnected_listener( goto end; } + if (graph->in_remove_listener) { + BT_LOGW("Cannot call this function during the execution of a remove listener: " + "addr=%p", graph); + ret = -1; + goto end; + } + if (!listener) { BT_LOGW_STR("Invalid parameter: listener is NULL."); ret = -1; goto end; } - ret = add_listener(graph->listeners.ports_disconnected, listener, data); + ret = add_listener(graph->listeners.ports_disconnected, listener, + listener_removed, data); BT_LOGV("Added \"port disconnected\" listener to graph: " "graph-addr=%p, listener-addr=%p, pos=%d", graph, listener, ret); diff --git a/tests/lib/test_graph_topo.c b/tests/lib/test_graph_topo.c index 038ce3eb..4066587e 100644 --- a/tests/lib/test_graph_topo.c +++ b/tests/lib/test_graph_topo.c @@ -618,16 +618,17 @@ struct bt_graph *create_graph(void) int ret; assert(graph); - ret = bt_graph_add_port_added_listener(graph, graph_port_added, NULL); + ret = bt_graph_add_port_added_listener(graph, graph_port_added, NULL, + NULL); assert(ret >= 0); ret = bt_graph_add_port_removed_listener(graph, graph_port_removed, - NULL); + NULL, NULL); assert(ret >= 0); - ret = bt_graph_add_ports_connected_listener(graph, graph_ports_connected, - NULL); + ret = bt_graph_add_ports_connected_listener(graph, + graph_ports_connected, NULL, NULL); assert(ret >= 0); ret = bt_graph_add_ports_disconnected_listener(graph, - graph_ports_disconnected, NULL); + graph_ports_disconnected, NULL, NULL); assert(ret >= 0); return graph; } diff --git a/tests/plugins/test-utils-muxer.c b/tests/plugins/test-utils-muxer.c index df507074..85ed44a9 100644 --- a/tests/plugins/test-utils-muxer.c +++ b/tests/plugins/test-utils-muxer.c @@ -1464,7 +1464,7 @@ void test_single_end_then_multiple_full(void) graph_listener_data.muxer = muxer_comp; graph_listener_data.sink = sink_comp; ret = bt_graph_add_port_added_listener(graph, - graph_port_added_listener_connect_to_avail_muxer_port, + graph_port_added_listener_connect_to_avail_muxer_port, NULL, &graph_listener_data); assert(ret >= 0); @@ -1592,7 +1592,7 @@ void test_single_again_end_then_multiple_full(void) graph_listener_data.muxer = muxer_comp; graph_listener_data.sink = sink_comp; ret = bt_graph_add_port_added_listener(graph, - graph_port_added_listener_connect_to_avail_muxer_port, + graph_port_added_listener_connect_to_avail_muxer_port, NULL, &graph_listener_data); assert(ret >= 0); -- 2.34.1