Add bt_graph_add_component(), make bt_component_create() internal
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 8 Jun 2017 02:25:48 +0000 (22:25 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 9 Jun 2017 21:03:27 +0000 (17:03 -0400)
With this patch, you can only instantiate a component class through an
existing graph. This can guarantee to the user (component class
developer) that, when the component class's initialization method is
called, the component always belongs to a graph. This simplifies things,
now and in the future. For example, it is possible to cancel the graph
during the execution of bt_graph_add_component() so that the user method
knows if it should retry now or return an error when the graph is
canceled.

bt_graph_add_component() returns BT_GRAPH_STATUS_CANCELED if the graph
is canceled. If the user's initialization method fails, its return
component status is converted to the appropriate graph status.

Another advantage of adding a component to a graph is that, if you add a
"port added" graph listener, it is guaranteed that the listener is
called even for the initial ports of a component. This was not possible
before.

This patch also makes a component's name mandatory, and
bt_graph_add_component() ensures that there are components sharing the
same name part of a given graph. This is a constraint similar to the
fact that all the ports of a component must have a unique name. It
should help to the implementation of a function to retrieve a component
by name from a graph in the future.

We do not check that a graph has or not "loose", disconnected components
in bt_graph_consume(). This is not a change because any component can
remove all its ports once connected once and become loose. A graph with
floating/loose components is said to be disconnected in classical graph
theory. This is not a problem for the moment, as the connected
components can still interact. The disconnected components should
probably be marked and then destroyed in bt_graph_consume() and/or in a
dedicated garbage collecting function if needed
(bt_graph_remove_disconnected_components() for example).

This patch also makes successfully user-initialized components marked as
such so that the user's finalization method is not called if its
initialization method failed. In other words, the initialization method
is responsible for any cleanup if it's about to fail.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
18 files changed:
cli/babeltrace.c
include/babeltrace/graph/component-filter-internal.h
include/babeltrace/graph/component-internal.h
include/babeltrace/graph/component-sink-internal.h
include/babeltrace/graph/component-source-internal.h
include/babeltrace/graph/component.h
include/babeltrace/graph/graph-internal.h
include/babeltrace/graph/graph.h
include/babeltrace/object-internal.h
lib/graph/component.c
lib/graph/filter.c
lib/graph/graph.c
lib/graph/sink.c
lib/graph/source.c
tests/lib/test_bt_notification_iterator.c
tests/lib/test_graph_topo.c
tests/lib/test_plugin.c
tests/plugins/test-utils-muxer.c

index b68ddf1531c51fd8e965cc4bdca2a3f1c7593090..4e35b8b6dd057024f8e53d96244c6479e0ccb05a 100644 (file)
@@ -1418,6 +1418,11 @@ void graph_port_added_listener(struct bt_port *port, void *data)
                "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
                comp, comp ? bt_component_get_name(comp) : "",
                port, bt_port_get_name(port));
