From f3e4505ba1b7bacce5fc1cc942f4cfaa905b4e74 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 14 Jul 2015 17:00:24 -0400 Subject: [PATCH] Start of bt_component_factory implementation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- converter/Makefile.am | 3 +- formats/lttng-live/lttng-live-comm.c | 11 +- include/babeltrace/babeltrace-internal.h | 12 + .../plugin/component-factory-internal.h | 26 +- include/babeltrace/plugin/component-factory.h | 61 +++- lib/prio_heap/prio_heap.c | 5 - plugins/Makefile.am | 1 + plugins/component-factory.c | 265 ++++++++++++++++++ 8 files changed, 363 insertions(+), 21 deletions(-) create mode 100644 plugins/component-factory.c diff --git a/converter/Makefile.am b/converter/Makefile.am index 47693f5a..1a6c0daf 100644 --- a/converter/Makefile.am +++ b/converter/Makefile.am @@ -17,7 +17,8 @@ babeltrace_LDADD = \ $(top_builddir)/formats/ctf-text/libbabeltrace-ctf-text.la \ $(top_builddir)/formats/ctf-metadata/libbabeltrace-ctf-metadata.la \ $(top_builddir)/formats/bt-dummy/libbabeltrace-dummy.la \ - $(top_builddir)/formats/lttng-live/libbabeltrace-lttng-live.la + $(top_builddir)/formats/lttng-live/libbabeltrace-lttng-live.la \ + $(top_builddir)/plugins/libbabeltrace-plugin.la if ENABLE_DEBUG_INFO babeltrace_LDADD += $(top_builddir)/lib/libdebug-info.la diff --git a/formats/lttng-live/lttng-live-comm.c b/formats/lttng-live/lttng-live-comm.c index fef374a3..6c5d4fd2 100644 --- a/formats/lttng-live/lttng-live-comm.c +++ b/formats/lttng-live/lttng-live-comm.c @@ -53,22 +53,13 @@ #include #include #include +#include #include "lttng-live.h" #include "lttng-viewer-abi.h" #define ACTIVE_POLL_DELAY 100 /* ms */ -/* - * Memory allocation zeroed - */ -#define zmalloc(x) calloc(1, x) - -#ifndef max_t -#define max_t(type, a, b) \ - ((type) (a) > (type) (b) ? (type) (a) : (type) (b)) -#endif - static void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, int whence); static int add_traces(struct lttng_live_ctx *ctx); diff --git a/include/babeltrace/babeltrace-internal.h b/include/babeltrace/babeltrace-internal.h index 6384eee0..9a91ba46 100644 --- a/include/babeltrace/babeltrace-internal.h +++ b/include/babeltrace/babeltrace-internal.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #define PERROR_BUFLEN 200 @@ -159,6 +161,16 @@ extern int babeltrace_verbose, babeltrace_debug; #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef max_t +#define max_t(type, a, b) \ + ((type) (a) > (type) (b) ? (type) (a) : (type) (b)) +#endif + +/* + * Memory allocation zeroed + */ +#define zmalloc(x) calloc(1, x) + /* * BT_HIDDEN: set the hidden attribute for internal functions */ diff --git a/include/babeltrace/plugin/component-factory-internal.h b/include/babeltrace/plugin/component-factory-internal.h index 0508cd86..3149bad3 100644 --- a/include/babeltrace/plugin/component-factory-internal.h +++ b/include/babeltrace/plugin/component-factory-internal.h @@ -28,11 +28,33 @@ */ #include -#include +#include +#include #include +#include +#include + +struct component_entry { + enum bt_component_type type; + GString *name; +}; + +struct source_component_entry { + struct component_entry parent; + bt_component_source_init_cb init; + +}; + +struct sink_component_entry { + struct component_entry parent; + bt_component_sink_init_cb init; +}; struct bt_component_factory { - int a; + /** Array of GModule pointers */ + GPtrArray *modules; + /** Array of pointers to struct component_entry */ + GPtrArray *components; }; #endif /* BABELTRACE_PLUGIN_COMPONENT_FACTORY_INTERNAL_H */ diff --git a/include/babeltrace/plugin/component-factory.h b/include/babeltrace/plugin/component-factory.h index 350bf72d..ded452f1 100644 --- a/include/babeltrace/plugin/component-factory.h +++ b/include/babeltrace/plugin/component-factory.h @@ -35,18 +35,73 @@ extern "C" { #endif +/** + * Status code. Errors are always negative. + */ +enum bt_component_factory_status { + /** General error. */ + BT_COMPONENT_FACTORY_STATUS_ERROR = -128, + + /** Invalid arguments. */ + /* -22 for compatibility with -EINVAL */ + BT_COMPONENT_FACTORY_STATUS_INVAL = -22, + + /** Memory allocation failure. */ + /* -12 for compatibility with -ENOMEM */ + BT_COMPONENT_FACTORY_STATUS_NOMEM = -12, + + /** I/O error. */ + /* -5 for compatibility with -EIO */ + BT_COMPONENT_FACTORY_STATUS_IO = -5, + + /** No such file or directory. */ + /* -2 for compatibility with -ENOENT */ + BT_COMPONENT_FACTORY_STATUS_NOENT = -2, + + /** Operation not permitted. */ + /* -1 for compatibility with -EPERM */ + BT_COMPONENT_FACTORY_STATUS_PERM = -1, + + /** No error, okay. */ + BT_COMPONENT_FACTORY_STATUS_OK = 0, +}; + struct bt_component_factory; -enum bt_component_status bt_component_factory_create(const char *path); +/** + * Create a component factory. + * + * @returns An instance of component factory + */ +extern +struct bt_component_factory *bt_component_factory_create(void); + +/** + * Recursively load and register Babeltrace plugins under a given path. + * + * Path will be traversed recursively if it is a directory, otherwise only the + * provided file will be loaded. + * + * @param factory A component factory instance + * @param path A path to a file or directory + * @returns One of #bt_component_factory_status values + */ +extern +enum bt_component_factory_status bt_component_factory_load( + struct bt_component_factory *factory, const char *path); -enum bt_component_status bt_component_factory_register_source_component_class( +extern +enum bt_component_factory_status +bt_component_factory_register_source_component_class( struct bt_component_factory *factory, const char *name, bt_component_source_init_cb init); -enum bt_component_status bt_component_factory_register_sink_component_class( +extern +enum bt_component_factory_status bt_component_factory_register_sink_component_class( struct bt_component_factory *factory, const char *name, bt_component_sink_init_cb init); +extern void bt_component_factory_destroy(struct bt_component_factory *factory); #ifdef __cplusplus diff --git a/lib/prio_heap/prio_heap.c b/lib/prio_heap/prio_heap.c index 8942a113..58e3de68 100644 --- a/lib/prio_heap/prio_heap.c +++ b/lib/prio_heap/prio_heap.c @@ -32,11 +32,6 @@ #include #include -#ifndef max_t -#define max_t(type, a, b) \ - ((type) (a) > (type) (b) ? (type) (a) : (type) (b)) -#endif - #ifdef DEBUG_HEAP void check_heap(const struct ptr_heap *heap) { diff --git a/plugins/Makefile.am b/plugins/Makefile.am index ec8248ff..53b9ec32 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -7,6 +7,7 @@ lib_LTLIBRARIES = libbabeltrace-plugin.la # Plug-in system library libbabeltrace_plugin_la_SOURCES = \ component.c \ + component-factory.c \ source.c \ sink.c \ iterator.c diff --git a/plugins/component-factory.c b/plugins/component-factory.c new file mode 100644 index 00000000..b4ebe3f2 --- /dev/null +++ b/plugins/component-factory.c @@ -0,0 +1,265 @@ +/* + * component-factory.c + * + * Babeltrace Plugin Component Factory + * + * Copyright 2015 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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 +#include +#include +#include +#include +#include +#include + +#define NATIVE_PLUGIN_SUFFIX ".so" +#define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX) +#define LIBTOOL_PLUGIN_SUFFIX ".la" +#define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX) +#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX),\ + sizeof(LIBTOOL_PLUGIN_SUFFIX)) + +static +void module_close(gpointer data) +{ + if (g_module_close((GModule *) data)) { + printf_error("Failed to close plugin"); + } +} + +static +void factory_destroy(gpointer data) +{ + bt_component_factory_destroy((struct bt_component_factory *)data); +} + +/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */ +static +struct dirent *alloc_dirent(const char *path) +{ + size_t len; + long name_max; + struct dirent *entry; + + name_max = pathconf(path, _PC_NAME_MAX); + if (name_max == -1) { + name_max = PATH_MAX; + } + len = offsetof(struct dirent, d_name) + name_max + 1; + entry = zmalloc(len); + return entry; +} + +static +enum bt_component_factory_status +bt_component_factory_load_file(struct bt_component_factory *factory, + const char *path) +{ + enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; + size_t path_len; + GModule *module; + + if (!factory || !path) { + ret = BT_COMPONENT_FACTORY_STATUS_INVAL; + goto end; + } + + path_len = strlen(path); + if (path_len <= PLUGIN_SUFFIX_LEN) { + goto end; + } + + path_len++; + /* + * Check if the file ends with a known plugin file type suffix (i.e. .so + * or .la on Linux). + */ + if (strncmp(NATIVE_PLUGIN_SUFFIX, + path + path_len - NATIVE_PLUGIN_SUFFIX_LEN, + NATIVE_PLUGIN_SUFFIX_LEN) && + strncmp(LIBTOOL_PLUGIN_SUFFIX, + path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN, + LIBTOOL_PLUGIN_SUFFIX_LEN)) { + /* Not a plugin file. */ + goto end; + } + + module = g_module_open(path, 0); + if (!module) { + printf_error("Module open error: %s", g_module_error()); + goto end; + } + + /* Check if the module defines the appropriate entry points */ +end: + return ret; +} + +static +enum bt_component_factory_status +bt_component_factory_load_dir_recursive(struct bt_component_factory *factory, + const char *path) +{ + DIR *directory = NULL; + struct dirent *entry = NULL, *result = NULL; + char *file_path = NULL; + size_t path_len = strlen(path); + enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; + + if (path_len >= PATH_MAX) { + ret = BT_COMPONENT_FACTORY_STATUS_INVAL; + goto end; + } + + entry = alloc_dirent(path); + if (!entry) { + ret = BT_COMPONENT_FACTORY_STATUS_NOMEM; + goto end; + } + + file_path = zmalloc(PATH_MAX); + if (!file_path) { + ret = BT_COMPONENT_FACTORY_STATUS_NOMEM; + goto end; + } + + strncpy(file_path, path, path_len); + /* Append a trailing '/' to the path */ + if (file_path[path_len - 1] != '/') { + file_path[path_len++] = '/'; + } + + /* Recursively walk directory */ + while (!readdir_r(directory, entry, &result) && result) { + struct stat st; + int stat_ret; + size_t file_name_len = strlen(result->d_name); + + if (path_len + file_name_len >= PATH_MAX) { + continue; + } + + strncpy(file_path + path_len, result->d_name, file_name_len); + file_path[path_len + file_name_len] = '\0'; + + stat_ret = stat(file_path, &st); + if (stat_ret < 0) { + /* Continue to next file / directory. */ + printf_perror("Failed to stat() plugin file"); + continue; + } + + if (S_ISDIR(st.st_mode)) { + ret = bt_component_factory_load_dir_recursive(factory, + file_path); + if (ret != BT_COMPONENT_FACTORY_STATUS_OK) { + goto end; + } + } else if (S_ISREG(st.st_mode)) { + ret = bt_component_factory_load_file(factory, + file_path); + if (ret != BT_COMPONENT_FACTORY_STATUS_OK) { + goto end; + } + } + } +end: + free(entry); + free(file_path); + return ret; +} + +void bt_component_factory_destroy(struct bt_component_factory *factory) +{ + if (!factory) { + return; + } + + g_free(factory); +} + +struct bt_component_factory * +bt_component_factory_create(void) +{ + struct bt_component_factory *factory; + + factory = g_new0(struct bt_component_factory, 1); + if (!factory) { + goto end; + } + + factory->modules = g_ptr_array_new_with_free_func(module_close); + if (!factory->modules) { + goto error; + } + + factory->components = g_ptr_array_new_with_free_func(factory_destroy); + if (factory->components) { + goto error; + } +end: + return factory; +error: + bt_component_factory_destroy(factory); + return NULL; +} + +enum bt_component_factory_status bt_component_factory_load( + struct bt_component_factory *factory, const char *path) +{ + enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; + DIR *directory = NULL; + + if (!factory || !path) { + ret = BT_COMPONENT_FACTORY_STATUS_INVAL; + goto end; + } + + directory = opendir(path) ; + if (!directory) { + switch (errno) { + case ENOTDIR: + /* Try loading as a file. */ + break; + case ENOENT: + ret = BT_COMPONENT_FACTORY_STATUS_NOENT; + goto end; + default: + ret = BT_COMPONENT_FACTORY_STATUS_IO; + goto end; + } + } + + if (directory) { + ret = bt_component_factory_load_dir_recursive(factory, path); + } else { + ret = bt_component_factory_load_file(factory, path); + } +end: + if (directory) { + closedir(directory); + } + return ret; +} -- 2.34.1