diff --git a/src/core/plugin.c b/src/core/plugin.c
index 6af090bfac233eec2e51a91221e4a762ee3f02f7..18ea82c77fc8475d73dfb9e4a37b8a7a693443fc 100644 (file)
--- a/src/core/plugin.c
+++ b/src/core/plugin.c
sdb_plugin_ctx_t public;
sdb_plugin_info_t info;
+ lt_dlhandle handle;
+
+ /* The usage count differs from the object's ref count
+ * in that it provides higher level information about how
+ * the plugin is in use. */
+ size_t use_cnt;
} ctx_t;
#define CTX_INIT { SDB_OBJECT_INIT, \
- SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT }
+ SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, NULL, 0 }
#define CTX(obj) ((ctx_t *)(obj))
static void
plugin_unregister_by_name(const char *plugin_name)
{
+ sdb_object_t *obj;
size_t i;
struct {
sdb_llist_t *list = all_lists[i].list;
while (1) {
- sdb_object_t *obj = sdb_llist_remove(list,
- plugin_lookup_by_name, plugin_name);
- sdb_plugin_cb_t *cb = SDB_PLUGIN_CB(obj);
+ sdb_plugin_cb_t *cb;
- if (! obj)
+ cb = SDB_PLUGIN_CB(sdb_llist_remove(list,
+ plugin_lookup_by_name, plugin_name));
+ if (! cb)
break;
sdb_log(SDB_LOG_INFO, "core: Unregistering "
- "%s callback '%s' (module %s)", type, obj->name,
+ "%s callback '%s' (module %s)", type, cb->super.name,
cb->cb_ctx->info.plugin_name);
- sdb_object_deref(obj);
+ sdb_object_deref(SDB_OBJ(cb));
}
}
+
+ 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);
+ /* else: other callbacks still reference it */
+ sdb_object_deref(obj);
} /* plugin_unregister_by_name */
/*
ctx->public = plugin_default_ctx;
ctx->info = plugin_default_info;
+ ctx->handle = NULL;
+ ctx->use_cnt = 1;
return 0;
} /* ctx_init */
ctx_destroy(sdb_object_t *obj)
{
ctx_t *ctx = CTX(obj);
+
+ if (ctx->handle) {
+ const char *err;
+ lt_dlerror();
+ lt_dlclose(ctx->handle);
+ if ((err = lt_dlerror()))
+ sdb_log(SDB_LOG_WARNING, "core: Failed to unload plugin %s: %s",
+ ctx->info.plugin_name, err);
+ }
+
plugin_info_clear(&ctx->info);
} /* ctx_destroy */
int
sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
{
- char real_name[name ? strlen(name) + 1 : 1];
+ char base_name[name ? strlen(name) + 1 : 1];
const char *name_ptr;
char *tmp;
if ((! name) || (! *name))
return -1;
- real_name[0] = '\0';
+ base_name[0] = '\0';
name_ptr = name;
while ((tmp = strstr(name_ptr, "::"))) {
- strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
- strcat(real_name, "/");
+ strncat(base_name, name_ptr, (size_t)(tmp - name_ptr));
+ strcat(base_name, "/");
name_ptr = tmp + strlen("::");
}
- strcat(real_name, name_ptr);
+ 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;
+ }
snprintf(filename, sizeof(filename), "%s/%s.so",
- PKGLIBDIR, real_name);
+ PKGLIBDIR, base_name);
filename[sizeof(filename) - 1] = '\0';
if (access(filename, R_OK)) {
if (ctx_get())
sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
- ctx = ctx_create(real_name);
+ ctx = ctx_create(name);
if (! ctx) {
sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
return -1;
ctx->info.plugin_name = strdup(name);
ctx->info.filename = strdup(filename);
+ ctx->handle = lh;
if (plugin_ctx)
ctx->public = *plugin_ctx;