From 706a18f9d5d66f764b864085768dde24d342d308 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 4 Aug 2017 19:07:24 -0400 Subject: [PATCH] Add built-in colander sink component class MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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, ¬if, &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 Signed-off-by: Jérémie Galarneau --- include/Makefile.am | 1 + include/babeltrace/babeltrace.h | 1 + .../graph/component-class-sink-colander.h | 40 ++++ .../babeltrace/graph/component-class-sink.h | 2 +- lib/graph/Makefile.am | 3 +- lib/graph/component-class-sink-colander.c | 194 ++++++++++++++++++ 6 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 include/babeltrace/graph/component-class-sink-colander.h create mode 100644 lib/graph/component-class-sink-colander.c diff --git a/include/Makefile.am b/include/Makefile.am index f9293210..f1f86fcb 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 \ diff --git a/include/babeltrace/babeltrace.h b/include/babeltrace/babeltrace.h index 7aad9b1c..31fcb9aa 100644 --- a/include/babeltrace/babeltrace.h +++ b/include/babeltrace/babeltrace.h @@ -65,6 +65,7 @@ /* Graph, component, and notification API */ #include #include +#include #include #include #include diff --git a/include/babeltrace/graph/component-class-sink-colander.h b/include/babeltrace/graph/component-class-sink-colander.h new file mode 100644 index 00000000..2a21603e --- /dev/null +++ b/include/babeltrace/graph/component-class-sink-colander.h @@ -0,0 +1,40 @@ +#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H +#define BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H + +/* + * Copyright 2017 Philippe Proulx + * + * 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 + +#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 */ diff --git a/include/babeltrace/graph/component-class-sink.h b/include/babeltrace/graph/component-class-sink.h index 76fce36f..fcfd0c50 100644 --- a/include/babeltrace/graph/component-class-sink.h +++ b/include/babeltrace/graph/component-class-sink.h @@ -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, diff --git a/lib/graph/Makefile.am b/lib/graph/Makefile.am index a3671a19..69990943 100644 --- a/lib/graph/Makefile.am +++ b/lib/graph/Makefile.am @@ -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 index 00000000..0d83e5d3 --- /dev/null +++ b/lib/graph/component-class-sink-colander.c @@ -0,0 +1,194 @@ +/* + * Copyright 2017 Philippe Proulx + * + * 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 + +#include +#include +#include +#include +#include +#include + +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); +} -- 2.34.1