X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fplugin%2Fplugin.c;h=a6e9806d21f77a26fcb8b61cd71e0c3cf7f3c808;hb=d9676d8c5afce3c35d282fb5053a9bbc7427526b;hp=3395da8d599f596e33e6cc79dfdc1616bf18aaf2;hpb=aea50fe84219314aa9c096283abae507e48b4c5d;p=babeltrace.git diff --git a/lib/plugin/plugin.c b/lib/plugin/plugin.c index 3395da8d..a6e9806d 100644 --- a/lib/plugin/plugin.c +++ b/lib/plugin/plugin.c @@ -1,10 +1,6 @@ /* - * plugin.c - * - * Babeltrace Plugin - * + * Copyright 2017-2018 Philippe Proulx * Copyright 2016 Jérémie Galarneau - * Copyright 2017 Philippe Proulx * * Author: Jérémie Galarneau * @@ -27,1201 +23,612 @@ * SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include +#define BT_LOG_TAG "PLUGIN" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#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) +#include +#include -#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \ - sizeof(LIBTOOL_PLUGIN_SUFFIX)) +#define PYTHON_PLUGIN_PROVIDER_FILENAME "libbabeltrace2-python-plugin-provider." G_MODULE_SUFFIX +#define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file +#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME) -#define SECTION_BEGIN(_name) (&(__start_##_name)) -#define SECTION_END(_name) (&(__stop_##_name)) -#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name)) +#define APPEND_ALL_FROM_DIR_NFDOPEN_MAX 8 -#define DECLARE_SECTION(_type, _name) \ - extern _type __start_##_name __attribute((weak)); \ - extern _type __stop_##_name __attribute((weak)) +#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT +#include -DECLARE_SECTION(struct __bt_plugin_descriptor const *, __bt_plugin_descriptors); -DECLARE_SECTION(struct __bt_plugin_descriptor_attribute const *, __bt_plugin_descriptor_attributes); -DECLARE_SECTION(struct __bt_plugin_component_class_descriptor const *, __bt_plugin_component_class_descriptors); -DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute const *, __bt_plugin_component_class_descriptor_attributes); - -/* - * This hash table, global to the library, maps component class pointers - * to shared library handles. - * - * The keys (component classes) are NOT owned by this hash table, whereas - * the values (shared library handles) are owned by this hash table. - * - * The keys are the component classes created with - * bt_plugin_add_component_class(). They keep the shared library handle - * object created by their plugin alive so that the plugin's code is - * not discarded when it could still be in use by living components - * created from those component classes: - * - * [component] --ref-> [component class] --through this HT-> [shlib handle] - * - * This hash table exists for two reasons: - * - * 1. To allow this application: - * - * my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so"); - * // instantiate components from a plugin's component classes - * // put plugins and free my_plugins here - * // user code of instantiated components still exists - * - * 2. To decouple the plugin subsystem from the component subsystem: - * while plugins objects need to know component class objects, the - * opposite is not necessary, thus it makes no sense for a component - * class to keep a reference to the plugin object from which it was - * created. - * - * An entry is removed from this HT when a component class is destroyed - * thanks to a custom destroy listener. When the entry is removed, the - * GLib function calls the value destroy notifier of the HT, which is - * bt_put(). This decreases the reference count of the mapped shared - * library handle. Assuming the original plugin object which contained - * some component classes is put first, when the last component class is - * removed from this HT, the shared library handle object's reference - * count falls to zero and the shared library is finally closed. - */ static -GHashTable *comp_classes_to_shlib_handles; +struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) = + bt_plugin_python_create_all_from_file; -__attribute__((constructor)) static -void init_comp_classes_to_shlib_handles(void) { - comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, bt_put); - assert(comp_classes_to_shlib_handles); -} +static +void init_python_plugin_provider(void) {} +#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */ +static GModule *python_plugin_provider_module; +static +struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path); -__attribute__((destructor)) static -void fini_comp_classes_to_shlib_handles(void) { - if (comp_classes_to_shlib_handles) { - g_hash_table_destroy(comp_classes_to_shlib_handles); +static +void init_python_plugin_provider(void) { + if (bt_plugin_python_create_all_from_file_sym != NULL) { + return; } -} -static -void bt_plugin_shared_lib_handle_destroy(struct bt_object *obj) -{ - struct bt_plugin_shared_lib_handle *shared_lib_handle; + BT_LOGD_STR("Loading Python plugin provider module."); + python_plugin_provider_module = + g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME, 0); + if (!python_plugin_provider_module) { + BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.", + PYTHON_PLUGIN_PROVIDER_FILENAME, g_module_error()); + return; + } - assert(obj); - shared_lib_handle = container_of(obj, - struct bt_plugin_shared_lib_handle, base); + if (!g_module_symbol(python_plugin_provider_module, + PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR, + (gpointer) &bt_plugin_python_create_all_from_file_sym)) { + BT_LOGI("Cannot find the Python plugin provider loading symbol: continuing without Python plugin support: " + "file=\"%s\", symbol=\"%s\"", + PYTHON_PLUGIN_PROVIDER_FILENAME, + PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR); + return; + } - if (shared_lib_handle->init_called && shared_lib_handle->exit) { - enum bt_plugin_status status = shared_lib_handle->exit(); + BT_LOGI("Loaded Python plugin provider module: addr=%p", + python_plugin_provider_module); +} - if (status < 0) { - const char *path = shared_lib_handle->path ? - shared_lib_handle->path->str : "[built-in]"; +__attribute__((destructor)) static +void fini_python_plugin_provider(void) { + if (python_plugin_provider_module) { + BT_LOGD("Unloading Python plugin provider module."); - printf_verbose("Plugin in module `%s` exited with error %d\n", - path, status); + if (!g_module_close(python_plugin_provider_module)) { + BT_LOGE("Failed to close the Python plugin provider module: %s.", + g_module_error()); } - } - if (shared_lib_handle->module) { - if (!g_module_close(shared_lib_handle->module)) { - printf_error("Module close error: %s\n", - g_module_error()); - } + python_plugin_provider_module = NULL; } +} +#endif - if (shared_lib_handle->path) { - g_string_free(shared_lib_handle->path, TRUE); - } +uint64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set) +{ + BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set"); + return (uint64_t) plugin_set->plugins->len; +} - g_free(shared_lib_handle); +const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const( + const struct bt_plugin_set *plugin_set, uint64_t index) +{ + BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set"); + BT_ASSERT_PRE_VALID_INDEX(index, plugin_set->plugins->len); + return g_ptr_array_index(plugin_set->plugins, index); } -static -struct bt_plugin_shared_lib_handle *bt_plugin_shared_lib_handle_create( - const char *path) +const struct bt_plugin_set *bt_plugin_find_all_from_static(void) { - struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL; + /* bt_plugin_so_create_all_from_static() logs errors */ + return bt_plugin_so_create_all_from_static(); +} - shared_lib_handle = g_new0(struct bt_plugin_shared_lib_handle, 1); - if (!shared_lib_handle) { - goto error; - } +const struct bt_plugin_set *bt_plugin_find_all_from_file(const char *path) +{ + struct bt_plugin_set *plugin_set = NULL; - bt_object_init(shared_lib_handle, bt_plugin_shared_lib_handle_destroy); + BT_ASSERT_PRE_NON_NULL(path, "Path"); + BT_LOGD("Creating plugins from file: path=\"%s\"", path); - if (!path) { + /* Try shared object plugins */ + plugin_set = bt_plugin_so_create_all_from_file(path); + if (plugin_set) { goto end; } - shared_lib_handle->path = g_string_new(path); - if (!shared_lib_handle->path) { - goto error; - } - - shared_lib_handle->module = g_module_open(path, 0); - if (!shared_lib_handle->module) { - printf_verbose("Module open error: %s\n", g_module_error()); - goto error; + /* Try Python plugins if support is available */ + init_python_plugin_provider(); + if (bt_plugin_python_create_all_from_file_sym) { + plugin_set = bt_plugin_python_create_all_from_file_sym(path); + if (plugin_set) { + goto end; + } } - goto end; - -error: - BT_PUT(shared_lib_handle); - end: - return shared_lib_handle; -} - -static -void bt_plugin_destroy(struct bt_object *obj) -{ - struct bt_plugin *plugin; - - assert(obj); - plugin = container_of(obj, struct bt_plugin, base); - - BT_PUT(plugin->shared_lib_handle); - - if (plugin->comp_classes) { - g_ptr_array_free(plugin->comp_classes, TRUE); + if (plugin_set) { + BT_LOGD("Created %u plugins from file: " + "path=\"%s\", count=%u, plugin-set-addr=%p", + plugin_set->plugins->len, path, + plugin_set->plugins->len, plugin_set); + } else { + BT_LOGD("Found no plugins in file: path=\"%s\"", path); } - g_free(plugin); + return plugin_set; } -static -struct bt_plugin *bt_plugin_create_empty( - struct bt_plugin_shared_lib_handle *shared_lib_handle) +static void destroy_gstring(void *data) { - struct bt_plugin *plugin = NULL; - - plugin = g_new0(struct bt_plugin, 1); - if (!plugin) { - goto error; - } - - bt_object_init(plugin, bt_plugin_destroy); - plugin->shared_lib_handle = bt_get(shared_lib_handle); - - /* Create empty array of component classes */ - plugin->comp_classes = - g_ptr_array_new_with_free_func((GDestroyNotify) bt_put); - if (!plugin->comp_classes) { - goto error; - } - - goto end; - -error: - BT_PUT(plugin); - -end: - return plugin; + g_string_free(data, TRUE); } -/* - * This function does the following: - * - * 1. Iterate on the plugin descriptor attributes section and set the - * plugin's attributes depending on the attribute types. This - * includes the name of the plugin, its description, and its - * initialization function, for example. - * - * 2. Iterate on the component class descriptors section and create one - * "full descriptor" (temporary structure) for each one that is found - * and attached to our plugin descriptor. - * - * 3. Iterate on the component class descriptor attributes section and - * set the corresponding full descriptor's attributes depending on - * the attribute types. This includes the description of the - * component class, as well as its initialization and destroy - * methods. - * - * 4. Call the user's plugin initialization function, if any is - * defined. - * - * 5. For each full component class descriptor, create a component class - * object, set its optional attributes, and add it to the plugin - * object. - * - * 6. Freeze the plugin object. - */ -static -enum bt_plugin_status bt_plugin_init( - struct bt_plugin *plugin, - const struct __bt_plugin_descriptor *descriptor, - struct __bt_plugin_descriptor_attribute const * const *attrs_begin, - struct __bt_plugin_descriptor_attribute const * const *attrs_end, - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin, - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end, - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin, - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end) +const struct bt_plugin *bt_plugin_find(const char *plugin_name) { - /* - * This structure's members point to the plugin's memory - * (do NOT free). - */ - struct comp_class_full_descriptor { - const struct __bt_plugin_component_class_descriptor *descriptor; - const char *description; - bt_component_class_init_method init_method; - bt_component_class_destroy_method destroy_method; - bt_component_class_filter_add_iterator_method filter_add_iterator_method; - bt_component_class_sink_add_iterator_method sink_add_iterator_method; - struct bt_component_class_iterator_methods iterator_methods; - }; - - enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; - struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr; - struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr; - struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr; - GArray *comp_class_full_descriptors; - size_t i; + const char *system_plugin_dir; + char *home_plugin_dir = NULL; + const char *envvar; + const struct bt_plugin *plugin = NULL; + const struct bt_plugin_set *plugin_set = NULL; + GPtrArray *dirs = NULL; int ret; - - comp_class_full_descriptors = g_array_new(FALSE, TRUE, - sizeof(struct comp_class_full_descriptor)); - if (!comp_class_full_descriptors) { - status = BT_PLUGIN_STATUS_ERROR; + size_t i, j; + + BT_ASSERT_PRE_NON_NULL(plugin_name, "Name"); + BT_LOGD("Finding named plugin in standard directories and built-in plugins: " + "name=\"%s\"", plugin_name); + dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring); + if (!dirs) { + BT_LOGE_STR("Failed to allocate a GPtrArray."); goto end; } - /* Set mandatory attributes */ - plugin->descriptor = descriptor; - plugin->name = descriptor->name; - /* - * Find and set optional attributes attached to this plugin - * descriptor. + * Search order is: + * + * 1. BABELTRACE_PLUGIN_PATH environment variable + * (colon-separated list of directories) + * 2. ~/.local/lib/babeltrace2/plugins + * 3. Default system directory for Babeltrace plugins, usually + * /usr/lib/babeltrace2/plugins or + * /usr/local/lib/babeltrace2/plugins if installed + * locally + * 4. Built-in plugins (static) + * + * Directories are searched non-recursively. */ - for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) { - const struct __bt_plugin_descriptor_attribute *cur_attr = - *cur_attr_ptr; - - if (cur_attr->plugin_descriptor != descriptor) { - continue; - } - - switch (cur_attr->type) { - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT: - plugin->init = cur_attr->value.init; - break; - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT: - plugin->shared_lib_handle->exit = cur_attr->value.exit; - break; - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR: - plugin->author = cur_attr->value.author; - break; - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE: - plugin->license = cur_attr->value.license; - break; - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION: - plugin->description = cur_attr->value.description; - break; - case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION: - plugin->version = &cur_attr->value.version; - break; - default: - printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n", - cur_attr->type_name, cur_attr->type, - descriptor->name); - break; + envvar = getenv("BABELTRACE_PLUGIN_PATH"); + if (envvar) { + ret = bt_common_append_plugin_path_dirs(envvar, dirs); + if (ret) { + BT_LOGE_STR("Failed to append plugin path to array of directories."); + goto end; } } - /* - * Find component class descriptors attached to this plugin - * descriptor and initialize corresponding full component class - * descriptors in the array. - */ - for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) { - const struct __bt_plugin_component_class_descriptor *cur_cc_descr = - *cur_cc_descr_ptr; - struct comp_class_full_descriptor full_descriptor = {0}; + home_plugin_dir = bt_common_get_home_plugin_path(); + if (home_plugin_dir) { + GString *home_plugin_dir_str = + g_string_new(home_plugin_dir); - if (cur_cc_descr->plugin_descriptor != descriptor) { - continue; + if (!home_plugin_dir_str) { + BT_LOGE_STR("Failed to allocate a GString."); + goto end; } - full_descriptor.descriptor = cur_cc_descr; - g_array_append_val(comp_class_full_descriptors, - full_descriptor); + g_ptr_array_add(dirs, home_plugin_dir_str); } - /* - * Find component class descriptor attributes attached to this - * plugin descriptor and update corresponding full component - * class descriptors in the array. - */ - for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) { - const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr = - *cur_cc_descr_attr_ptr; + system_plugin_dir = bt_common_get_system_plugin_path(); + if (system_plugin_dir) { + GString *system_plugin_dir_str = + g_string_new(system_plugin_dir); - if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor != - descriptor) { - continue; + if (!system_plugin_dir_str) { + BT_LOGE_STR("Failed to allocate a GString."); + goto end; } - /* Find the corresponding component class descriptor entry */ - for (i = 0; i < comp_class_full_descriptors->len; i++) { - struct comp_class_full_descriptor *cc_full_descr = - &g_array_index(comp_class_full_descriptors, - struct comp_class_full_descriptor, i); - - if (cur_cc_descr_attr->comp_class_descriptor == - cc_full_descr->descriptor) { - switch (cur_cc_descr_attr->type) { - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION: - cc_full_descr->description = - cur_cc_descr_attr->value.description; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD: - cc_full_descr->init_method = - cur_cc_descr_attr->value.init_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD: - cc_full_descr->destroy_method = - cur_cc_descr_attr->value.destroy_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD: - cc_full_descr->filter_add_iterator_method = - cur_cc_descr_attr->value.filter_add_iterator_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD: - cc_full_descr->sink_add_iterator_method = - cur_cc_descr_attr->value.sink_add_iterator_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD: - cc_full_descr->iterator_methods.init = - cur_cc_descr_attr->value.notif_iter_init_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_DESTROY_METHOD: - cc_full_descr->iterator_methods.destroy = - cur_cc_descr_attr->value.notif_iter_destroy_method; - break; - case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD: - cc_full_descr->iterator_methods.seek_time = - cur_cc_descr_attr->value.notif_iter_seek_time_method; - break; - default: - printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n", - cur_cc_descr_attr->type_name, - cur_cc_descr_attr->type, - cur_cc_descr_attr->comp_class_descriptor->name, - cur_cc_descr_attr->comp_class_descriptor->type, - descriptor->name); - break; - } - } - } + g_ptr_array_add(dirs, system_plugin_dir_str); } - /* Initialize plugin */ - if (plugin->init) { - status = plugin->init(plugin); - if (status < 0) { - printf_verbose("Plugin `%s` initialization error: %d\n", - plugin->name, status); - goto end; - } - } + for (i = 0; i < dirs->len; i++) { + GString *dir = g_ptr_array_index(dirs, i); - plugin->shared_lib_handle->init_called = true; - - /* Add described component classes to plugin */ - for (i = 0; i < comp_class_full_descriptors->len; i++) { - struct comp_class_full_descriptor *cc_full_descr = - &g_array_index(comp_class_full_descriptors, - struct comp_class_full_descriptor, i); - struct bt_component_class *comp_class; - - switch (cc_full_descr->descriptor->type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - comp_class = bt_component_class_source_create( - cc_full_descr->descriptor->name, - cc_full_descr->descriptor->methods.source.notif_iter_get, - cc_full_descr->descriptor->methods.source.notif_iter_next); - break; - case BT_COMPONENT_CLASS_TYPE_FILTER: - comp_class = bt_component_class_filter_create( - cc_full_descr->descriptor->name, - cc_full_descr->descriptor->methods.source.notif_iter_get, - cc_full_descr->descriptor->methods.source.notif_iter_next); - break; - case BT_COMPONENT_CLASS_TYPE_SINK: - comp_class = bt_component_class_sink_create( - cc_full_descr->descriptor->name, - cc_full_descr->descriptor->methods.sink.consume); - break; - default: - printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n", - cc_full_descr->descriptor->type, - cc_full_descr->descriptor->name, - descriptor->name); - continue; - } + BT_OBJECT_PUT_REF_AND_RESET(plugin_set); - if (!comp_class) { - status = BT_PLUGIN_STATUS_ERROR; - goto end; + /* + * Skip this if the directory does not exist because + * bt_plugin_find_all_from_dir() would log a warning. + */ + if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) { + BT_LOGV("Skipping nonexistent directory path: " + "path=\"%s\"", dir->str); + continue; } - if (cc_full_descr->description) { - ret = bt_component_class_set_description(comp_class, - cc_full_descr->description); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } + /* bt_plugin_find_all_from_dir() logs details/errors */ + plugin_set = bt_plugin_find_all_from_dir(dir->str, BT_FALSE); + if (!plugin_set) { + BT_LOGD("No plugins found in directory: path=\"%s\"", + dir->str); + continue; } - if (cc_full_descr->init_method) { - ret = bt_component_class_set_init_method(comp_class, - cc_full_descr->init_method); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } + for (j = 0; j < plugin_set->plugins->len; j++) { + const struct bt_plugin *candidate_plugin = + g_ptr_array_index(plugin_set->plugins, j); - if (cc_full_descr->destroy_method) { - ret = bt_component_class_set_destroy_method(comp_class, - cc_full_descr->destroy_method); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); + if (strcmp(bt_plugin_get_name(candidate_plugin), + plugin_name) == 0) { + BT_LOGD("Plugin found in directory: name=\"%s\", path=\"%s\"", + plugin_name, dir->str); + plugin = candidate_plugin; + bt_object_get_no_null_check(plugin); goto end; } } - switch (cc_full_descr->descriptor->type) { - case BT_COMPONENT_CLASS_TYPE_SOURCE: - if (cc_full_descr->iterator_methods.init) { - ret = bt_component_class_source_set_notification_iterator_init_method( - comp_class, - cc_full_descr->iterator_methods.init); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } - - if (cc_full_descr->iterator_methods.destroy) { - ret = bt_component_class_source_set_notification_iterator_destroy_method( - comp_class, - cc_full_descr->iterator_methods.destroy); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } - - if (cc_full_descr->iterator_methods.seek_time) { - ret = bt_component_class_source_set_notification_iterator_seek_time_method( - comp_class, - cc_full_descr->iterator_methods.seek_time); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } - break; - case BT_COMPONENT_CLASS_TYPE_FILTER: - if (cc_full_descr->filter_add_iterator_method) { - ret = bt_component_class_filter_set_add_iterator_method( - comp_class, - cc_full_descr->filter_add_iterator_method); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } - - if (cc_full_descr->iterator_methods.init) { - ret = bt_component_class_filter_set_notification_iterator_init_method( - comp_class, - cc_full_descr->iterator_methods.init); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } + BT_LOGD("Plugin not found in directory: name=\"%s\", path=\"%s\"", + plugin_name, dir->str); + } - if (cc_full_descr->iterator_methods.destroy) { - ret = bt_component_class_filter_set_notification_iterator_destroy_method( - comp_class, - cc_full_descr->iterator_methods.destroy); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } + bt_object_put_ref(plugin_set); + plugin_set = bt_plugin_find_all_from_static(); + if (plugin_set) { + for (j = 0; j < plugin_set->plugins->len; j++) { + const struct bt_plugin *candidate_plugin = + g_ptr_array_index(plugin_set->plugins, j); - if (cc_full_descr->iterator_methods.seek_time) { - ret = bt_component_class_filter_set_notification_iterator_seek_time_method( - comp_class, - cc_full_descr->iterator_methods.seek_time); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } - } - break; - case BT_COMPONENT_CLASS_TYPE_SINK: - if (cc_full_descr->sink_add_iterator_method) { - ret = bt_component_class_sink_set_add_iterator_method( - comp_class, - cc_full_descr->sink_add_iterator_method); - if (ret) { - status = BT_PLUGIN_STATUS_ERROR; - BT_PUT(comp_class); - goto end; - } + if (strcmp(bt_plugin_get_name(candidate_plugin), + plugin_name) == 0) { + BT_LOGD("Plugin found in built-in plugins: " + "name=\"%s\"", plugin_name); + plugin = candidate_plugin; + bt_object_get_no_null_check(plugin); + goto end; } - break; - default: - assert(false); - break; - } - - /* Add component class to the plugin object */ - status = bt_plugin_add_component_class(plugin, - comp_class); - BT_PUT(comp_class); - if (status < 0) { - printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n", - cc_full_descr->descriptor->name, - cc_full_descr->descriptor->type, - plugin->name, status); - goto end; } } - /* - * All the plugin's component classes should be added at this - * point. We freeze the plugin so that it's not possible to add - * component classes to this plugin object after this stage - * (plugin object becomes immutable). - */ - plugin->frozen = true; - end: - g_array_free(comp_class_full_descriptors, TRUE); - return status; -} + free(home_plugin_dir); + bt_object_put_ref(plugin_set); -static -struct bt_plugin **bt_plugin_create_all_from_sections( - struct bt_plugin_shared_lib_handle *shared_lib_handle, - struct __bt_plugin_descriptor const * const *descriptors_begin, - struct __bt_plugin_descriptor const * const *descriptors_end, - struct __bt_plugin_descriptor_attribute const * const *attrs_begin, - struct __bt_plugin_descriptor_attribute const * const *attrs_end, - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin, - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end, - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin, - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end) -{ - size_t descriptor_count; - size_t attrs_count; - size_t cc_descriptors_count; - size_t cc_descr_attrs_count; - size_t i; - struct bt_plugin **plugins = NULL; - - descriptor_count = descriptors_end - descriptors_begin; - attrs_count = attrs_end - attrs_begin; - cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin; - cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin; - printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n", - descriptors_begin, descriptors_end, descriptor_count); - printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n", - attrs_begin, attrs_end, attrs_count); - printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n", - cc_descriptors_begin, cc_descriptors_end, cc_descriptors_count); - printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n", - cc_descr_attrs_begin, cc_descr_attrs_end, cc_descr_attrs_count); - plugins = calloc(descriptor_count + 1, sizeof(*plugins)); - if (!plugins) { - goto error; + if (dirs) { + g_ptr_array_free(dirs, TRUE); } - for (i = 0; i < descriptor_count; i++) { - enum bt_plugin_status status; - const struct __bt_plugin_descriptor *descriptor = - descriptors_begin[i]; - struct bt_plugin *plugin; - - printf_verbose("Loading plugin %s (ABI %d.%d)\n", descriptor->name, - descriptor->major, descriptor->minor); - - if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) { - printf_error("Unknown plugin's major version: %d\n", - descriptor->major); - goto error; - } - - plugin = bt_plugin_create_empty(shared_lib_handle); - if (!plugin) { - printf_error("Cannot allocate plugin object for plugin %s\n", - descriptor->name); - goto error; - } - - status = bt_plugin_init(plugin, descriptor, attrs_begin, - attrs_end, cc_descriptors_begin, cc_descriptors_end, - cc_descr_attrs_begin, cc_descr_attrs_end); - if (status < 0) { - printf_error("Cannot initialize plugin object %s\n", - descriptor->name); - BT_PUT(plugin); - goto error; - } - - /* Transfer ownership to the array */ - plugins[i] = plugin; + if (plugin) { + BT_LIB_LOGD("Found plugin in standard directories and built-in plugins: " + "%!+l", plugin); + } else { + BT_LOGD("No plugin found in standard directories and built-in plugins: " + "name=\"%s\"", plugin_name); } - goto end; - -error: - g_free(plugins); - plugins = NULL; - -end: - return plugins; + return plugin; } -struct bt_plugin **bt_plugin_create_all_from_static(void) -{ - struct bt_plugin **plugins = NULL; - struct bt_plugin_shared_lib_handle *shared_lib_handle = - bt_plugin_shared_lib_handle_create(NULL); - - if (!shared_lib_handle) { - goto end; - } - - plugins = bt_plugin_create_all_from_sections(shared_lib_handle, - SECTION_BEGIN(__bt_plugin_descriptors), - SECTION_END(__bt_plugin_descriptors), - SECTION_BEGIN(__bt_plugin_descriptor_attributes), - SECTION_END(__bt_plugin_descriptor_attributes), - SECTION_BEGIN(__bt_plugin_component_class_descriptors), - SECTION_END(__bt_plugin_component_class_descriptors), - SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes), - SECTION_END(__bt_plugin_component_class_descriptor_attributes)); - -end: - BT_PUT(shared_lib_handle); - - return plugins; -} +static struct { + pthread_mutex_t lock; + struct bt_plugin_set *plugin_set; + bool recurse; +} append_all_from_dir_info = { + .lock = PTHREAD_MUTEX_INITIALIZER +}; -struct bt_plugin **bt_plugin_create_all_from_file(const char *path) +static +int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag, + struct FTW *s) { - size_t path_len; - struct bt_plugin **plugins = NULL; - struct __bt_plugin_descriptor const * const *descriptors_begin = NULL; - struct __bt_plugin_descriptor const * const *descriptors_end = NULL; - struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL; - struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL; - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL; - struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL; - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL; - struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL; - bool is_libtool_wrapper = false, is_shared_object = false; - struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL; - - if (!path) { - goto end; - } + int ret = 0; + const char *name = file + s->base; - path_len = strlen(path); - if (path_len <= PLUGIN_SUFFIX_LEN) { + /* Check for recursion */ + if (!append_all_from_dir_info.recurse && s->level > 1) { goto end; } - path_len++; - /* - * Check if the file ends with a known plugin file type suffix (i.e. .so - * or .la on Linux). - */ - is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX, - path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN, - LIBTOOL_PLUGIN_SUFFIX_LEN); - is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX, - path + path_len - NATIVE_PLUGIN_SUFFIX_LEN, - NATIVE_PLUGIN_SUFFIX_LEN); - if (!is_shared_object && !is_libtool_wrapper) { - /* Name indicates that this is not a plugin file. */ - goto end; - } - - shared_lib_handle = bt_plugin_shared_lib_handle_create(path); - if (!shared_lib_handle) { - goto end; - } + switch (flag) { + case FTW_F: + { + const struct bt_plugin_set *plugins_from_file; - if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors", - (gpointer *) &descriptors_begin)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__start___bt_plugin_descriptors", - g_module_name(shared_lib_handle->module)); - goto end; - } - - if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors", - (gpointer *) &descriptors_end)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__stop___bt_plugin_descriptors", - g_module_name(shared_lib_handle->module)); - goto end; - } - - if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes", - (gpointer *) &attrs_begin)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__start___bt_plugin_descriptor_attributes", - g_module_name(shared_lib_handle->module)); - } - - if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes", - (gpointer *) &attrs_end)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__stop___bt_plugin_descriptor_attributes", - g_module_name(shared_lib_handle->module)); - } - - if ((!!attrs_begin - !!attrs_end) != 0) { - printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n", - g_module_name(shared_lib_handle->module)); - goto end; - } + if (name[0] == '.') { + /* Skip hidden files */ + BT_LOGV("Skipping hidden file: path=\"%s\"", file); + goto end; + } - if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors", - (gpointer *) &cc_descriptors_begin)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__start___bt_plugin_component_class_descriptors", - g_module_name(shared_lib_handle->module)); - } + plugins_from_file = bt_plugin_find_all_from_file(file); - if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors", - (gpointer *) &cc_descriptors_end)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__stop___bt_plugin_component_class_descriptors", - g_module_name(shared_lib_handle->module)); - } + if (plugins_from_file) { + size_t j; - if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) { - printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n", - g_module_name(shared_lib_handle->module)); - goto end; - } + for (j = 0; j < plugins_from_file->plugins->len; j++) { + struct bt_plugin *plugin = + g_ptr_array_index(plugins_from_file->plugins, j); - if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes", - (gpointer *) &cc_descr_attrs_begin)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__start___bt_plugin_component_class_descriptor_attributes", - g_module_name(shared_lib_handle->module)); - } + BT_LIB_LOGD("Adding plugin to plugin set: " + "plugin-path=\"%s\", %![plugin-]+l", + file, plugin); + bt_plugin_set_add_plugin( + append_all_from_dir_info.plugin_set, + plugin); + } - if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes", - (gpointer *) &cc_descr_attrs_end)) { - printf_verbose("Unable to resolve plugin symbol %s from %s\n", - "__stop___bt_plugin_component_class_descriptor_attributes", - g_module_name(shared_lib_handle->module)); + bt_object_put_ref(plugins_from_file); + } + break; } - - if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) { - printf_verbose("Found __start___bt_plugin_component_class_descriptor_attributes or __stop___bt_plugin_component_class_descriptor_attributes symbol, but not both in %s\n", - g_module_name(shared_lib_handle->module)); - goto end; + case FTW_DNR: + /* Continue to next file / directory. */ + BT_LOGW("Cannot enter directory: continuing: path=\"%s\"", file); + break; + case FTW_NS: + /* Continue to next file / directory. */ + BT_LOGD("Cannot get file information: continuing: path=\"%s\"", file); + break; } - /* Initialize plugin */ - plugins = bt_plugin_create_all_from_sections(shared_lib_handle, - descriptors_begin, descriptors_end, attrs_begin, attrs_end, - cc_descriptors_begin, cc_descriptors_end, - cc_descr_attrs_begin, cc_descr_attrs_end); - end: - BT_PUT(shared_lib_handle); - return plugins; -} - -/* 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; + return ret; } static enum bt_plugin_status bt_plugin_create_append_all_from_dir( - GPtrArray *plugins, const char *path, bool recurse) + struct bt_plugin_set *plugin_set, const char *path, + bt_bool recurse) { - DIR *directory = NULL; - struct dirent *entry = NULL, *result = NULL; - char *file_path = NULL; - size_t path_len; + int nftw_flags = FTW_PHYS; enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK; - if (!path) { + BT_ASSERT(plugin_set); + BT_ASSERT(path); + BT_ASSERT(strlen(path) < PATH_MAX); + pthread_mutex_lock(&append_all_from_dir_info.lock); + append_all_from_dir_info.plugin_set = plugin_set; + append_all_from_dir_info.recurse = recurse; + ret = nftw(path, nftw_append_all_from_dir, + APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags); + pthread_mutex_unlock(&append_all_from_dir_info.lock); + if (ret != 0) { + BT_LOGW_ERRNO("Cannot open directory", ": path=\"%s\"", path); ret = BT_PLUGIN_STATUS_ERROR; - goto end; } - path_len = strlen(path); - - if (path_len >= PATH_MAX) { - ret = BT_PLUGIN_STATUS_ERROR; - goto end; - } - - entry = alloc_dirent(path); - if (!entry) { - ret = BT_PLUGIN_STATUS_ERROR; - goto end; - } - - file_path = zmalloc(PATH_MAX); - if (!file_path) { - ret = BT_PLUGIN_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++] = '/'; - } - - directory = opendir(file_path); - if (!directory) { - perror("Failed to open plug-in directory"); - ret = BT_PLUGIN_STATUS_ERROR; - goto end; - } - - /* Recursively walk directory */ - while (!readdir_r(directory, entry, &result) && result) { - struct stat st; - int stat_ret; - size_t file_name_len; - - if (result->d_name[0] == '.') { - /* Skip hidden files, . and .. */ - continue; - } - - 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\n"); - continue; - } - - if (S_ISDIR(st.st_mode) && recurse) { - ret = bt_plugin_create_append_all_from_dir(plugins, - file_path, true); - if (ret < 0) { - goto end; - } - } else if (S_ISREG(st.st_mode)) { - struct bt_plugin **plugins_from_file = - bt_plugin_create_all_from_file(file_path); - - if (plugins_from_file) { - struct bt_plugin **plugin; - - for (plugin = plugins_from_file; *plugin; plugin++) { - /* Transfer ownership to array */ - g_ptr_array_add(plugins, *plugin); - } - - free(plugins_from_file); - } - } - } -end: - if (directory) { - if (closedir(directory)) { - /* - * We don't want to override the error since there is - * nothing could do. - */ - perror("Failed to close plug-in directory"); - } - } - free(entry); - free(file_path); return ret; } -struct bt_plugin **bt_plugin_create_all_from_dir(const char *path, - bool recurse) +const struct bt_plugin_set *bt_plugin_find_all_from_dir(const char *path, + bt_bool recurse) { - GPtrArray *plugins_array = g_ptr_array_new(); - struct bt_plugin **plugins = NULL; + struct bt_plugin_set *plugin_set; enum bt_plugin_status status; + BT_LOGD("Creating all plugins in directory: path=\"%s\", recurse=%d", + path, recurse); + plugin_set = bt_plugin_set_create(); + if (!plugin_set) { + BT_LOGE_STR("Cannot create empty plugin set."); + goto error; + } + /* Append found plugins to array */ - status = bt_plugin_create_append_all_from_dir(plugins_array, path, + status = bt_plugin_create_append_all_from_dir(plugin_set, path, recurse); if (status < 0) { + BT_LOGW("Cannot append plugins found in directory: " + "path=\"%s\", status=%s", + path, bt_plugin_status_string(status)); goto error; } - /* Add sentinel to array */ - g_ptr_array_add(plugins_array, NULL); - plugins = (struct bt_plugin **) plugins_array->pdata; + BT_LOGD("Created %u plugins from directory: count=%u, path=\"%s\"", + plugin_set->plugins->len, plugin_set->plugins->len, path); goto end; error: - if (plugins_array) { - g_ptr_array_free(plugins_array, TRUE); - plugins_array = NULL; - } + BT_OBJECT_PUT_REF_AND_RESET(plugin_set); end: - if (plugins_array) { - g_ptr_array_free(plugins_array, FALSE); - } - - return plugins; + return plugin_set; } -const char *bt_plugin_get_name(struct bt_plugin *plugin) +const char *bt_plugin_get_name(const struct bt_plugin *plugin) { - return plugin ? plugin->name : NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return plugin->info.name_set ? plugin->info.name->str : NULL; } -const char *bt_plugin_get_author(struct bt_plugin *plugin) +const char *bt_plugin_get_author(const struct bt_plugin *plugin) { - return plugin ? plugin->author : NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return plugin->info.author_set ? plugin->info.author->str : NULL; } -const char *bt_plugin_get_license(struct bt_plugin *plugin) +const char *bt_plugin_get_license(const struct bt_plugin *plugin) { - return plugin ? plugin->license : NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return plugin->info.license_set ? plugin->info.license->str : NULL; } -const char *bt_plugin_get_path(struct bt_plugin *plugin) +const char *bt_plugin_get_path(const struct bt_plugin *plugin) { - return (plugin && plugin->shared_lib_handle->path) ? - plugin->shared_lib_handle->path->str : NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return plugin->info.path_set ? plugin->info.path->str : NULL; } -const char *bt_plugin_get_description(struct bt_plugin *plugin) +const char *bt_plugin_get_description(const struct bt_plugin *plugin) { - return plugin ? plugin->description : NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return plugin->info.description_set ? + plugin->info.description->str : NULL; } -enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin, +enum bt_property_availability bt_plugin_get_version(const struct bt_plugin *plugin, unsigned int *major, unsigned int *minor, unsigned int *patch, const char **extra) { - enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; + enum bt_property_availability avail = + BT_PROPERTY_AVAILABILITY_AVAILABLE; + + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); - if (!plugin || !plugin->version) { - status = BT_PLUGIN_STATUS_ERROR; + if (!plugin->info.version_set) { + BT_LIB_LOGV("Plugin's version is not set: %!+l", plugin); + avail = BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE; goto end; } if (major) { - *major = (unsigned int) plugin->version->major; + *major = plugin->info.version.major; } if (minor) { - *minor = (unsigned int) plugin->version->minor; + *minor = plugin->info.version.minor; } if (patch) { - *patch = (unsigned int) plugin->version->patch; + *patch = plugin->info.version.patch; } if (extra) { - *extra = plugin->version->extra; + *extra = plugin->info.version.extra->str; } end: - return status; + return avail; } -int bt_plugin_get_component_class_count(struct bt_plugin *plugin) +uint64_t bt_plugin_get_source_component_class_count(const struct bt_plugin *plugin) { - return plugin ? plugin->comp_classes->len : -1; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return (uint64_t) plugin->src_comp_classes->len; } -struct bt_component_class *bt_plugin_get_component_class( - struct bt_plugin *plugin, size_t index) +uint64_t bt_plugin_get_filter_component_class_count(const struct bt_plugin *plugin) { - struct bt_component_class *comp_class = NULL; + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return (uint64_t) plugin->flt_comp_classes->len; +} - if (!plugin || index >= plugin->comp_classes->len) { - goto error; - } +uint64_t bt_plugin_get_sink_component_class_count(const struct bt_plugin *plugin) +{ + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + return (uint64_t) plugin->sink_comp_classes->len; +} - comp_class = g_ptr_array_index(plugin->comp_classes, index); - bt_get(comp_class); - goto end; +static inline +struct bt_component_class *borrow_component_class_by_index( + const struct bt_plugin *plugin, GPtrArray *comp_classes, + uint64_t index) +{ + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + BT_ASSERT_PRE_VALID_INDEX(index, comp_classes->len); + return g_ptr_array_index(comp_classes, index); +} -error: - BT_PUT(comp_class); +const struct bt_component_class_source * +bt_plugin_borrow_source_component_class_by_index_const( + const struct bt_plugin *plugin, uint64_t index) +{ + return (const void *) borrow_component_class_by_index(plugin, + plugin->src_comp_classes, index); +} -end: - return comp_class; +const struct bt_component_class_filter * +bt_plugin_borrow_filter_component_class_by_index_const( + const struct bt_plugin *plugin, uint64_t index) +{ + return (const void *) borrow_component_class_by_index(plugin, + plugin->flt_comp_classes, index); +} + +const struct bt_component_class_sink * +bt_plugin_borrow_sink_component_class_by_index_const( + const struct bt_plugin *plugin, uint64_t index) +{ + return (const void *) borrow_component_class_by_index(plugin, + plugin->sink_comp_classes, index); } -struct bt_component_class *bt_plugin_get_component_class_by_name_and_type( - struct bt_plugin *plugin, const char *name, - enum bt_component_class_type type) +static inline +struct bt_component_class *borrow_component_class_by_name( + const struct bt_plugin *plugin, GPtrArray *comp_classes, + const char *name) { struct bt_component_class *comp_class = NULL; size_t i; - if (!plugin || !name) { - goto error; - } + BT_ASSERT_PRE_NON_NULL(plugin, "Plugin"); + BT_ASSERT_PRE_NON_NULL(name, "Name"); - for (i = 0; i < plugin->comp_classes->len; i++) { + for (i = 0; i < comp_classes->len; i++) { struct bt_component_class *comp_class_candidate = - g_ptr_array_index(plugin->comp_classes, i); + g_ptr_array_index(comp_classes, i); const char *comp_class_cand_name = bt_component_class_get_name(comp_class_candidate); - enum bt_component_class_type comp_class_cand_type = - bt_component_class_get_type(comp_class_candidate); - assert(comp_class_cand_name); - assert(comp_class_cand_type >= 0); + BT_ASSERT(comp_class_cand_name); - if (strcmp(name, comp_class_cand_name) == 0 && - comp_class_cand_type == type) { - comp_class = bt_get(comp_class_candidate); + if (strcmp(name, comp_class_cand_name) == 0) { + comp_class = comp_class_candidate; break; } } - goto end; - -error: - BT_PUT(comp_class); - -end: return comp_class; } -static -void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class, - void *data) +const struct bt_component_class_source * +bt_plugin_borrow_source_component_class_by_name_const( + const struct bt_plugin *plugin, const char *name) { - gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles, - comp_class); - assert(exists); + return (const void *) borrow_component_class_by_name(plugin, + plugin->src_comp_classes, name); } -enum bt_plugin_status bt_plugin_add_component_class( - struct bt_plugin *plugin, struct bt_component_class *comp_class) +const struct bt_component_class_filter * +bt_plugin_borrow_filter_component_class_by_name_const( + const struct bt_plugin *plugin, const char *name) { - enum bt_plugin_status status = BT_PLUGIN_STATUS_OK; - struct bt_component_class *comp_class_dup = NULL; - int ret; - int comp_class_index = -1; - - if (!plugin || !comp_class || plugin->frozen) { - goto error; - } - - /* Check for duplicate */ - comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin, - bt_component_class_get_name(comp_class), - bt_component_class_get_type(comp_class)); - if (comp_class_dup) { - printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n", - plugin->name, - bt_component_class_get_name(comp_class), - bt_component_class_get_type(comp_class)); - goto error; - } - - /* Add new component class */ - comp_class_index = plugin->comp_classes->len; - g_ptr_array_add(plugin->comp_classes, bt_get(comp_class)); - - /* Map component class pointer to shared lib handle in global HT */ - g_hash_table_insert(comp_classes_to_shlib_handles, comp_class, - bt_get(plugin->shared_lib_handle)); + return (const void *) borrow_component_class_by_name(plugin, + plugin->flt_comp_classes, name); +} - /* Add our custom destroy listener */ - ret = bt_component_class_add_destroy_listener(comp_class, - plugin_comp_class_destroy_listener, NULL); - if (ret) { - goto error; - } +const struct bt_component_class_sink * +bt_plugin_borrow_sink_component_class_by_name_const( + const struct bt_plugin *plugin, const char *name) +{ + return (const void *) borrow_component_class_by_name(plugin, + plugin->sink_comp_classes, name); +} - goto end; +void bt_plugin_get_ref(const struct bt_plugin *plugin) +{ + bt_object_get_ref(plugin); +} -error: - /* Remove entry from global hash table (if exists) */ - g_hash_table_remove(comp_classes_to_shlib_handles, - comp_class); - - /* Remove entry from plugin's component classes (if added) */ - if (comp_class_index >= 0) { - g_ptr_array_remove_index(plugin->comp_classes, - comp_class_index); - } +void bt_plugin_put_ref(const struct bt_plugin *plugin) +{ + bt_object_put_ref(plugin); +} - status = BT_PLUGIN_STATUS_ERROR; +void bt_plugin_set_get_ref(const struct bt_plugin_set *plugin_set) +{ + bt_object_get_ref(plugin_set); +} -end: - bt_put(comp_class_dup); - return status; +void bt_plugin_set_put_ref(const struct bt_plugin_set *plugin_set) +{ + bt_object_put_ref(plugin_set); }