/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
* Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
*/
#define BT_LOG_TAG "COMP"
-#include <babeltrace/lib-logging-internal.h>
-
-#include <babeltrace/graph/self-component.h>
-#include <babeltrace/graph/component-const.h>
-#include <babeltrace/graph/component-source-const.h>
-#include <babeltrace/graph/component-filter-const.h>
-#include <babeltrace/graph/component-sink-const.h>
-#include <babeltrace/graph/component-internal.h>
-#include <babeltrace/graph/component-class-internal.h>
-#include <babeltrace/graph/component-source-internal.h>
-#include <babeltrace/graph/component-filter-internal.h>
-#include <babeltrace/graph/component-sink-internal.h>
-#include <babeltrace/graph/connection-internal.h>
-#include <babeltrace/graph/graph-internal.h>
-#include <babeltrace/graph/notification-iterator-internal.h>
-#include <babeltrace/graph/port-internal.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/compiler-internal.h>
-#include <babeltrace/object.h>
-#include <babeltrace/types.h>
-#include <babeltrace/values.h>
-#include <babeltrace/values-internal.h>
-#include <babeltrace/assert-internal.h>
-#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace2/lib-logging-internal.h>
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/graph/self-component.h>
+#include <babeltrace2/graph/component-const.h>
+#include <babeltrace2/graph/component-source-const.h>
+#include <babeltrace2/graph/component-filter-const.h>
+#include <babeltrace2/graph/component-sink-const.h>
+#include <babeltrace2/graph/component-internal.h>
+#include <babeltrace2/graph/component-class-internal.h>
+#include <babeltrace2/graph/component-source-internal.h>
+#include <babeltrace2/graph/component-filter-internal.h>
+#include <babeltrace2/graph/component-sink-internal.h>
+#include <babeltrace2/graph/connection-internal.h>
+#include <babeltrace2/graph/graph-internal.h>
+#include <babeltrace2/graph/message-iterator-internal.h>
+#include <babeltrace2/graph/port-internal.h>
+#include <babeltrace2/babeltrace-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-internal.h>
#include <stdint.h>
#include <inttypes.h>
}
static
-struct bt_port *add_port(
+enum bt_self_component_status add_port(
struct bt_component *component, GPtrArray *ports,
- enum bt_port_type port_type, const char *name, void *user_data)
+ enum bt_port_type port_type, const char *name, void *user_data,
+ struct bt_port **port)
{
struct bt_port *new_port = NULL;
struct bt_graph *graph = NULL;
+ enum bt_self_component_status status;
BT_ASSERT_PRE_NON_NULL(component, "Component");
BT_ASSERT_PRE_NON_NULL(name, "Name");
BT_ASSERT_PRE(graph && !bt_graph_is_canceled(graph),
"Component's graph is canceled: %![comp-]+c, %![graph-]+g",
component, graph);
+ BT_ASSERT_PRE(
+ graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+ "Component's graph is already configured: "
+ "%![comp-]+c, %![graph-]+g", component, graph);
// TODO: Validate that the name is not already used.
new_port = bt_port_create(component, port_type, name, user_data);
if (!new_port) {
BT_LOGE_STR("Cannot create port object.");
- goto end;
+ status = BT_SELF_COMPONENT_STATUS_NOMEM;
+ goto error;
}
/*
/*
* Notify the graph's creator that a new port was added.
*/
- bt_object_get_ref(bt_component_borrow_graph(component));
graph = bt_component_borrow_graph(component);
if (graph) {
- bt_graph_notify_port_added(graph, new_port);
- BT_OBJECT_PUT_REF_AND_RESET(graph);
+ enum bt_graph_listener_status listener_status;
+
+ listener_status = bt_graph_notify_port_added(graph, new_port);
+ if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
+ bt_graph_make_faulty(graph);
+ status = listener_status;
+ goto error;
+ }
}
BT_LIB_LOGD("Created and added port to component: "
"%![comp-]+c, %![port-]+p", component, new_port);
+ *port = new_port;
+ status = BT_SELF_COMPONENT_STATUS_OK;
+
+ goto end;
+error:
+ /*
+ * We need to release the reference that we would otherwise have
+ * returned to the caller.
+ */
+ BT_PORT_PUT_REF_AND_RESET(new_port);
+
end:
- return new_port;
+ return status;
}
BT_HIDDEN
BT_ASSERT(user_component);
BT_ASSERT(component_class);
BT_ASSERT(name);
-
type = bt_component_class_get_type(component_class);
BT_LIB_LOGD("Creating empty component from component class: %![cc-]+C, "
"comp-name=\"%s\"", component_class, name);
goto end;
}
- bt_object_init_shared_with_parent(&component->base,
- destroy_component);
+ bt_object_init_shared_with_parent(&component->base, destroy_component);
component->class = component_class;
bt_object_get_no_null_check(component->class);
component->destroy = component_destroy_funcs[type];
return component->name->str;
}
-struct bt_component_class *bt_component_borrow_class(
+const struct bt_component_class *bt_component_borrow_class_const(
const struct bt_component *component)
{
BT_ASSERT_PRE_NON_NULL(component, "Component");
}
BT_HIDDEN
-struct bt_port_input *bt_component_add_input_port(
+enum bt_self_component_status bt_component_add_input_port(
struct bt_component *component, const char *name,
- void *user_data)
+ void *user_data, struct bt_port **port)
{
/* add_port() logs details */
- return (void *)
- add_port(component, component->input_ports,
- BT_PORT_TYPE_INPUT, name, user_data);
+ return add_port(component, component->input_ports,
+ BT_PORT_TYPE_INPUT, name, user_data, port);
}
BT_HIDDEN
-struct bt_port_output *bt_component_add_output_port(
+enum bt_self_component_status bt_component_add_output_port(
struct bt_component *component, const char *name,
- void *user_data)
+ void *user_data, struct bt_port **port)
{
/* add_port() logs details */
- return (void *)
- add_port(component, component->output_ports,
- BT_PORT_TYPE_OUTPUT, name, user_data);
-}
-
-static
-void remove_port_by_index(struct bt_component *component,
- GPtrArray *ports, uint64_t index)
-{
- struct bt_port *port;
- struct bt_graph *graph;
-
- BT_ASSERT(ports);
- BT_ASSERT(index < ports->len);
- port = g_ptr_array_index(ports, index);
- BT_LIB_LOGD("Removing port from component: %![comp-]+c, %![port-]+p",
- component, port);
-
- /* Disconnect both ports of this port's connection, if any */
- if (port->connection) {
- bt_connection_end(port->connection, true);
- }
-
- /*
- * The port's current reference count can be 0 at this point,
- * which means its parent (component) keeps it alive. We are
- * about to remove the port from its parent's container (with
- * the g_ptr_array_remove_index() call below), which in this
- * case would destroy it. This is not good because we still
- * need the port for the bt_graph_notify_port_removed() call
- * below (in which its component is `NULL` as expected because
- * of the bt_object_set_parent() call below).
- *
- * To avoid a destroyed port during the notification callback,
- * get a reference now, and put it (destroying the port if its
- * reference count is 0 at this point) after notifying the
- * graph's user.
- */
- bt_object_get_no_null_check(&port->base);
-
- /*
- * Remove from parent's array of ports (weak refs). This never
- * destroys the port object because its reference count is at
- * least 1 thanks to the bt_object_get_no_null_check() call
- * above.
- */
- g_ptr_array_remove_index(ports, index);
-
- /* Detach port from its component parent */
- bt_object_set_parent(&port->base, NULL);
-
- /*
- * Notify the graph's creator that a port is removed.
- */
- graph = bt_component_borrow_graph(component);
- if (graph) {
- bt_graph_notify_port_removed(graph, component, port);
- }
-
- BT_LIB_LOGD("Removed port from component: %![comp-]+c, %![port-]+p",
- component, port);
-
- /*
- * Put the local reference. If this port's reference count was 0
- * when entering this function, it is 1 now, so it is destroyed
- * immediately.
- */
- bt_object_put_no_null_check(&port->base);
-}
-
-BT_HIDDEN
-void bt_component_remove_port(struct bt_component *component,
- struct bt_port *port)
-{
- uint64_t i;
- GPtrArray *ports = NULL;
-
- BT_ASSERT(component);
- BT_ASSERT(port);
-
- switch (port->type) {
- case BT_PORT_TYPE_INPUT:
- ports = component->input_ports;
- break;
- case BT_PORT_TYPE_OUTPUT:
- ports = component->output_ports;
- break;
- default:
- abort();
- }
-
- BT_ASSERT(ports);
-
- for (i = 0; i < ports->len; i++) {
- struct bt_port *cur_port = g_ptr_array_index(ports, i);
-
- if (cur_port == port) {
- remove_port_by_index(component,
- ports, i);
- goto end;
- }
- }
-
- BT_LIB_LOGW("Port to remove from component was not found: "
- "%![comp-]+c, %![port-]+p", component, port);
-
-end:
- return;
+ return add_port(component, component->output_ports,
+ BT_PORT_TYPE_OUTPUT, name, user_data, port);
}
BT_HIDDEN
status = method(comp, self_port, (void *) other_port);
BT_LOGD("User method returned: status=%s",
bt_self_component_status_string(status));
+ BT_ASSERT_PRE(status == BT_SELF_COMPONENT_STATUS_OK ||
+ status == BT_SELF_COMPONENT_STATUS_ERROR ||
+ status == BT_SELF_COMPONENT_STATUS_NOMEM,
+ "Unexpected returned component status: status=%s",
+ bt_self_component_status_string(status));
}
return status;
}
-BT_HIDDEN
-void bt_component_port_disconnected(struct bt_component *comp,
- struct bt_port *port)
-{
- typedef void (*method_t)(void *, void *);
-
- method_t method = NULL;
-
- BT_ASSERT(comp);
- BT_ASSERT(port);
-
- switch (comp->class->type) {
- case BT_COMPONENT_CLASS_TYPE_SOURCE:
- {
- struct bt_component_class_source *src_cc = (void *) comp->class;
-
- switch (port->type) {
- case BT_PORT_TYPE_OUTPUT:
- method = (method_t) src_cc->methods.output_port_disconnected;
- break;
- default:
- abort();
- }
-
- break;
- }
- case BT_COMPONENT_CLASS_TYPE_FILTER:
- {
- struct bt_component_class_filter *flt_cc = (void *) comp->class;
-
- switch (port->type) {
- case BT_PORT_TYPE_INPUT:
- method = (method_t) flt_cc->methods.input_port_disconnected;
- break;
- case BT_PORT_TYPE_OUTPUT:
- method = (method_t) flt_cc->methods.output_port_disconnected;
- break;
- default:
- abort();
- }
-
- break;
- }
- case BT_COMPONENT_CLASS_TYPE_SINK:
- {
- struct bt_component_class_sink *sink_cc = (void *) comp->class;
-
- switch (port->type) {
- case BT_PORT_TYPE_INPUT:
- method = (method_t) sink_cc->methods.input_port_disconnected;
- break;
- default:
- abort();
- }
-
- break;
- }
- default:
- abort();
- }
-
- if (method) {
- BT_LIB_LOGD("Calling user's \"port disconnected\" method: "
- "%![comp-]+c, %![port-]+p", comp, port);
- method(comp, port);
- }
-}
-
BT_HIDDEN
void bt_component_add_destroy_listener(struct bt_component *component,
bt_component_destroy_listener_func func, void *data)
}
}
}
+
+void bt_component_get_ref(const struct bt_component *component)
+{
+ bt_object_get_ref(component);
+}
+
+void bt_component_put_ref(const struct bt_component *component)
+{
+ bt_object_put_ref(component);
+}