Add graph event listeners
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Sat, 25 Mar 2017 05:27:24 +0000 (01:27 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:38 +0000 (12:57 -0400)
With this patch you can add event listeners to a graph:

* Port added to a graph's component. Note that this is only called when
  the component belongs to a graph. It is not called for existing ports
  when the component becomes part of a graph (with bt_graph_connect()).
* Port removed from a graph's component.
* Graph component's port connected.
* Graph component's port disconnected.

All those listeners return `void` because they cannot "fail". In the
worst case they should just abort. Another way would be to set a flag
at some place and read it once you have called bt_graph_run() or
bt_graph_consume().

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
include/babeltrace/component/graph-internal.h
include/babeltrace/component/graph.h
lib/component/component.c
lib/component/connection.c
lib/component/graph.c

index 7da6255fa92fdda33efe1534ea01b8f2e63f7d62..0084628af5bd987e5ebafd571f0cc28c35d90056 100644 (file)
@@ -32,6 +32,9 @@
 #include <babeltrace/object-internal.h>
 #include <glib.h>
 
+struct bt_component;
+struct bt_port;
+
 struct bt_graph {
        /**
         * A component graph contains components and point-to-point connection
@@ -51,6 +54,28 @@ struct bt_graph {
        GPtrArray *components;
        /* Queue of pointers (weak references) to sink bt_components. */
        GQueue *sinks_to_consume;
+
+       struct {
+               GArray *port_added;
+               GArray *port_removed;
+               GArray *port_connected;
+               GArray *port_disconnected;
+       } listeners;
 };
 
+BT_HIDDEN
+void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port);
+
+BT_HIDDEN
+void bt_graph_notify_port_removed(struct bt_graph *graph,
+               struct bt_component *comp, struct bt_port *port);
+
+BT_HIDDEN
+void bt_graph_notify_port_connected(struct bt_graph *graph,
+               struct bt_port *port);
+
+BT_HIDDEN
+void bt_graph_notify_port_disconnected(struct bt_graph *graph,
+               struct bt_component *comp, struct bt_port *port);
+
 #endif /* BABELTRACE_COMPONENT_COMPONENT_GRAPH_INTERNAL_H */
index 4524be3588d852e0b48293bbb79a1958d479deda..2d62484fa4bc220e9181269dcca1f3c44dd860e6 100644 (file)
@@ -54,6 +54,16 @@ enum bt_graph_status {
        BT_GRAPH_STATUS_ERROR = -5,
 };
 
+typedef void (*bt_graph_port_added_listener)(struct bt_port *port,
+               void *data);
+typedef void (*bt_graph_port_removed_listener)(struct bt_component *component,
+               struct bt_port *port, void *data);
+typedef void (*bt_graph_port_connected_listener)(struct bt_port *port,
+               void *data);
+typedef void (*bt_graph_port_disconnected_listener)(
+               struct bt_component *component, struct bt_port *port,
+               void *data);
+
 extern struct bt_graph *bt_graph_create(void);
 
 /**
@@ -88,6 +98,22 @@ 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 enum bt_graph_status bt_graph_add_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_port_added_listener listener, void *data);
+
+extern enum bt_graph_status bt_graph_add_port_removed_listener(
+               struct bt_graph *graph,
+               bt_graph_port_removed_listener listener, void *data);
+
+extern enum bt_graph_status bt_graph_add_port_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_port_connected_listener listener, void *data);
+
+extern enum bt_graph_status bt_graph_add_port_disconnected_listener(
+               struct bt_graph *graph,
+               bt_graph_port_disconnected_listener listener, void *data);
+
 #ifdef __cplusplus
 }
 #endif
index 7a72fe797f02713acf1451f5f242c0f87676d2c3..d55526c8ee4bdfa7d7968d0f4df277035f7039b5 100644 (file)
@@ -187,6 +187,7 @@ struct bt_port *bt_component_add_port(
 {
        size_t i;
        struct bt_port *new_port = NULL;
+       struct bt_graph *graph = NULL;
 
        if (!name || strlen(name) == 0) {
                goto end;
@@ -221,6 +222,16 @@ struct bt_port *bt_component_add_port(
         * is now protected by the component's own lifetime.
         */
        g_ptr_array_add(ports, new_port);
