Add built-in colander sink component class
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 4 Aug 2017 23:07:24 +0000 (19:07 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 11 Aug 2017 22:54:16 +0000 (18:54 -0400)
You can use this new built-in sink component class to create a component
which passes the consumed notification to the user through a pointer
passed as the initialization method data:

    struct bt_notification *notif = NULL;
    struct bt_component_class *colander_cc =
        bt_component_class_sink_colander_get();
    struct bt_component *colander_comp;

    ret = bt_graph_add_component_with_init_method_data(graph,
        colander_cc, "colander", NULL, &notif, &colander_comp);

    ...

    for (;;) {
        ret = bt_graph_consume(graph);
        if (ret != BT_GRAPH_STATUS_OK) {
            ...
        }

        /* Do something with notif */
        BT_PUT(notif);
    }

Everytime you call bt_graph_consume() and this function is successful,
your notification pointer contains a reference to the consumed
notification. You need to release this reference with bt_put(), as the
colander component won't do it. This is why you should not use
bt_graph_run() with a colander component because notifications will
leak.

bt_component_class_sink_colander_get() lazily creates the component
class the first time it is called and the uses this same reference for
future calls. The source file's destructor releases the global reference
when the library is destroyed.

The component class is built-in so that you do not need any installed
plugins to use this utility. Since it's not part of a plugin, you cannot
use it with the CLI, but this is okay because it needs custom
initialization method data anyway.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
include/Makefile.am
include/babeltrace/babeltrace.h
include/babeltrace/graph/component-class-sink-colander.h [new file with mode: 0644]
include/babeltrace/graph/component-class-sink.h
lib/graph/Makefile.am
lib/graph/component-class-sink-colander.c [new file with mode: 0644]

index f929321067964b541afa5f164b470c5cae86f973..f1f86fcb69f28cc11690b9672b10c3fd1f4823f9 100644 (file)
@@ -51,6 +51,7 @@ babeltracegraphincludedir = "$(includedir)/babeltrace/graph"
 babeltracegraphinclude_HEADERS = \
        babeltrace/graph/clock-class-priority-map.h \
        babeltrace/graph/component-class-filter.h \
+       babeltrace/graph/component-class-sink-colander.h \
        babeltrace/graph/component-class-sink.h \
        babeltrace/graph/component-class-source.h \
        babeltrace/graph/component-class.h \
index 7aad9b1c5a75274b6a71c28eb5263ed53a08e48f..31fcb9aae78db61a5d54c195897ccd42d1d0ea05 100644 (file)
@@ -65,6 +65,7 @@
 /* Graph, component, and notification API */
 #include <babeltrace/graph/clock-class-priority-map.h>
 #include <babeltrace/graph/component-class-filter.h>
+#include <babeltrace/graph/component-class-sink-colander.h>
 #include <babeltrace/graph/component-class-sink.h>
 #include <babeltrace/graph/component-class-source.h>
 #include <babeltrace/graph/component-class.h>
diff --git a/include/babeltrace/graph/component-class-sink-colander.h b/include/babeltrace/graph/component-class-sink-colander.h
new file mode 100644 (file)
index 0000000..2a21603
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
+#define BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_component_class;
+
+extern struct bt_component_class *bt_component_class_sink_colander_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H */
index 76fce36fdc93bfa3d7645d0a14d8f690a56271b8..fcfd0c502c7c0f013561e28e19b8703cddae59e0 100644 (file)
@@ -34,7 +34,7 @@ extern "C" {
 struct bt_component_class;
 
 typedef enum bt_component_status (*bt_component_class_sink_consume_method)(
-        struct bt_private_component *private_component);
+       struct bt_private_component *private_component);
 
 extern
 struct bt_component_class *bt_component_class_sink_create(const char *name,
index a3671a1970c22d845810d7a56673c2b1e147c8ee..6999094398bc452644bd8348192c388ae8f8309d 100644 (file)
@@ -13,7 +13,8 @@ libgraph_la_SOURCES = \
        source.c \
        sink.c \
        filter.c \
-       iterator.c
+       iterator.c \
+       component-class-sink-colander.c
 
 libgraph_la_LIBADD = \
        notification/libgraph-notification.la
diff --git a/lib/graph/component-class-sink-colander.c b/lib/graph/component-class-sink-colander.c
new file mode 100644 (file)
index 0000000..0d83e5d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COLANDER"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/graph/component-class-sink.h>
+#include <babeltrace/graph/private-component-sink.h>
+#include <babeltrace/graph/private-port.h>
+#include <babeltrace/graph/private-connection.h>
+#include <glib.h>
+#include <assert.h>
+
+static
+struct bt_component_class *colander_comp_cls;
+
+struct colander_data {
+       struct bt_notification **user_notif;
+       struct bt_notification_iterator *notif_iter;
+};
+
+static
+enum bt_component_status colander_init(
+               struct bt_private_component *priv_comp,
+               struct bt_value *params, void *init_method_data)
+{
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
+       struct colander_data *colander_data = NULL;
+
+       if (!init_method_data) {
+               BT_LOGW_STR("Component initialization method data is NULL.");
+               status = BT_COMPONENT_STATUS_INVALID;
+               goto end;
+       }
+
+       colander_data = g_new0(struct colander_data, 1);
+       if (!colander_data) {
+               BT_LOGE_STR("Failed to allocate colander data.");
+               status = BT_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       colander_data->user_notif = init_method_data;
+       status = bt_private_component_sink_add_input_private_port(
+               priv_comp, "in", NULL, NULL);
+       if (status != BT_COMPONENT_STATUS_OK) {
+               BT_LOGE_STR("Cannot add input port.");
+               goto end;
+       }
+
+       (void) bt_private_component_set_user_data(priv_comp, colander_data);
+
+end:
+       return status;
+}
+
+static
+void colander_finalize(struct bt_private_component *priv_comp)
+{
+       struct colander_data *colander_data =
+               bt_private_component_get_user_data(priv_comp);
+
+       if (!colander_data) {
+               return;
+       }
+
+       if (colander_data->notif_iter) {
+               bt_put(colander_data->notif_iter);
+       }
+
+       g_free(colander_data);
+}
+
+static
+void colander_port_connected(struct bt_private_component *priv_comp,
+               struct bt_private_port *self_priv_port,
+               struct bt_port *other_port)
+{
+       enum bt_connection_status conn_status;
+       struct bt_private_connection *priv_conn =
+               bt_private_port_get_private_connection(self_priv_port);
+       struct colander_data *colander_data =
+               bt_private_component_get_user_data(priv_comp);
+
+       assert(priv_conn);
+       assert(colander_data);
+       BT_PUT(colander_data->notif_iter);
+       conn_status = bt_private_connection_create_notification_iterator(
+               priv_conn, NULL, &colander_data->notif_iter);
+       if (conn_status) {
+               BT_LOGE("Cannot create notification iterator from connection: "
+                       "comp-addr=%p, conn-addr=%p", priv_comp, priv_conn);
+               goto end;
+       }
+
+end:
+       bt_put(priv_conn);
+}
+
+static
+enum bt_component_status colander_consume(
+               struct bt_private_component *priv_comp)
+{
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
+       enum bt_notification_iterator_status notif_iter_status;
+       struct bt_notification *notif = NULL;
+       struct colander_data *colander_data =
+               bt_private_component_get_user_data(priv_comp);
+
+       assert(colander_data);
+
+       if (!colander_data->notif_iter) {
+               BT_LOGW("Trying to consume without an upstream notification iterator: "
+                       "comp-addr=%p", priv_comp);
+               goto end;
+       }
+
+       notif_iter_status = bt_notification_iterator_next(
+               colander_data->notif_iter);
+       switch (notif_iter_status) {
+       case BT_NOTIFICATION_ITERATOR_STATUS_CANCELED:
+               status = BT_COMPONENT_STATUS_OK;
+               goto end;
+       case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
+               status = BT_COMPONENT_STATUS_AGAIN;
+               goto end;
+       case BT_NOTIFICATION_ITERATOR_STATUS_END:
+               status = BT_COMPONENT_STATUS_END;
+               goto end;
+       case BT_NOTIFICATION_ITERATOR_STATUS_OK:
+               break;
+       default:
+               status = BT_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       notif = bt_notification_iterator_get_notification(
+               colander_data->notif_iter);
+       assert(notif);
+
+end:
+       /* Move notification to user's pointer, even if NULL. */
+       *colander_data->user_notif = notif;
+       return status;
+}
+
+struct bt_component_class *bt_component_class_sink_colander_get(void)
+{
+       if (colander_comp_cls) {
+               goto end;
+       }
+
+       colander_comp_cls = bt_component_class_sink_create("colander",
+               colander_consume);
+       if (!colander_comp_cls) {
+               BT_LOGE_STR("Cannot create sink colander component class.");
+               goto end;
+       }
+
+       (void) bt_component_class_set_init_method(colander_comp_cls,
+               colander_init);
+       (void) bt_component_class_set_finalize_method(colander_comp_cls,
+               colander_finalize);
+       (void) bt_component_class_set_port_connected_method(colander_comp_cls,
+               colander_port_connected);
+       (void) bt_component_class_freeze(colander_comp_cls);
+
+end:
+       return bt_get(colander_comp_cls);
+}
+
+__attribute__((destructor)) static
+void put_colander(void) {
+       BT_PUT(colander_comp_cls);
+}
This page took 0.030168 seconds and 4 git commands to generate.