X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcore%2Fplugin.c;h=e6df9e9c2a9da7b1746fba2121492dbce630f0bc;hb=7bea0dab48f1b8665e8f003c48b80aa996cf75a5;hp=559e6eb4d7db1aa803a55783025d2dc4a8ee6afb;hpb=39a45905e0b237e458b1826ff9b4fad1c4a59550;p=sysdb.git diff --git a/src/core/plugin.c b/src/core/plugin.c index 559e6eb..e6df9e9 100644 --- a/src/core/plugin.c +++ b/src/core/plugin.c @@ -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_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 */ /* @@ -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,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 */ @@ -274,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 */ @@ -295,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 */ @@ -390,7 +424,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 +439,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 +481,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 +489,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; @@ -578,7 +620,7 @@ int sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback) { return plugin_add_callback(&config_list, "init", name, - callback, NULL); + (void *)callback, NULL); } /* sdb_plugin_register_config */ int @@ -586,7 +628,7 @@ sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback, sdb_object_t *user_data) { return plugin_add_callback(&init_list, "init", name, - callback, user_data); + (void *)callback, user_data); } /* sdb_plugin_register_init */ int @@ -594,14 +636,14 @@ sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback, sdb_object_t *user_data) { return plugin_add_callback(&shutdown_list, "shutdown", name, - callback, user_data); + (void *)callback, user_data); } /* sdb_plugin_register_shutdown */ int sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback, sdb_object_t *user_data) { - return plugin_add_callback(&log_list, "log", name, callback, + return plugin_add_callback(&log_list, "log", name, (void *)callback, user_data); } /* sdb_plugin_register_log */ @@ -609,7 +651,7 @@ int sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback, sdb_object_t *user_data) { - return plugin_add_callback(&cname_list, "cname", name, callback, + return plugin_add_callback(&cname_list, "cname", name, (void *)callback, user_data); } /* sdb_plugin_register_cname */ @@ -713,7 +755,6 @@ sdb_plugin_configure(const char *name, oconfig_item_t *ci) plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name)); if (! plugin) { - /* XXX: check if any such plugin has been loaded */ ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name)); if (! ctx) sdb_log(SDB_LOG_ERR, "core: Plugin '%s' not loaded.", name); @@ -725,7 +766,7 @@ sdb_plugin_configure(const char *name, oconfig_item_t *ci) } old_ctx = ctx_set(plugin->cb_ctx); - callback = plugin->cb_callback; + callback = (sdb_plugin_config_cb)plugin->cb_callback; status = callback(ci); ctx_set(old_ctx); return status; @@ -747,7 +788,7 @@ sdb_plugin_init_all(void) assert(obj); cb = SDB_PLUGIN_CB(obj); - callback = cb->cb_callback; + callback = (sdb_plugin_init_cb)cb->cb_callback; old_ctx = ctx_set(cb->cb_ctx); if (callback(cb->cb_user_data)) { @@ -784,7 +825,7 @@ sdb_plugin_collector_loop(sdb_plugin_loop_t *loop) if (! obj) return -1; - callback = SDB_PLUGIN_CCB(obj)->ccb_callback; + callback = (sdb_plugin_collector_cb)SDB_PLUGIN_CCB(obj)->ccb_callback; if (! (now = sdb_gettime())) { char errbuf[1024]; @@ -882,7 +923,7 @@ sdb_plugin_cname(char *hostname) sdb_object_t *obj = sdb_llist_iter_get_next(iter); assert(obj); - callback = SDB_PLUGIN_CB(obj)->cb_callback; + callback = (sdb_plugin_cname_cb)SDB_PLUGIN_CB(obj)->cb_callback; cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data); if (cname) { free(hostname); @@ -914,7 +955,7 @@ sdb_plugin_log(int prio, const char *msg) sdb_object_t *obj = sdb_llist_iter_get_next(iter); assert(obj); - callback = SDB_PLUGIN_CB(obj)->cb_callback; + callback = (sdb_plugin_log_cb)SDB_PLUGIN_CB(obj)->cb_callback; tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data); if (tmp > ret) ret = tmp;