+
+       /*
+        * Notify the graph's creator that a new port was added.
+        */
+       graph = bt_component_get_graph(component);
+       if (graph) {
+               bt_graph_notify_port_added(graph, new_port);
+               BT_PUT(graph);
+       }
+
 end:
        return new_port;
 }
@@ -515,6 +526,7 @@ void bt_component_remove_port_at_index(struct bt_component *component,
                GPtrArray *ports, size_t index)
 {
        struct bt_port *port;
+       struct bt_graph *graph;
 
        assert(ports);
        assert(index < ports->len);
@@ -531,7 +543,14 @@ void bt_component_remove_port_at_index(struct bt_component *component,
        /* Detach port from its component parent */
        BT_PUT(port->base.parent);
 
-       // TODO: notify graph user: component's port removed
+       /*
+        * Notify the graph's creator that a port is removed.
+        */
+       graph = bt_component_get_graph(component);
+       if (graph) {
+               bt_graph_notify_port_removed(graph, component, port);
+               BT_PUT(graph);
+       }
 }
 
 BT_HIDDEN
index 88f26af4aa553d5d097bb9a7cf3515699872d019..702db81d7f73b282e96a83090479ae3776066b14 100644 (file)
@@ -112,7 +112,24 @@ void bt_connection_disconnect_ports(struct bt_connection *conn,
                bt_component_port_disconnected(upstream_comp, upstream_port);
        }
 
-       // TODO: notify graph user: component's port disconnected
+       if (upstream_comp) {
+               struct bt_graph *graph = bt_component_get_graph(upstream_comp);
+
+               assert(graph);
+               bt_graph_notify_port_disconnected(graph, upstream_comp,
+                       upstream_port);
+               bt_put(graph);
+       }
+
+       if (downstream_comp) {
+               struct bt_graph *graph =
+                       bt_component_get_graph(downstream_comp);
+
+               assert(graph);
+               bt_graph_notify_port_disconnected(graph, downstream_comp,
+                       downstream_port);
+               bt_put(graph);
+       }
 
        bt_put(downstream_comp);
        bt_put(upstream_comp);
index 8b2bed4488ad6e29d5463d8d57c5b2286b7ba2f4..8e21e1a3873cac9bd76a025d0d56a12664da7867 100644 (file)
 #include <babeltrace/component/port.h>
 #include <babeltrace/compiler.h>
 #include <unistd.h>
+#include <glib.h>
+
+struct bt_graph_listener {
+       void *func;
+       void *data;
+};
 
 static
 void bt_graph_destroy(struct bt_object *obj)
@@ -51,12 +57,46 @@ void bt_graph_destroy(struct bt_object *obj)
        if (graph->sinks_to_consume) {
                g_queue_free(graph->sinks_to_consume);
        }
+
+       if (graph->listeners.port_added) {
+               g_array_free(graph->listeners.port_added, TRUE);
+       }
+
+       if (graph->listeners.port_removed) {
+               g_array_free(graph->listeners.port_removed, TRUE);
+       }
+
+       if (graph->listeners.port_connected) {
+               g_array_free(graph->listeners.port_connected, TRUE);
+       }
+
+       if (graph->listeners.port_disconnected) {
+               g_array_free(graph->listeners.port_disconnected, TRUE);
+       }
+
        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) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
 struct bt_graph *bt_graph_create(void)
 {
        struct bt_graph *graph;
+       int ret;
 
        graph = g_new0(struct bt_graph, 1);
        if (!graph) {
@@ -77,6 +117,27 @@ struct bt_graph *bt_graph_create(void)
        if (!graph->sinks_to_consume) {
                goto error;
        }
+
+       ret = init_listeners_array(&graph->listeners.port_added);
+       if (ret) {
+               goto error;
+       }
+
+       ret = init_listeners_array(&graph->listeners.port_removed);
+       if (ret) {
+               goto error;
+       }
+
+       ret = init_listeners_array(&graph->listeners.port_connected);
+       if (ret) {
+               goto error;
+       }
+
+       ret = init_listeners_array(&graph->listeners.port_disconnected);
+       if (ret) {
+               goto error;
+       }
+
 end:
        return graph;
 error:
@@ -204,6 +265,14 @@ struct bt_connection *bt_graph_connect(struct bt_graph *graph,
        if (component_status != BT_COMPONENT_STATUS_OK) {
                goto error_rollback;
        }
+
+       /*
+        * Both components accepted the connection. Notify the graph's
+        * creator that both ports are connected.
+        */
+       bt_graph_notify_port_connected(graph, upstream_port);
+       bt_graph_notify_port_connected(graph, downstream_port);
+
 end:
        bt_put(upstream_graph);
        bt_put(downstream_graph);
@@ -558,3 +627,149 @@ enum bt_graph_status bt_graph_run(struct bt_graph *graph)
 error:
        return status;
 }
+
+static
+void add_listener(GArray *listeners, void *func, void *data)
+{
+       struct bt_graph_listener listener = {
+               .func = func,
+               .data = data,
+       };
+
+       g_array_append_val(listeners, listener);
+}
+
+enum bt_graph_status bt_graph_add_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_port_added_listener listener, void *data)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+
+       if (!graph || !listener) {
+               status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       add_listener(graph->listeners.port_added, listener, data);
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_add_port_removed_listener(
+               struct bt_graph *graph,
+               bt_graph_port_removed_listener listener, void *data)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+
+       if (!graph || !listener) {
+               status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       add_listener(graph->listeners.port_removed, listener, data);
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_add_port_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_port_connected_listener listener, void *data)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+
+       if (!graph || !listener) {
+               status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       add_listener(graph->listeners.port_connected, listener, data);
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_add_port_disconnected_listener(
+               struct bt_graph *graph,
+               bt_graph_port_disconnected_listener listener, void *data)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+
+       if (!graph || !listener) {
+               status = BT_GRAPH_STATUS_INVALID;
+               goto end;
+       }
+
+       add_listener(graph->listeners.port_disconnected, listener, data);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void bt_graph_notify_port_added(struct bt_graph *graph, struct bt_port *port)
+{
+       size_t i;
+
+       for (i = 0; i < graph->listeners.port_added->len; i++) {
+               struct bt_graph_listener listener =
+                       g_array_index(graph->listeners.port_added,
+                               struct bt_graph_listener, i);
+               bt_graph_port_added_listener func = listener.func;
+
+               assert(func);
+               func(port, listener.data);
+       }
+}
+
+BT_HIDDEN
+void bt_graph_notify_port_removed(struct bt_graph *graph,
+               struct bt_component *comp, struct bt_port *port)
+{
+       size_t i;
+
+       for (i = 0; i < graph->listeners.port_removed->len; i++) {
+               struct bt_graph_listener listener =
+                       g_array_index(graph->listeners.port_removed,
+                               struct bt_graph_listener, i);
+               bt_graph_port_removed_listener func = listener.func;
+
+               assert(func);
+               func(comp, port, listener.data);
+       }
+}
+
+BT_HIDDEN
+void bt_graph_notify_port_connected(struct bt_graph *graph,
+               struct bt_port *port)
+{
+       size_t i;
+
+       for (i = 0; i < graph->listeners.port_connected->len; i++) {
+               struct bt_graph_listener listener =
+                       g_array_index(graph->listeners.port_connected,
+                               struct bt_graph_listener, i);
+               bt_graph_port_connected_listener func = listener.func;
+
+               assert(func);
+               func(port, listener.data);
+       }
+}
+
+BT_HIDDEN
+void bt_graph_notify_port_disconnected(struct bt_graph *graph,
+               struct bt_component *comp, struct bt_port *port)
+{
+       size_t i;
+
+       for (i = 0; i < graph->listeners.port_disconnected->len; i++) {
+               struct bt_graph_listener listener =
+                       g_array_index(graph->listeners.port_disconnected,
+                               struct bt_graph_listener, i);
+               bt_graph_port_disconnected_listener func = listener.func;
+
+               assert(func);
+               func(comp, port, listener.data);
+       }
+}
This page took 0.030301 seconds and 4 git commands to generate.