Code

plugin: Only log a message when actually unloading a module.
[sysdb.git] / src / core / plugin.c
index 6af090bfac233eec2e51a91221e4a762ee3f02f7..18ea82c77fc8475d73dfb9e4a37b8a7a693443fc 100644 (file)
@@ -81,9 +81,15 @@ 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
+        * 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))
 
@@ -199,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 {
@@ -218,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_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 */
 
 /*
@@ -246,6 +259,8 @@ 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 */
 
@@ -253,6 +268,16 @@ static void
 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 */
 
@@ -390,7 +415,7 @@ plugin_add_callback(sdb_llist_t **list, const char *type,
 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;
 
@@ -405,18 +430,25 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
        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)) {
@@ -440,7 +472,7 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
        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;
@@ -448,6 +480,7 @@ 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;