+
+       if (!ctx->connect_ports) {
+               goto end;
+       }
+
        if (!comp) {
                BT_LOGW_STR("Port has no component.");
                goto end;
@@ -1598,9 +1603,9 @@ int cmd_run_ctx_create_components_from_config_components(
                        goto error;
                }
 
-               comp = bt_component_create(comp_cls,
-                       cfg_comp->instance_name->str, cfg_comp->params);
-               if (!comp) {
+               ret = bt_graph_add_component(ctx->graph, comp_cls,
+                       cfg_comp->instance_name->str, cfg_comp->params, &comp);
+               if (ret) {
                        BT_LOGE("Cannot create component: plugin-name=\"%s\", "
                                "comp-cls-name=\"%s\", comp-cls-type=%d, "
                                "comp-name=\"%s\"",
@@ -1744,8 +1749,6 @@ const char *bt_graph_status_str(enum bt_graph_status status)
                return "BT_GRAPH_STATUS_END";
        case BT_GRAPH_STATUS_OK:
                return "BT_GRAPH_STATUS_OK";
-       case BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH:
-               return "BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH";
        case BT_GRAPH_STATUS_INVALID:
                return "BT_GRAPH_STATUS_INVALID";
        case BT_GRAPH_STATUS_NO_SINK:
index 3bf79a187cc55b67bb8669c7b60136f50f2aa886..38a1a240acc9f8942bc004580f9d1521d5b74412 100644 (file)
@@ -46,7 +46,7 @@ struct bt_component_filter {
  */
 BT_HIDDEN
 struct bt_component *bt_component_filter_create(
-               struct bt_component_class *class, struct bt_value *params);
+               struct bt_component_class *class);
 
 BT_HIDDEN
 void bt_component_filter_destroy(struct bt_component *component);
index f78c468b079ff69d3e5aea0522449e8565ffca42..35a353a1ba7be28abc8974c05535e801a9a3a11a 100644 (file)
@@ -64,6 +64,8 @@ struct bt_component {
 
        /* Array of struct bt_component_destroy_listener */
        GArray *destroy_listeners;
+
+       bool initialized;
 };
 
 static inline
@@ -87,6 +89,11 @@ struct bt_graph *bt_component_borrow_graph(struct bt_component *comp)
        return (void *) comp->base.parent;
 }
 
+BT_HIDDEN
+enum bt_component_status bt_component_create(
+               struct bt_component_class *component_class,
+               const char *name, struct bt_component **component);
+
 BT_HIDDEN
 enum bt_component_status bt_component_accept_port_connection(
                struct bt_component *component, struct bt_port *self_port,
index cffb9a9648b23830e11e1c6da3ad24708ab8239f..c1e7a4548eac51fe9817d890d3e6b94c8cbfb95b 100644 (file)
@@ -49,7 +49,7 @@ struct bt_component_sink {
  */
 BT_HIDDEN
 struct bt_component *bt_component_sink_create(
-               struct bt_component_class *class, struct bt_value *params);
+               struct bt_component_class *class);
 
 BT_HIDDEN
 void bt_component_sink_destroy(struct bt_component *component);
index fde158453504edf7ad225a0a59e4f82b7a562386..98b523ce236775223add08775d702b43cc9e220e 100644 (file)
@@ -46,7 +46,7 @@ struct bt_component_source {
  */
 BT_HIDDEN
 struct bt_component *bt_component_source_create(
-               struct bt_component_class *class, struct bt_value *params);
+               struct bt_component_class *class);
 
 BT_HIDDEN
 void bt_component_source_destroy(struct bt_component *component);
index 31fde560a59edb9fe0d83595e3f778b123ec8c18..e9ee509360c979336c1e5a6f22582cd313639529 100644 (file)
@@ -43,22 +43,6 @@ struct bt_component;
 struct bt_value;
 struct bt_port;
 
-/**
- * Create an instance of a component from a component class.
- *
- * @param component_class      Component class of which to create an instance
- * @param name                 Name of the new component instance, optional
- * @param params               A dictionary of component parameters
- * @returns                    Returns a pointer to a new component instance
- */
-extern struct bt_component *bt_component_create(
-               struct bt_component_class *component_class, const char *name,
-               struct bt_value *params);
-
-extern struct bt_component *bt_component_create_with_init_method_data(
-               struct bt_component_class *component_class, const char *name,
-               struct bt_value *params, void *init_method_data);
-
 /**
  * Get component's name.
  *
index f8f0d1a17475f27cb7a783567eaa43134d2e9981..d418642595c0bbf7dbd847a81d316d118d29394b 100644 (file)
@@ -101,8 +101,6 @@ const char *bt_graph_status_string(enum bt_graph_status status)
                return "BT_GRAPH_STATUS_END";
        case BT_GRAPH_STATUS_OK:
                return "BT_GRAPH_STATUS_OK";
-       case BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH:
-               return "BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH";
        case BT_GRAPH_STATUS_INVALID:
                return "BT_GRAPH_STATUS_INVALID";
        case BT_GRAPH_STATUS_NO_SINK:
index a2dfbd8235f85e63d64e3a48fd6e2c6fd8fe7130..a5077c4901991bcc9e343f6aaf4f3a048d375fb3 100644 (file)
@@ -46,8 +46,6 @@ enum bt_graph_status {
        /** Downstream component does not support multiple inputs. */
        BT_GRAPH_STATUS_END = 1,
        BT_GRAPH_STATUS_OK = 0,
-       /** Component is already part of another graph. */
-       BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH = -2,
        /** Invalid arguments. */
        BT_GRAPH_STATUS_INVALID = -22,
        /** No sink in graph. */
@@ -71,6 +69,19 @@ typedef void (*bt_graph_ports_disconnected_listener)(
 
 extern struct bt_graph *bt_graph_create(void);
 
+extern enum bt_graph_status bt_graph_add_component(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               struct bt_component **component);
+
+extern enum bt_graph_status bt_graph_add_component_with_init_method_data(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               void *init_method_data,
+               struct bt_component **component);
+
 /**
  * Creates a connection between two components using the two ports specified
  * and adds the connection and components (if not already added) to the graph.
index 2b368c5510e46f86ea26758b44e8c939a0346ae6..9859e329d36a34565bb86daedb75762387d8cacb 100644 (file)
@@ -64,7 +64,7 @@ void bt_object_release(void *ptr)
                obj->ref_count.count);
 #endif
 
-       if (obj && obj->release && !bt_object_get_ref_count(obj)) {
+       if (obj && obj->release && bt_object_get_ref_count(obj) == 0) {
                obj->release(obj);
        }
 }
index 8664e3b423fb4a19ef2f70dc73adf2731ee422e6..ee8e94530063faea67dafd99772b995bf155e89a 100644 (file)
@@ -52,7 +52,7 @@
 
 static
 struct bt_component * (* const component_create_funcs[])(
-               struct bt_component_class *, struct bt_value *) = {
+               struct bt_component_class *) = {
        [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
        [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
        [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
@@ -105,10 +105,11 @@ void bt_component_destroy(struct bt_object *obj)
        component_class = component->class;
 
        /*
-        * User data is destroyed first, followed by the concrete component
-        * instance.
+        * User data is destroyed first, followed by the concrete
+        * component instance. Do not finalize if the component's user
+        * initialization method failed in the first place.
         */
-       if (component->class->methods.finalize) {
+       if (component->initialized && component->class->methods.finalize) {
                BT_LOGD_STR("Calling user's finalization method.");
                component->class->methods.finalize(
                        bt_private_component_from_component(component));
@@ -240,57 +241,26 @@ int64_t bt_component_get_output_port_count(struct bt_component *comp)
        return (int64_t) comp->output_ports->len;
 }
 
-struct bt_component *bt_component_create_with_init_method_data(
-               struct bt_component_class *component_class, const char *name,
-               struct bt_value *params, void *init_method_data)
+enum bt_component_status bt_component_create(
+               struct bt_component_class *component_class,
+               const char *name, struct bt_component **user_component)
 {
-       int ret;
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
        struct bt_component *component = NULL;
        enum bt_component_class_type type;
 
-       bt_get(params);
-
-       if (!component_class) {
-               BT_LOGW_STR("Invalid parameter: component class is NULL.");
-               goto end;
-       }
+       assert(user_component);
+       assert(component_class);
+       assert(name);
 
        type = bt_component_class_get_type(component_class);
-       if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
-                       type > BT_COMPONENT_CLASS_TYPE_FILTER) {
-               BT_LOGW("Invalid parameter: unknown component class type: "
-                       "type=%s", bt_component_class_type_string(type));
-               goto end;
-       }
-
-       BT_LOGD("Creating component from component class: "
-               "comp-cls-addr=%p, comp-cls-type=%s, name=\"%s\", "
-               "params-addr=%p, init-method-data-addr=%p",
-               component_class, bt_component_class_type_string(type),
-               name, params, init_method_data);
-
-       /*
-        * Parameters must be a map value, but we create a convenient
-        * empty one if it's NULL.
-        */
-       if (params) {
-               if (!bt_value_is_map(params)) {
-                       BT_LOGW("Invalid parameter: initialization parameters must be a map value: "
-                               "type=%s",
-                               bt_value_type_string(bt_value_get_type(params)));
-                       goto end;
-               }
-       } else {
-               params = bt_value_map_create();
-               if (!params) {
-                       BT_LOGE_STR("Cannot create map value object.");
-                       goto end;
-               }
-       }
-
-       component = component_create_funcs[type](component_class, params);
+       BT_LOGD("Creating empty component from component class: "
+               "comp-cls-addr=%p, comp-cls-type=%s, name=\"%s\"",
+               component_class, bt_component_class_type_string(type), name);
+       component = component_create_funcs[type](component_class);
        if (!component) {
                BT_LOGE_STR("Cannot create specific component object.");
+               status = BT_COMPONENT_STATUS_NOMEM;
                goto end;
        }
 
@@ -300,7 +270,7 @@ struct bt_component *bt_component_create_with_init_method_data(
        component->name = g_string_new(name);
        if (!component->name) {
                BT_LOGE_STR("Failed to allocate one GString.");
-               BT_PUT(component);
+               status = BT_COMPONENT_STATUS_NOMEM;
                goto end;
        }
 
@@ -308,7 +278,7 @@ struct bt_component *bt_component_create_with_init_method_data(
                bt_object_release);
        if (!component->input_ports) {
                BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               BT_PUT(component);
+               status = BT_COMPONENT_STATUS_NOMEM;
                goto end;
        }
 
@@ -316,7 +286,7 @@ struct bt_component *bt_component_create_with_init_method_data(
                bt_object_release);
        if (!component->output_ports) {
                BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               BT_PUT(component);
+               status = BT_COMPONENT_STATUS_NOMEM;
                goto end;
        }
 
@@ -324,44 +294,19 @@ struct bt_component *bt_component_create_with_init_method_data(
                sizeof(struct bt_component_destroy_listener));
        if (!component->destroy_listeners) {
                BT_LOGE_STR("Failed to allocate one GArray.");
-               BT_PUT(component);
+               status = BT_COMPONENT_STATUS_NOMEM;
                goto end;
        }
 
-       if (component_class->methods.init) {
-               BT_LOGD_STR("Calling user's initialization method.");
-               ret = component_class->methods.init(
-                       bt_private_component_from_component(component), params,
-                       init_method_data);
-               BT_LOGD("User method returned: status=%s",
-                       bt_component_status_string(ret));
-               if (ret != BT_COMPONENT_STATUS_OK) {
-                       BT_LOGW_STR("Initialization method failed.");
-                       BT_PUT(component);
-                       goto end;
-               }
-       }
-
-       BT_LOGD_STR("Freezing component class.");
-       bt_component_class_freeze(component->class);
-       BT_LOGD("Created component from component class: "
-               "comp-cls-addr=%p, comp-cls-type=%s, name=\"%s\", "
-               "params-addr=%p, init-method-data-addr=%p, comp-addr=%p",
-               component_class, bt_component_class_type_string(type),
-               name, params, init_method_data, component);
+       BT_LOGD("Created empty component from component class: "
+               "comp-cls-addr=%p, comp-cls-type=%s, name=\"%s\", comp-addr=%p",
+               component_class, bt_component_class_type_string(type), name,
+               component);
+       BT_MOVE(*user_component, component);
 
 end:
-       bt_put(params);
-       return component;
-}
-
-struct bt_component *bt_component_create(
-               struct bt_component_class *component_class, const char *name,
-               struct bt_value *params)
-{
-       /* bt_component_create_with_init_method_data() logs details */
-       return bt_component_create_with_init_method_data(component_class, name,
-               params, NULL);
+       bt_put(component);
+       return status;
 }
 
 const char *bt_component_get_name(struct bt_component *component)
@@ -421,13 +366,7 @@ BT_HIDDEN
 void bt_component_set_graph(struct bt_component *component,
                struct bt_graph *graph)
 {
-       struct bt_object *parent = bt_object_get_parent(&component->base);
-
-       assert(!parent || parent == &graph->base);
-       if (!parent) {
-               bt_object_set_parent(component, &graph->base);
-       }
-       bt_put(parent);
+       bt_object_set_parent(component, graph ? &graph->base : NULL);
 }
 
 struct bt_graph *bt_component_get_graph(
index 78913517d2189bf69e5c1d372f7c073bf319876c..67beb4cd7c367a883efc3ab924f3c27fd8bf48ac 100644 (file)
@@ -45,7 +45,7 @@ void bt_component_filter_destroy(struct bt_component *component)
 
 BT_HIDDEN
 struct bt_component *bt_component_filter_create(
-               struct bt_component_class *class, struct bt_value *params)
+               struct bt_component_class *class)
 {
        struct bt_component_filter *filter = NULL;
 
index 5b5acae75054b481ef6ec1b44f05a95b2b100530..e7f8db3f3e76f3b5c3e0f9b18a724a06ba6b00cd 100644 (file)
@@ -37,6 +37,8 @@
 #include <babeltrace/graph/port.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/types.h>
+#include <babeltrace/values.h>
+#include <babeltrace/values-internal.h>
 #include <unistd.h>
 #include <glib.h>
 
@@ -208,8 +210,6 @@ 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;
-       bt_bool upstream_was_already_in_graph;
-       bt_bool downstream_was_already_in_graph;
 
        if (!graph) {
                BT_LOGW_STR("Invalid parameter: graph is NULL.");
@@ -291,24 +291,6 @@ enum bt_graph_status bt_graph_connect_ports(struct bt_graph *graph,
                upstream_component, bt_component_get_name(upstream_component),
                downstream_component, bt_component_get_name(downstream_component));
 
-       /* Ensure the components are not already part of another graph. */
-       upstream_graph = bt_component_get_graph(upstream_component);
-       if (upstream_graph && (graph != upstream_graph)) {
-               BT_LOGW("Invalid parameter: upstream port's component is already part of another graph: "
-                       "other-graph-addr=%p", upstream_graph);
-               status = BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH;
-               goto end;
-       }
-       upstream_was_already_in_graph = (graph == upstream_graph);
-       downstream_graph = bt_component_get_graph(downstream_component);
-       if (downstream_graph && (graph != downstream_graph)) {
-               BT_LOGW("Invalid parameter: downstream port's component is already part of another graph: "
-                       "other-graph-addr=%p", downstream_graph);
-               status = BT_GRAPH_STATUS_ALREADY_IN_A_GRAPH;
-               goto end;
-       }
-       downstream_was_already_in_graph = (graph == downstream_graph);
-
        /*
         * At this point the ports are not connected yet. Both
         * components need to accept an eventual connection to their
@@ -363,26 +345,6 @@ enum bt_graph_status bt_graph_connect_ports(struct bt_graph *graph,
         */
        g_ptr_array_add(graph->connections, connection);
 
-       if (!upstream_was_already_in_graph) {
-               g_ptr_array_add(graph->components, upstream_component);
-               bt_component_set_graph(upstream_component, graph);
-       }
-       if (!downstream_was_already_in_graph) {
-               g_ptr_array_add(graph->components, downstream_component);
-               bt_component_set_graph(downstream_component, graph);
-               if (bt_component_get_class_type(downstream_component) ==
-                               BT_COMPONENT_CLASS_TYPE_SINK) {
-                       g_queue_push_tail(graph->sinks_to_consume,
-                                       downstream_component);
-               }
-       }
-
-       /*
-        * The graph is now the parent of these components which
-        * garantees their existence for the duration of the graph's
-        * lifetime.
-        */
-
        /*
         * Notify both components that their port is connected.
         */
@@ -811,3 +773,175 @@ void bt_graph_remove_connection(struct bt_graph *graph,
                graph, connection);
        g_ptr_array_remove(graph->connections, connection);
 }
+
+enum bt_graph_status bt_graph_add_component_with_init_method_data(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               void *init_method_data,
+               struct bt_component **user_component)
+{
+       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
+       enum bt_component_status comp_status;
+       struct bt_component *component = NULL;
+       enum bt_component_class_type type;
+       size_t i;
+
+       bt_get(params);
+
+       if (!graph) {
+               BT_LOGW_STR("Invalid parameter: graph is NULL.");
+               graph_status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!component_class) {
+               BT_LOGW_STR("Invalid parameter: component class is NULL.");
+               graph_status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       type = bt_component_class_get_type(component_class);
+       BT_LOGD("Adding component to graph: "
+               "graph-addr=%p, comp-cls-addr=%p, "
+               "comp-cls-type=%s, name=\"%s\", params-addr=%p, "
+               "init-method-data-addr=%p",
+               graph, component_class, bt_component_class_type_string(type),
+               name, params, init_method_data);
+
+       if (!name) {
+               BT_LOGW_STR("Invalid parameter: name is NULL.");
+               graph_status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       if (graph->canceled) {
+               BT_LOGW_STR("Invalid parameter: graph is canceled.");
+               graph_status = BT_GRAPH_STATUS_CANCELED;
+               goto end;
+       }
+
+       if (type != BT_COMPONENT_CLASS_TYPE_SOURCE &&
+                       type != BT_COMPONENT_CLASS_TYPE_FILTER &&
+                       type != BT_COMPONENT_CLASS_TYPE_SINK) {
+               BT_LOGW("Invalid parameter: unknown component class type: "
+                       "type=%d", type);
+               graph_status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       for (i = 0; i < graph->components->len; i++) {
+               void *other_comp = graph->components->pdata[i];
+
+               if (strcmp(name, bt_component_get_name(other_comp)) == 0) {
+                       BT_LOGW("Invalid parameter: another component with the same name already exists in the graph: "
+                               "other-comp-addr=%p, name=\"%s\"",
+                               other_comp, name);
+                       graph_status = BT_GRAPH_STATUS_INVALID;
+                       goto end;
+               }
+       }
+
+       /*
+        * Parameters must be a map value, but we create a convenient
+        * empty one if it's NULL.
+        */
+       if (params) {
+               if (!bt_value_is_map(params)) {
+                       BT_LOGW("Invalid parameter: initialization parameters must be a map value: "
+                               "type=%s",
+                               bt_value_type_string(bt_value_get_type(params)));
+                       graph_status = BT_GRAPH_STATUS_INVALID;
+                       goto end;
+               }
+       } else {
+               params = bt_value_map_create();
+               if (!params) {
+                       BT_LOGE_STR("Cannot create map value object.");
+                       graph_status = BT_GRAPH_STATUS_NOMEM;
+                       goto end;
+               }
+       }
+
+       comp_status = bt_component_create(component_class, name, &component);
+       if (comp_status != BT_COMPONENT_STATUS_OK) {
+               BT_LOGE("Cannot create empty component object: status=%s",
+                       bt_component_status_string(comp_status));
+               graph_status = bt_graph_status_from_component_status(
+                       comp_status);
+               goto end;
+       }
+
+       /*
+        * The user's initialization method needs to see that this
+        * component is part of the graph. If the user method fails, we
+        * immediately remove the component from the graph's components.
+        */
+       g_ptr_array_add(graph->components, component);
+       bt_component_set_graph(component, graph);
+
+       if (component_class->methods.init) {
+               BT_LOGD_STR("Calling user's initialization method.");
+               comp_status = component_class->methods.init(
+                       bt_private_component_from_component(component), params,
+                       init_method_data);
+               BT_LOGD("User method returned: status=%s",
+                       bt_component_status_string(comp_status));
+               if (comp_status != BT_COMPONENT_STATUS_OK) {
+                       BT_LOGW_STR("Initialization method failed.");
+                       graph_status = bt_graph_status_from_component_status(
+                               comp_status);
+                       bt_component_set_graph(component, NULL);
+                       g_ptr_array_remove_fast(graph->components, component);
+                       goto end;
+               }
+       }
+
+       /*
+        * Mark the component as initialized so that its finalization
+        * method is called when it is destroyed.
+        */
+       component->initialized = true;
+
+       /*
+        * If it's a sink component, it needs to be part of the graph's
+        * sink queue to be consumed by bt_graph_consume().
+        */
+       if (bt_component_is_sink(component)) {
+               g_queue_push_tail(graph->sinks_to_consume, component);
+       }
+
+       /*
+        * Freeze the component class now that it's instantiated at
+        * least once.
+        */
+       BT_LOGD_STR("Freezing component class.");
+       bt_component_class_freeze(component->class);
+       BT_LOGD("Added component to graph: "
+               "graph-addr=%p, comp-cls-addr=%p, "
+               "comp-cls-type=%s, name=\"%s\", params-addr=%p, "
+               "init-method-data-addr=%p, comp-addr=%p",
+               graph, component_class, bt_component_class_type_string(type),
+               name, params, init_method_data, component);
+
+       if (user_component) {
+               /* Move reference to user */
+               *user_component = component;
+               component = NULL;
+       }
+
+end:
+       bt_put(component);
+       bt_put(params);
+       return graph_status;
+}
+
+enum bt_graph_status bt_graph_add_component(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               struct bt_component **component)
+{
+       return bt_graph_add_component_with_init_method_data(graph,
+               component_class, name, params, NULL, component);
+}
index 9462765f66a2535cea8a442baf88bbad7e54a070..455ed4ef1dc5cc26738cbe697b46c37c43aff739 100644 (file)
@@ -43,7 +43,7 @@ void bt_component_sink_destroy(struct bt_component *component)
 
 BT_HIDDEN
 struct bt_component *bt_component_sink_create(
-               struct bt_component_class *class, struct bt_value *params)
+               struct bt_component_class *class)
 {
        struct bt_component_sink *sink = NULL;
 
index 758a1b525659f5ead76bce5704e1e67e03403e17..b1a12a5d1097a72017fa6d5097f9abd987390ba7 100644 (file)
@@ -45,7 +45,7 @@ void bt_component_source_destroy(struct bt_component *component)
 
 BT_HIDDEN
 struct bt_component *bt_component_source_create(
-               struct bt_component_class *class, struct bt_value *params)
+               struct bt_component_class *class)
 {
        struct bt_component_source *source = NULL;
 
index cbce6b4c965a00acef12aa469933640ae6307e5f..d6ca1973d58c4960539f3068a6f3d5fc891dd9d2 100644 (file)
@@ -866,7 +866,7 @@ void sink_finalize(struct bt_private_component *private_component)
 }
 
 static
-void create_source_sink(struct bt_component **source,
+void create_source_sink(struct bt_graph *graph, struct bt_component **source,
                struct bt_component **sink)
 {
        struct bt_component_class *src_comp_class;
@@ -887,8 +887,9 @@ void create_source_sink(struct bt_component **source,
        ret = bt_component_class_source_set_notification_iterator_finalize_method(
                src_comp_class, src_iter_finalize);
        assert(ret == 0);
-       *source = bt_component_create(src_comp_class, "source", NULL);
-       assert(*source);
+       ret = bt_graph_add_component(graph, src_comp_class, "source", NULL,
+               source);
+       assert(ret == 0);
 
        /* Create sink component */
        sink_comp_class = bt_component_class_sink_create("sink", sink_consume);
@@ -900,7 +901,9 @@ void create_source_sink(struct bt_component **source,
        ret = bt_component_class_set_port_connected_method(sink_comp_class,
                sink_port_connected);
        assert(ret == 0);
-       *sink = bt_component_create(sink_comp_class, "sink", NULL);
+       ret = bt_graph_add_component(graph, sink_comp_class, "sink", NULL,
+               sink);
+       assert(ret == 0);
 
        bt_put(src_comp_class);
        bt_put(sink_comp_class);
@@ -920,9 +923,9 @@ void do_std_test(enum test test, const char *name,
        clear_test_events();
        current_test = test;
        diag("test: %s", name);
-       create_source_sink(&src_comp, &sink_comp);
        graph = bt_graph_create();
        assert(graph);
+       create_source_sink(graph, &src_comp, &sink_comp);
 
        /* Connect source to sink */
        upstream_port = bt_component_source_get_output_port_by_name(src_comp, "out");
index 058393a2b091503afc8fac29826b26dc46d8a105..2efac144433798df9a5a646717925203935685ac 100644 (file)
@@ -39,7 +39,7 @@
 
 #include "tap/tap.h"
 
-#define NR_TESTS       69
+#define NR_TESTS       77
 
 enum event_type {
        COMP_ACCEPT_PORT_CONNECTION,
@@ -588,22 +588,26 @@ void fini_test(void)
 }
 
 static
-struct bt_component *create_src(void)
+struct bt_component *create_src(struct bt_graph *graph)
 {
-       struct bt_component *comp =
-               bt_component_create(src_comp_class, "src-comp", NULL);
+       struct bt_component *comp;
+       int ret;
 
-       assert(comp);
+       ret = bt_graph_add_component(graph, src_comp_class, "src-comp", NULL,
+               &comp);
+       assert(ret == 0);
        return comp;
 }
 
 static
-struct bt_component *create_sink(void)
+struct bt_component *create_sink(struct bt_graph *graph)
 {
-       struct bt_component *comp =
-               bt_component_create(sink_comp_class, "sink-comp", NULL);
+       struct bt_component *comp;
+       int ret;
 
-       assert(comp);
+       ret = bt_graph_add_component(graph, sink_comp_class, "sink-comp",
+               NULL, &comp);
+       assert(ret == 0);
        return comp;
 }
 
@@ -661,9 +665,10 @@ void test_sink_removes_port_in_port_connected_then_src_removes_disconnected_port
 
        prepare_test(TEST_SINK_REMOVES_PORT_IN_CONSUME_THEN_SRC_REMOVES_DISCONNECTED_PORT,
                "sink removes port in consume, then source removes disconnected port");
-       src = create_src();
-       sink = create_sink();
        graph = create_graph();
+       assert(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
        src_def_port = bt_component_source_get_output_port_by_name(src, "out");
        assert(src_def_port);
        sink_def_port = bt_component_sink_get_input_port_by_name(sink, "in");
@@ -673,8 +678,20 @@ void test_sink_removes_port_in_port_connected_then_src_removes_disconnected_port
        assert(status == 0);
        assert(conn);
 
-       /* We're supposed to have 5 events so far */
-       ok(events->len == 5, "we have the expected number of events (before consume)");
+       /* We're supposed to have 7 events so far */
+       ok(events->len == 7, "we have the expected number of events (before consume)");
+
+       /* Source's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = src;
+       event.data.graph_port_added.port = src_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = sink;
+       event.data.graph_port_added.port = sink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
 
        /* Source's accept port connection */
        event.type = COMP_ACCEPT_PORT_CONNECTION;
@@ -825,9 +842,10 @@ void test_sink_removes_port_in_port_connected(void)
 
        prepare_test(TEST_SINK_REMOVES_PORT_IN_CONSUME,
                "sink removes port in consume");
-       src = create_src();
-       sink = create_sink();
        graph = create_graph();
+       assert(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
        src_def_port = bt_component_source_get_output_port_by_name(src, "out");
        assert(src_def_port);
        sink_def_port = bt_component_sink_get_input_port_by_name(sink, "in");
@@ -836,8 +854,20 @@ void test_sink_removes_port_in_port_connected(void)
                &conn);
        assert(status == 0);
 
-       /* We're supposed to have 5 events so far */
-       ok(events->len == 5, "we have the expected number of events (before consume)");
+       /* We're supposed to have 7 events so far */
+       ok(events->len == 7, "we have the expected number of events (before consume)");
+
+       /* Source's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = src;
+       event.data.graph_port_added.port = src_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = sink;
+       event.data.graph_port_added.port = sink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
 
        /* Source's accept port connection */
        event.type = COMP_ACCEPT_PORT_CONNECTION;
@@ -970,9 +1000,10 @@ void test_src_adds_port_in_port_connected(void)
 
        prepare_test(TEST_SRC_ADDS_PORT_IN_PORT_CONNECTED,
                "source adds port in port connected");
-       src = create_src();
-       sink = create_sink();
        graph = create_graph();
+       assert(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
        src_def_port = bt_component_source_get_output_port_by_name(src, "out");
        assert(src_def_port);
        sink_def_port = bt_component_sink_get_input_port_by_name(sink, "in");
@@ -984,8 +1015,20 @@ void test_src_adds_port_in_port_connected(void)
                "hello");
        assert(src_hello_port);
 
-       /* We're supposed to have 6 events */
-       ok(events->len == 6, "we have the expected number of events");
+       /* We're supposed to have 8 events */
+       ok(events->len == 8, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = src;
+       event.data.graph_port_added.port = src_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = sink;
+       event.data.graph_port_added.port = sink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
 
        /* Source's accept port connection */
        event.type = COMP_ACCEPT_PORT_CONNECTION;
@@ -1077,9 +1120,10 @@ void test_simple(void)
        size_t graph_ports_connected_pos;
 
        prepare_test(TEST_SIMPLE, "simple");
-       src = create_src();
-       sink = create_sink();
        graph = create_graph();
+       assert(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
        src_def_port = bt_component_source_get_output_port_by_name(src, "out");
        assert(src_def_port);
        sink_def_port = bt_component_sink_get_input_port_by_name(sink, "in");
@@ -1088,8 +1132,20 @@ void test_simple(void)
                &conn);
        assert(status == 0);
 
-       /* We're supposed to have 5 events */
-       ok(events->len == 5, "we have the expected number of events");
+       /* We're supposed to have 7 events */
+       ok(events->len == 7, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = src;
+       event.data.graph_port_added.port = src_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_PORT_ADDED;
+       event.data.graph_port_added.comp = sink;
+       event.data.graph_port_added.port = sink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
 
        /* Source's accept port connection */
        event.type = COMP_ACCEPT_PORT_CONNECTION;
index d4390dcbe0bd1aca195231babc9e9dd68ae818e0..cec0933e0e6b376869052f4fb44a854d335051b8 100644 (file)
@@ -23,6 +23,7 @@
 #include <babeltrace/ref.h>
 #include <babeltrace/values.h>
 #include <babeltrace/graph/component.h>
+#include <babeltrace/graph/graph.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -148,6 +149,7 @@ static void test_sfs(const char *plugin_dir)
        struct bt_value *results;
        struct bt_value *object;
        struct bt_value *res_params;
+       struct bt_graph *graph;
        const char *object_str;
        int ret;
 
@@ -218,20 +220,35 @@ static void test_sfs(const char *plugin_dir)
 
        diag("> putting the plugin object here");
        BT_PUT(plugin);
-       sink_component = bt_component_create(sink_comp_class, NULL, NULL);
-       ok(sink_component, "bt_component_create() still works after the plugin object is destroyed");
+       graph = bt_graph_create();
+       assert(graph);
+       ret = bt_graph_add_component(graph, sink_comp_class, "the-sink", NULL,
+               &sink_component);
+       ok(ret == 0 && sink_component,
+               "bt_graph_add_component() still works after the plugin object is destroyed");
        BT_PUT(sink_component);
        BT_PUT(source_comp_class);
-       sink_component = bt_component_create(sink_comp_class, NULL, NULL);
-       ok(sink_component, "bt_component_create() still works after the source component class object is destroyed");
+       bt_put(graph);
+       graph = bt_graph_create();
+       assert(graph);
+       ret = bt_graph_add_component(graph, sink_comp_class, "the-sink", NULL,
+               &sink_component);
+       ok(ret == 0 && sink_component,
+               "bt_graph_add_component() still works after the source component class object is destroyed");
        BT_PUT(sink_component);
        BT_PUT(filter_comp_class);
-       sink_component = bt_component_create(sink_comp_class, NULL, NULL);
-       ok(sink_component, "bt_component_create() still works after the filter component class object is destroyed");
+       bt_put(graph);
+       graph = bt_graph_create();
+       assert(graph);
+       ret = bt_graph_add_component(graph, sink_comp_class, "the-sink", NULL,
+               &sink_component);
+       ok(ret == 0 && sink_component,
+               "bt_graph_add_component() still works after the filter component class object is destroyed");
        BT_PUT(sink_comp_class);
        BT_PUT(sink_component);
 
        free(sfs_path);
+       bt_put(graph);
        bt_put(plugin_set);
        bt_put(object);
        bt_put(res_params);
index 6600a72e8f183caeb5fec509fa562d6e7e784ecf..76edfd76d058046f6412c9b10a212c26cba8eb7b 100644 (file)
@@ -912,7 +912,8 @@ void sink_finalize(struct bt_private_component *private_component)
 }
 
 static
-void create_source_muxer_sink(struct bt_component **source,
+void create_source_muxer_sink(struct bt_graph *graph,
+               struct bt_component **source,
                struct bt_component **muxer,
                struct bt_component **sink)
 {
@@ -935,15 +936,15 @@ void create_source_muxer_sink(struct bt_component **source,
        ret = bt_component_class_source_set_notification_iterator_finalize_method(
                src_comp_class, src_iter_finalize);
        assert(ret == 0);
-       *source = bt_component_create(src_comp_class, "source", NULL);
-       assert(*source);
+       ret = bt_graph_add_component(graph, src_comp_class, "source", NULL, source);
+       assert(ret == 0);
 
        /* Create muxer component */
        muxer_comp_class = bt_plugin_find_component_class("utils", "muxer",
                BT_COMPONENT_CLASS_TYPE_FILTER);
        assert(muxer_comp_class);
-       *muxer = bt_component_create(muxer_comp_class, "muxer", NULL);
-       assert(*muxer);
+       ret = bt_graph_add_component(graph, muxer_comp_class, "muxer", NULL, muxer);
+       assert(ret == 0);
 
        /* Create sink component */
        sink_comp_class = bt_component_class_sink_create("sink", sink_consume);
@@ -955,7 +956,8 @@ void create_source_muxer_sink(struct bt_component **source,
        ret = bt_component_class_set_port_connected_method(sink_comp_class,
                sink_port_connected);
        assert(ret == 0);
-       *sink = bt_component_create(sink_comp_class, "sink", NULL);
+       ret = bt_graph_add_component(graph, sink_comp_class, "sink", NULL, sink);
+       assert(ret == 0);
 
        bt_put(src_comp_class);
        bt_put(muxer_comp_class);
@@ -980,9 +982,9 @@ void do_std_test(enum test test, const char *name,
        clear_test_events();
        current_test = test;
        diag("test: %s", name);
-       create_source_muxer_sink(&src_comp, &muxer_comp, &sink_comp);
        graph = bt_graph_create();
        assert(graph);
+       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
 
        /* Connect source output ports to muxer input ports */
        if (with_upstream) {
@@ -1454,9 +1456,9 @@ void test_single_end_then_multiple_full(void)
        clear_test_events();
        current_test = TEST_SINGLE_END_THEN_MULTIPLE_FULL;
        diag("test: single end then multiple full");
-       create_source_muxer_sink(&src_comp, &muxer_comp, &sink_comp);
        graph = bt_graph_create();
        assert(graph);
+       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
        graph_listener_data.graph = graph;
        graph_listener_data.source = src_comp;
        graph_listener_data.muxer = muxer_comp;
@@ -1582,9 +1584,9 @@ void test_single_again_end_then_multiple_full(void)
        clear_test_events();
        current_test = TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL;
        diag("test: single again then end then multiple full");
-       create_source_muxer_sink(&src_comp, &muxer_comp, &sink_comp);
        graph = bt_graph_create();
        assert(graph);
+       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
        graph_listener_data.graph = graph;
        graph_listener_data.source = src_comp;
        graph_listener_data.muxer = muxer_comp;
This page took 0.042461 seconds and 4 git commands to generate.