lib: graph: disallow recursive consuming
[babeltrace.git] / lib / graph / graph.c
index e7f8db3f3e76f3b5c3e0f9b18a724a06ba6b00cd..b6460f74e228bd684c6ad9f59b8fa139f440475a 100644 (file)
 
 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;
@@ -166,6 +188,7 @@ struct bt_graph *bt_graph_create(void)
                goto error;
        }
 
+       graph->can_consume = BT_TRUE;
        ret = init_listeners_array(&graph->listeners.port_added);
        if (ret) {
                BT_LOGE_STR("Cannot create the \"port added\" listener array.");
@@ -210,6 +233,7 @@ enum bt_graph_status bt_graph_connect_ports(struct bt_graph *graph,
        struct bt_component *upstream_component = NULL;
        struct bt_component *downstream_component = NULL;
        enum bt_component_status component_status;
+       const bt_bool init_can_consume = graph->can_consume;
 
        if (!graph) {
                BT_LOGW_STR("Invalid parameter: graph is NULL.");
@@ -242,6 +266,8 @@ enum bt_graph_status bt_graph_connect_ports(struct bt_graph *graph,
                goto end;
        }
 
+       graph->can_consume = BT_FALSE;
+
        /* Ensure appropriate types for upstream and downstream ports. */
        if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) {
                BT_LOGW_STR("Invalid parameter: upstream port is not an output port.");
@@ -384,6 +410,7 @@ end:
        bt_put(upstream_component);
        bt_put(downstream_component);
        bt_put(connection);
+       graph->can_consume = init_can_consume;
        return status;
 }
 
@@ -397,6 +424,12 @@ enum bt_graph_status bt_graph_consume_no_check(struct bt_graph *graph)
 
        BT_LOGV("Making next sink consume: addr=%p", graph);
 
+       if (!graph->has_sink) {
+               BT_LOGW_STR("Graph has no sink component.");
+               status = BT_GRAPH_STATUS_NO_SINK;
+               goto end;
+       }
+
        if (g_queue_is_empty(graph->sinks_to_consume)) {
                BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
                status = BT_GRAPH_STATUS_END;
@@ -462,7 +495,15 @@ enum bt_graph_status bt_graph_consume(struct bt_graph *graph)
                goto end;
        }
 
+       if (!graph->can_consume) {
+               BT_LOGW_STR("Cannot consume graph in its current state.");
+               status = BT_GRAPH_STATUS_CANNOT_CONSUME;
+               goto end;
+       }
+
+       graph->can_consume = BT_FALSE;
        status = bt_graph_consume_no_check(graph);
+       graph->can_consume = BT_TRUE;
 
 end:
        return status;
@@ -485,6 +526,13 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph)
                goto end;
        }
 
+       if (!graph->can_consume) {
+               BT_LOGW_STR("Cannot run graph in its current state.");
+               status = BT_GRAPH_STATUS_CANNOT_CONSUME;
+               goto end;
+       }
+
+       graph->can_consume = BT_FALSE;
        BT_LOGV("Running graph: addr=%p", graph);
 
        do {
@@ -501,7 +549,7 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph)
                        goto end;
                }
 
-               status = bt_graph_consume(graph);
+               status = bt_graph_consume_no_check(graph);
                if (status == BT_GRAPH_STATUS_AGAIN) {
                        /*
                         * If AGAIN is received and there are multiple
@@ -517,6 +565,8 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph)
                        if (graph->sinks_to_consume->length > 1) {
                                status = BT_GRAPH_STATUS_OK;
                        }
+               } else if (status == BT_GRAPH_STATUS_NO_SINK) {
+                       goto end;
                }
        } while (status == BT_GRAPH_STATUS_OK);
 
@@ -526,14 +576,16 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph)
 
 end:
        BT_LOGV("Graph ran: status=%s", bt_graph_status_string(status));
+       graph->can_consume = BT_TRUE;
        return status;
 }
 
 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 +595,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 +606,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 +631,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 +642,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 +667,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 +678,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 +703,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 +714,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);
@@ -741,7 +829,7 @@ void bt_graph_notify_ports_disconnected(struct bt_graph *graph,
        }
 }
 
-extern enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
+enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
 {
        enum bt_graph_status ret = BT_GRAPH_STATUS_OK;
 
@@ -758,9 +846,19 @@ end:
        return ret;
 }
 
-extern bt_bool bt_graph_is_canceled(struct bt_graph *graph)
+bt_bool bt_graph_is_canceled(struct bt_graph *graph)
 {
-       return graph ? graph->canceled : BT_FALSE;
+       bt_bool canceled = BT_FALSE;
+
+       if (!graph) {
+               BT_LOGW_STR("Invalid parameter: graph is NULL.");
+               goto end;
+       }
+
+       canceled = graph->canceled;
+
+end:
+       return canceled;
 }
 
 BT_HIDDEN
@@ -786,6 +884,7 @@ enum bt_graph_status bt_graph_add_component_with_init_method_data(
        struct bt_component *component = NULL;
        enum bt_component_class_type type;
        size_t i;
+       const bt_bool init_can_consume = graph->can_consume;
 
        bt_get(params);
 
@@ -801,6 +900,7 @@ enum bt_graph_status bt_graph_add_component_with_init_method_data(
                goto end;
        }
 
+       graph->can_consume = BT_FALSE;
        type = bt_component_class_get_type(component_class);
        BT_LOGD("Adding component to graph: "
                "graph-addr=%p, comp-cls-addr=%p, "
@@ -908,6 +1008,7 @@ enum bt_graph_status bt_graph_add_component_with_init_method_data(
         * sink queue to be consumed by bt_graph_consume().
         */
        if (bt_component_is_sink(component)) {
+               graph->has_sink = BT_TRUE;
                g_queue_push_tail(graph->sinks_to_consume, component);
        }
 
@@ -933,6 +1034,7 @@ enum bt_graph_status bt_graph_add_component_with_init_method_data(
 end:
        bt_put(component);
        bt_put(params);
+       graph->can_consume = init_can_consume;
        return graph_status;
 }
 
This page took 0.028279 seconds and 4 git commands to generate.