Code

plugin: Split sdb_plugin_load() into multiple functions.
[sysdb.git] / src / core / plugin.c
index 45d3940ff2a36b829fd1559f51074d5b6c03c2c0..929abaee8467cf4bc7f419c324cdd7c6b46a339f 100644 (file)
@@ -81,6 +81,7 @@ typedef struct {
        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
@@ -88,7 +89,7 @@ typedef struct {
        size_t use_cnt;
 } ctx_t;
 #define CTX_INIT { SDB_OBJECT_INIT, \
-       SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, 0 }
+       SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, NULL, 0 }
 
 #define CTX(obj) ((ctx_t *)(obj))
 
@@ -204,6 +205,7 @@ plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
 static void
 plugin_unregister_by_name(const char *plugin_name)
 {
+       sdb_object_t *obj;
        size_t i;
 
        struct {
@@ -223,19 +225,25 @@ plugin_unregister_by_name(const char *plugin_name)
                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_search_by_name(all_plugins, plugin_name);
+       if (obj->ref_cnt <= 1)
+               sdb_llist_remove_by_name(all_plugins, plugin_name);
+       /* else: other callbacks still reference it */
+       sdb_object_deref(obj);
 } /* plugin_unregister_by_name */
 
 /*
@@ -251,6 +259,7 @@ ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
 
        ctx->public = plugin_default_ctx;
        ctx->info = plugin_default_info;
+       ctx->handle = NULL;
        ctx->use_cnt = 1;
        return 0;
 } /* ctx_init */
@@ -259,6 +268,20 @@ static void
 ctx_destroy(sdb_object_t *obj)
 {
        ctx_t *ctx = CTX(obj);
+
+       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 module %s: %s",
+                                       ctx->info.plugin_name, err);
+       }
+
        plugin_info_clear(&ctx->info);
 } /* ctx_destroy */
 
@@ -280,6 +303,7 @@ ctx_create(const char *name)
 
        if (! plugin_ctx_key_initialized)
                ctx_key_init();
+       sdb_object_ref(SDB_OBJ(ctx));
        pthread_setspecific(plugin_ctx_key, ctx);
        return ctx;
 } /* ctx_create */
@@ -301,6 +325,10 @@ ctx_set(ctx_t *new)
                ctx_key_init();
 
        old = pthread_getspecific(plugin_ctx_key);
+       if (old)
+               sdb_object_deref(SDB_OBJ(old));
+       if (new)
+               sdb_object_ref(SDB_OBJ(new));
        pthread_setspecific(plugin_ctx_key, new);
        return old;
 } /* ctx_set */
@@ -356,60 +384,41 @@ static sdb_type_t sdb_plugin_collector_cb_type = {
 };
 
 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 */
+} /* module_init */
 
-/*
- * public API
- */
-
-int
-sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
+static int
+module_load(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 *);
-       int status;
+       ctx_t *ctx;
 
-       if ((! name) || (! *name))
-               return -1;
+       int status;
 
        base_name[0] = '\0';
        name_ptr = name;
@@ -421,13 +430,6 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
        }
        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, base_name);
        filename[sizeof(filename) - 1] = '\0';
@@ -461,25 +463,14 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
 
        ctx->info.plugin_name = strdup(name);
        ctx->info.filename = strdup(filename);
+       ctx->handle = lh;
 
        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);
+       if ((status = module_init(name, lh, &ctx->info))) {
                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);
-               sdb_object_deref(SDB_OBJ(ctx));
-               return -1;
+               return status;
        }
 
        /* compare minor version */
@@ -491,16 +482,6 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
                                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 "
@@ -516,6 +497,70 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
        /* 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 *name, const sdb_plugin_ctx_t *plugin_ctx)
+{
+       ctx_t *ctx;
+
+       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 */
+               ++ctx->use_cnt;
+               return 0;
+       }
+
+       return module_load(name, plugin_ctx);
 } /* sdb_plugin_load */
 
 int