diff --git a/src/core/plugin.c b/src/core/plugin.c
index e67f814ba24510ae47b2640bddfa17dacea3c76f..b3d5973178dffed19411af5d5acea45a99b718e3 100644 (file)
--- a/src/core/plugin.c
+++ b/src/core/plugin.c
static sdb_llist_t *shutdown_list = NULL;
static sdb_llist_t *log_list = NULL;
+static struct {
+ const char *type;
+ sdb_llist_t **list;
+} all_lists[] = {
+ { "config", &config_list },
+ { "init", &init_list },
+ { "collector", &collector_list },
+ { "cname", &cname_list },
+ { "shutdown", &shutdown_list },
+ { "log", &log_list },
+};
+
/*
* private helper functions
*/
const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
const char *name = id;
- assert(cb && id && cb->cb_ctx);
+ assert(cb && id);
+
+ /* when a plugin was registered from outside a plugin (e.g. the core),
+ * we don't have a plugin context */
+ if (! cb->cb_ctx)
+ return 1;
+
if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
return 0;
return 1;
} /* plugin_lookup_by_name */
+/* since this function is called from sdb_plugin_reconfigure_finish()
+ * when iterating through all_plugins, we may not do any additional
+ * modifications to all_plugins except for the optional removal */
static void
plugin_unregister_by_name(const char *plugin_name)
{
sdb_object_t *obj;
size_t i;
- struct {
- const char *type;
- sdb_llist_t *list;
- } all_lists[] = {
- { "config", config_list },
- { "init", init_list },
- { "collector", collector_list },
- { "cname", cname_list },
- { "shutdown", shutdown_list },
- { "log", log_list },
- };
-
for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
- const char *type = all_lists[i].type;
- sdb_llist_t *list = all_lists[i].list;
+ const char *type = all_lists[i].type;
+ sdb_llist_t *list = *all_lists[i].list;
while (1) {
sdb_plugin_cb_t *cb;
if (! cb)
break;
+ assert(cb->cb_ctx);
+
sdb_log(SDB_LOG_INFO, "core: Unregistering "
"%s callback '%s' (module %s)", type, cb->super.name,
cb->cb_ctx->info.plugin_name);
}
}
- obj = sdb_llist_remove_by_name(all_plugins, plugin_name);
- if (obj->ref_cnt <= 1)
- sdb_log(SDB_LOG_INFO, "core: Unloading module %s", plugin_name);
+ obj = sdb_llist_search_by_name(all_plugins, plugin_name);
+ /* when called from sdb_plugin_reconfigure_finish, the object has already
+ * been removed from the list */
+ if (obj && (obj->ref_cnt <= 1)) {
+ sdb_llist_remove_by_name(all_plugins, plugin_name);
+ sdb_object_deref(obj);
+ }
/* else: other callbacks still reference it */
- sdb_object_deref(obj);
} /* plugin_unregister_by_name */
+static void
+plugin_unregister_all(void)
+{
+ size_t i;
+
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
+ const char *type = all_lists[i].type;
+ sdb_llist_t *list = *all_lists[i].list;
+
+ size_t len = sdb_llist_len(list);
+
+ if (! len)
+ continue;
+
+ sdb_llist_clear(list);
+ sdb_log(SDB_LOG_INFO, "core: Unregistered %zu %s callback%s",
+ len, type, len == 1 ? "" : "s");
+ }
+} /* plugin_unregister_all */
+
/*
* private types
*/
if (ctx->handle) {
const char *err;
+
+ sdb_log(SDB_LOG_INFO, "core: Unloading module %s",
+ ctx->info.plugin_name);
+
lt_dlerror();
lt_dlclose(ctx->handle);
if ((err = lt_dlerror()))
- sdb_log(SDB_LOG_WARNING, "core: Failed to unload plugin %s: %s",
+ sdb_log(SDB_LOG_WARNING, "core: Failed to unload module %s: %s",
ctx->info.plugin_name, err);
}
ctx_destroy
};
-static ctx_t *
-ctx_create(const char *name)
-{
- ctx_t *ctx;
-
- ctx = CTX(sdb_object_create(name, ctx_type));
- if (! ctx)
- return NULL;
-
- if (! plugin_ctx_key_initialized)
- ctx_key_init();
- sdb_object_ref(SDB_OBJ(ctx));
- pthread_setspecific(plugin_ctx_key, ctx);
- return ctx;
-} /* ctx_create */
-
static ctx_t *
ctx_get(void)
{
return old;
} /* ctx_set */
+static ctx_t *
+ctx_create(const char *name)
+{
+ ctx_t *ctx;
+
+ ctx = CTX(sdb_object_create(name, ctx_type));
+ if (! ctx)
+ return NULL;
+
+ if (! plugin_ctx_key_initialized)
+ ctx_key_init();
+ ctx_set(ctx);
+ return ctx;
+} /* ctx_create */
+
static int
plugin_cb_init(sdb_object_t *obj, va_list ap)
{
return -1;
}
+ /* cb_ctx may be NULL if the plugin was not registered by a plugin */
+
SDB_PLUGIN_CB(obj)->cb_callback = callback;
SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
};
static int
-plugin_add_callback(sdb_llist_t **list, const char *type,
- const char *name, void *callback, sdb_object_t *user_data)
+module_init(const char *name, lt_dlhandle lh, sdb_plugin_info_t *info)
{
- sdb_object_t *obj;
-
- if ((! name) || (! callback))
- return -1;
-
- assert(list);
-
- if (! *list)
- *list = sdb_llist_create();
- if (! *list)
- return -1;
+ int (*mod_init)(sdb_plugin_info_t *);
+ int status;
- obj = sdb_object_create(name, sdb_plugin_cb_type,
- list, type, callback, user_data);
- if (! obj)
+ mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
+ if (! mod_init) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
+ "could not find symbol 'sdb_module_init'", name);
return -1;
+ }
- if (sdb_llist_append(*list, obj)) {
- sdb_object_deref(obj);
+ status = mod_init(info);
+ if (status) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
+ "module '%s'", name);
+ plugin_unregister_by_name(name);
return -1;
}
-
- /* pass control to the list */
- sdb_object_deref(obj);
-
- sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
- type, name);
return 0;
-} /* plugin_add_callback */
-
-/*
- * public API
- */
+} /* module_init */
-int
-sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
+static int
+module_load(const char *basedir, const char *name,
+ const sdb_plugin_ctx_t *plugin_ctx)
{
char base_name[name ? strlen(name) + 1 : 1];
const char *name_ptr;
char *tmp;
char filename[1024];
- ctx_t *ctx;
-
lt_dlhandle lh;
- int (*mod_init)(sdb_plugin_info_t *);
+ ctx_t *ctx;
+
int status;
- if ((! name) || (! *name))
- return -1;
+ assert(name);
base_name[0] = '\0';
name_ptr = name;
}
strcat(base_name, name_ptr);
- ctx = CTX(sdb_llist_search_by_name(all_plugins, base_name));
- if (ctx) {
- /* plugin already loaded */
- ++ctx->use_cnt;
- return 0;
- }
+ if (! basedir)
+ basedir = PKGLIBDIR;
- snprintf(filename, sizeof(filename), "%s/%s.so",
- PKGLIBDIR, base_name);
+ snprintf(filename, sizeof(filename), "%s/%s.so", basedir, base_name);
filename[sizeof(filename) - 1] = '\0';
if (access(filename, R_OK)) {
if (plugin_ctx)
ctx->public = *plugin_ctx;
- mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
- if (! mod_init) {
- sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
- "could not find symbol 'sdb_module_init'", name);
- sdb_object_deref(SDB_OBJ(ctx));
- return -1;
- }
-
- status = mod_init(&ctx->info);
- if (status) {
- sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
- "module '%s'", name);
- plugin_unregister_by_name(ctx->info.plugin_name);
+ if ((status = module_init(name, lh, &ctx->info))) {
sdb_object_deref(SDB_OBJ(ctx));
- return -1;
+ return status;
}
/* compare minor version */
name, SDB_VERSION_DECODE(ctx->info.version),
SDB_VERSION_DECODE(SDB_VERSION));
- if (! all_plugins) {
- if (! (all_plugins = sdb_llist_create())) {
- sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
- "internal error while creating linked list", name);
- plugin_unregister_by_name(ctx->info.plugin_name);
- sdb_object_deref(SDB_OBJ(ctx));
- return -1;
- }
- }
-
sdb_llist_append(all_plugins, SDB_OBJ(ctx));
sdb_log(SDB_LOG_INFO, "core: Successfully loaded "
/* reset */
ctx_set(NULL);
return 0;
+} /* module_load */
+
+static int
+plugin_add_callback(sdb_llist_t **list, const char *type,
+ const char *name, void *callback, sdb_object_t *user_data)
+{
+ sdb_object_t *obj;
+
+ if ((! name) || (! callback))
+ return -1;
+
+ assert(list);
+
+ if (! *list)
+ *list = sdb_llist_create();
+ if (! *list)
+ return -1;
+
+ obj = sdb_object_create(name, sdb_plugin_cb_type,
+ list, type, callback, user_data);
+ if (! obj)
+ return -1;
+
+ if (sdb_llist_append(*list, obj)) {
+ sdb_object_deref(obj);
+ return -1;
+ }
+
+ /* pass control to the list */
+ sdb_object_deref(obj);
+
+ sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
+ type, name);
+ return 0;
+} /* plugin_add_callback */
+
+/*
+ * public API
+ */
+
+int
+sdb_plugin_load(const char *basedir, const char *name,
+ const sdb_plugin_ctx_t *plugin_ctx)
+{
+ ctx_t *ctx;
+
+ int status;
+
+ if ((! name) || (! *name))
+ return -1;
+
+ if (! all_plugins) {
+ if (! (all_plugins = sdb_llist_create())) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
+ "internal error while creating linked list", name);
+ return -1;
+ }
+ }
+
+ ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
+ if (ctx) {
+ /* plugin already loaded */
+ if (! ctx->use_cnt) {
+ /* reloading plugin */
+ ctx_t *old_ctx = ctx_set(ctx);
+
+ status = module_init(ctx->info.plugin_name, ctx->handle, NULL);
+ if (status)
+ return status;
+
+ sdb_log(SDB_LOG_INFO, "core: Successfully reloaded plugin "
+ "'%s' (%s)", INFO_GET(&ctx->info, name),
+ INFO_GET(&ctx->info, description));
+ ctx_set(old_ctx);
+ }
+ ++ctx->use_cnt;
+ return 0;
+ }
+
+ return module_load(basedir, name, plugin_ctx);
} /* sdb_plugin_load */
int
return status;
} /* sdb_plugin_configure */
+int
+sdb_plugin_reconfigure_init(void)
+{
+ sdb_llist_iter_t *iter;
+
+ iter = sdb_llist_get_iter(config_list);
+ if (config_list && (! iter))
+ return -1;
+
+ /* deconfigure all plugins */
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_cb_t *plugin;
+ sdb_plugin_config_cb callback;
+ ctx_t *old_ctx;
+
+ plugin = SDB_PLUGIN_CB(sdb_llist_iter_get_next(iter));
+ old_ctx = ctx_set(plugin->cb_ctx);
+ callback = (sdb_plugin_config_cb)plugin->cb_callback;
+ callback(NULL);
+ ctx_set(old_ctx);
+ }
+ sdb_llist_iter_destroy(iter);
+
+ iter = sdb_llist_get_iter(all_plugins);
+ if (all_plugins && (! iter))
+ return -1;
+
+ /* record all plugins as being unused */
+ while (sdb_llist_iter_has_next(iter))
+ CTX(sdb_llist_iter_get_next(iter))->use_cnt = 0;
+ sdb_llist_iter_destroy(iter);
+
+ plugin_unregister_all();
+ return 0;
+} /* sdb_plugin_reconfigure_init */
+
+int
+sdb_plugin_reconfigure_finish(void)
+{
+ sdb_llist_iter_t *iter;
+
+ iter = sdb_llist_get_iter(all_plugins);
+ if (all_plugins && (! iter))
+ return -1;
+
+ while (sdb_llist_iter_has_next(iter)) {
+ ctx_t *ctx = CTX(sdb_llist_iter_get_next(iter));
+ if (ctx->use_cnt)
+ continue;
+
+ sdb_log(SDB_LOG_INFO, "core: Module %s no longer in use",
+ ctx->info.plugin_name);
+ sdb_llist_iter_remove_current(iter);
+ plugin_unregister_by_name(ctx->info.plugin_name);
+ sdb_object_deref(SDB_OBJ(ctx));
+ }
+ sdb_llist_iter_destroy(iter);
+ return 0;
+} /* sdb_plugin_reconfigure_finish */
+
int
sdb_plugin_init_all(void)
{
if (callback(cb->cb_user_data)) {
sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
"'%s'. Unregistering all callbacks.", obj->name);
+ ctx_set(old_ctx);
plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
++ret;
}
- ctx_set(old_ctx);
+ else
+ ctx_set(old_ctx);
}
sdb_llist_iter_destroy(iter);
return ret;
} /* sdb_plugin_init_all */
+int
+sdb_plugin_shutdown_all(void)
+{
+ sdb_llist_iter_t *iter;
+ int ret = 0;
+
+ iter = sdb_llist_get_iter(shutdown_list);
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_cb_t *cb;
+ sdb_plugin_shutdown_cb callback;
+ ctx_t *old_ctx;
+
+ sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+ assert(obj);
+ cb = SDB_PLUGIN_CB(obj);
+
+ callback = (sdb_plugin_shutdown_cb)cb->cb_callback;
+
+ old_ctx = ctx_set(cb->cb_ctx);
+ if (callback(cb->cb_user_data)) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to shutdown plugin '%s'.",
+ obj->name);
+ ++ret;
+ }
+ ctx_set(old_ctx);
+ }
+ sdb_llist_iter_destroy(iter);
+ return ret;
+} /* sdb_plugin_shutdown_all */
+
int
sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
{
sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
"in collector main loop: %s",
sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ sdb_llist_insert_sorted(collector_list, obj,
+ plugin_cmp_next_update);
+ sdb_object_deref(obj);
return -1;
}
errno = 0;
}
- if (! loop->do_loop)
+ if (! loop->do_loop) {
+ /* put back; don't worry about errors */
+ sdb_llist_insert_sorted(collector_list, obj,
+ plugin_cmp_next_update);
+ sdb_object_deref(obj);
return 0;
+ }
}
old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
sdb_llist_iter_t *iter;
int ret = -1;
+ _Bool logged = 0;
+
if (! msg)
return 0;
- if (! log_list)
- return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
-
iter = sdb_llist_get_iter(log_list);
while (sdb_llist_iter_has_next(iter)) {
sdb_plugin_log_cb callback;
tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
if (tmp > ret)
ret = tmp;
+
+ if (SDB_PLUGIN_CB(obj)->cb_ctx)
+ logged = 1;
+ /* else: this is an internally registered callback */
}
sdb_llist_iter_destroy(iter);
+
+ if (! logged)
+ return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
return ret;
} /* sdb_plugin_log */