From 202a3a1362bcff05d6e53afafe3d487c71b362d8 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 11 May 2017 17:54:10 -0400 Subject: [PATCH] Add graph cancellation API MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit With this API you can cancel a graph with bt_graph_cancel() and check if a graph is canceled with bt_graph_is_canceled(). A canceled graph is used to indicate to a contained component or notification iterator if it should retry or not when a system call is interrupted. This exists mostly to support a clean termination when we get SIGINT, but with debugger support (a system call is interrupted when the debugger sends SIGCONT; in this case we need to retry the system call). Cancelling a graph also makes bt_graph_run() quit before the next sink consuming iteration. It is not allowed to run a canceled graph again. Once it is canceled, it's dead for good. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- include/babeltrace/graph/graph-internal.h | 2 + include/babeltrace/graph/graph.h | 6 +++ lib/graph/graph.c | 58 +++++++++++++++++++---- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/include/babeltrace/graph/graph-internal.h b/include/babeltrace/graph/graph-internal.h index 85c196be..9efd3590 100644 --- a/include/babeltrace/graph/graph-internal.h +++ b/include/babeltrace/graph/graph-internal.h @@ -55,6 +55,8 @@ struct bt_graph { /* Queue of pointers (weak references) to sink bt_components. */ GQueue *sinks_to_consume; + bt_bool canceled; + struct { GArray *port_added; GArray *port_removed; diff --git a/include/babeltrace/graph/graph.h b/include/babeltrace/graph/graph.h index cb14c7da..b89aaa82 100644 --- a/include/babeltrace/graph/graph.h +++ b/include/babeltrace/graph/graph.h @@ -28,6 +28,7 @@ */ #include +#include #ifdef __cplusplus extern "C" { @@ -50,6 +51,8 @@ enum bt_graph_status { BT_GRAPH_STATUS_NO_SINK = -6, /** General error. */ BT_GRAPH_STATUS_ERROR = -1, + /** Canceled. */ + BT_GRAPH_STATUS_CANCELED = -125, }; typedef void (*bt_graph_port_added_listener)(struct bt_port *port, @@ -114,6 +117,9 @@ extern enum bt_graph_status bt_graph_add_ports_disconnected_listener( struct bt_graph *graph, bt_graph_ports_disconnected_listener listener, 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); + #ifdef __cplusplus } #endif diff --git a/lib/graph/graph.c b/lib/graph/graph.c index 8e4dbf68..90eb92fc 100644 --- a/lib/graph/graph.c +++ b/lib/graph/graph.c @@ -163,6 +163,10 @@ struct bt_connection *bt_graph_connect_ports(struct bt_graph *graph, goto end; } + if (graph->canceled) { + goto end; + } + /* Ensure appropriate types for upstream and downstream ports. */ if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) { goto end; @@ -357,6 +361,11 @@ enum bt_graph_status bt_graph_add_component_as_sibling(struct bt_graph *graph, goto end; } + if (graph->canceled) { + status = BT_GRAPH_STATUS_CANCELED; + goto end; + } + if (bt_component_get_class_type(origin) != bt_component_get_class_type(new_component)) { status = BT_GRAPH_STATUS_INVALID; @@ -494,6 +503,11 @@ enum bt_graph_status bt_graph_consume(struct bt_graph *graph) goto end; } + if (graph->canceled) { + status = BT_GRAPH_STATUS_CANCELED; + goto end; + } + if (g_queue_is_empty(graph->sinks_to_consume)) { status = BT_GRAPH_STATUS_END; goto end; @@ -542,21 +556,27 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph) if (!graph) { status = BT_GRAPH_STATUS_INVALID; - goto error; + goto end; } do { + if (graph->canceled) { + status = BT_GRAPH_STATUS_CANCELED; + goto end; + } + status = bt_graph_consume(graph); if (status == BT_GRAPH_STATUS_AGAIN) { /* - * If AGAIN is received and there are multiple sinks, - * go ahead and consume from the next sink. + * If AGAIN is received and there are multiple + * sinks, go ahead and consume from the next + * sink. * - * However, in the case where a single sink is left, - * the caller can decide to busy-wait and call - * bt_graph_run continuously until the source is ready - * or it can decide to sleep for an arbitrary amount of - * time. + * However, in the case where a single sink is + * left, the caller can decide to busy-wait and + * call bt_graph_run() continuously until the + * source is ready or it can decide to sleep for + * an arbitrary amount of time. */ if (graph->sinks_to_consume->length > 1) { status = BT_GRAPH_STATUS_OK; @@ -567,7 +587,7 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph) if (g_queue_is_empty(graph->sinks_to_consume)) { status = BT_GRAPH_STATUS_END; } -error: +end: return status; } @@ -719,3 +739,23 @@ void bt_graph_notify_ports_disconnected(struct bt_graph *graph, downstream_port, listener.data); } } + +extern enum bt_graph_status bt_graph_cancel(struct bt_graph *graph) +{ + enum bt_graph_status ret = BT_GRAPH_STATUS_OK; + + if (!graph) { + ret = BT_GRAPH_STATUS_INVALID; + goto end; + } + + graph->canceled = BT_TRUE; + +end: + return ret; +} + +extern bt_bool bt_graph_is_canceled(struct bt_graph *graph) +{ + return graph ? graph->canceled : BT_FALSE; +} -- 2.34.1