diff -r a10ba529ae39 -r 7728d6ec3abf src/module.c --- a/src/module.c Wed May 27 23:07:00 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -#include "module.h" -#include "log.h" - -#include -#include -#include -#include -#include - -err_t modules_create (struct modules **modules_ptr, struct nexus *nexus) -{ - struct modules *modules; - - // alloc - if ((modules = calloc(1, sizeof(*modules))) == NULL) - return ERR_CALLOC; - - // init - TAILQ_INIT(&modules->list); - - // store - modules->nexus = nexus; - - // ok - *modules_ptr = modules; - - return SUCCESS; -} - -const char* modules_path (struct modules *modules, const char *path) -{ - const char *old_path = modules->path; - - if (path) - // replace - modules->path = path; - - return old_path; -} - -/** - * module_get without the refcount stuff - */ -static struct module* modules_lookup (struct modules *modules, const char *name) -{ - struct module *module = NULL; - - // look for it... - TAILQ_FOREACH(module, &modules->list, modules_list) { - if (strcasecmp(module->info.name, name) == 0) { - // found it - return module; - } - } - - // no such module - return NULL; -} - -struct module* modules_get (struct modules *modules, const char *name) -{ - struct module *module; - - // get it - if (!(module = modules_lookup(modules, name))) - return NULL; - - // up the refcount - module->refcount++; - - // ok - return module; -} - -err_t modules_unload (struct modules *modules) -{ - struct module *module; - err_t err; - - // unload each module in turn - while ((module = TAILQ_FIRST(&modules->list))) { - if ((err = module_unload(module))) - log_warn("module_unload(%s) failed: %s", module->info.name, error_name(err)); - } - - // ok - return SUCCESS; -} - -void modules_destroy (struct modules *modules) -{ - struct module *module; - - // destroy each module - while ((module = TAILQ_FIRST(&modules->list))) - module_destroy(module); - - // ourselves - free(modules); -} - - -const char* module_name (struct module *module) -{ - return module ? module->info.name : NULL; -} - -/** - * Load the symbol named "_". - */ -static err_t module_symbol (struct module *module, void **sym, const char *suffix) -{ - char sym_name[MODULE_SYMBOL_MAX]; - - // validate the length of the suffix - assert(strlen(module->info.name) <= MODULE_NAME_MAX); - assert(strlen(suffix) <= MODULE_SUFFIX_MAX); - - // format - sprintf(sym_name, "%s_%s", module->info.name, suffix); - - // load - if ((*sym = dlsym(module->handle, sym_name)) == NULL) - return ERR_MODULE_SYM; - - // ok - return SUCCESS; -} - -/** - * XXX: ugly function to format to a dynamically allocated string - */ -char *strfmt (const char *fmt, ...) -{ - va_list vargs; - size_t len; - char *buf; - - // figure out the length of the resulting string - va_start(vargs, fmt); - - len = vsnprintf(NULL, 0, fmt, vargs) + 1; - - va_end(vargs); - - // malloc - if ((buf = malloc(len)) == NULL) - return NULL; - - // format - va_start(vargs, fmt); - - vsnprintf(buf, len, fmt, vargs); - - va_end(vargs); - - // ok - return buf; -} - -/** - * Looks up a module's path by name, returning a dynamically allocated string with the path on success - */ -static char* module_find (struct modules *modules, struct module_info *info, struct error_info *err) -{ - char *path = NULL; - - // build the path... - if ((path = strfmt("%s/mod_%s.so", modules->path, info->name)) == NULL) - JUMP_SET_ERROR(err, ERR_STRDUP); - - // exists and readable? - if (access(path, R_OK)) - // XXX: this doesn't contain the path... - JUMP_SET_ERROR_STR(err, ERR_MODULE_PATH, "module not found in search path"); - - // ok - return path; - -error: - // release the dynamically allocated path - free(path); - - return NULL; -} - -err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *_info, struct error_info *err) -{ - struct module *module; - - // validate the module name - if (strlen(_info->name) > MODULE_NAME_MAX) - return SET_ERROR(err, ERR_MODULE_NAME); - - // already open with the same name? - if (modules_lookup(modules, _info->name)) - return SET_ERROR(err, ERR_MODULE_DUP); - - // alloc - if ((module = calloc(1, sizeof(*module))) == NULL) - return SET_ERROR(err, ERR_CALLOC); - - // initialize - module->info = *_info; - module->modules = modules; - module->refcount = 1; - - // add to modules list - TAILQ_INSERT_TAIL(&modules->list, module, modules_list); - - // lookup path? - if (!module->info.path) { - // have a search path? - if (!modules->path) - JUMP_SET_ERROR_STR(err, ERR_MODULE_PATH, "no module search path defined"); - - // try and resolve the path automatically - if ((module->path_buf = module_find(modules, &module->info, err)) == NULL) - goto error; - - // use that path - module->info.path = module->path_buf; - } - - // clear dlerrors - (void) dlerror(); - - // load it - if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL) - JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror()); - - // load the funcs symbol - if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module"))) - JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror()); - - // call the init func - if ((module->desc->init(modules->nexus, &module->ctx, err))) - goto error; - - // ok - if (module_ptr) { - module->refcount++; - *module_ptr = module; - } - - return SUCCESS; - -error: - // cleanup - module->refcount = 0; - module_destroy(module); - - return ERROR_CODE(err); -} - -void module_put (struct module *module) -{ - assert(module->refcount > 0); - - // decrement, just return if still alive - if (--module->refcount > 0) - return; - - // refcount zero, destroy - module_destroy(module); -} - -err_t module_conf_raw (struct module *module, const char *name, char *value, struct error_info *err) -{ - // sanity-check - if (!module->desc->config_options) - RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "module does not have any config options"); - - // wrong state - if (module->unloading) - RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "module is being unloaded"); - - // parse/apply using the module's stuff - return config_apply_raw(module->desc->config_options, module->modules->nexus, module->ctx, name, value, err); -} - -const struct config_option* module_conf_lookup (struct module *module, const char *name, struct error_info *err) -{ - // sanity-check - if (!module->desc->config_options) - JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "module does not have any config options"); - - // direct lookup - return config_lookup(module->desc->config_options, name, err); - -error: - return NULL; -} - -err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, struct error_info *err) -{ - // wrong state - if (module->unloading) - RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "module is being unloaded"); - - // apply with the module's ctx - return config_apply_opt(opt, module->ctx, value, err); -} - -err_t module_unload (struct module *module) -{ - err_t err; - - // wrong state - if (module->unloading) - return ERR_MODULE_STATE; - - // remove from modules list - TAILQ_REMOVE(&module->modules->list, module, modules_list); - - // update status - module->unloading = true; - - if (module->desc->unload) { - // invoke the unload func, passing it our reference - // note that the module might not exist anymore after calling this - if ((err = module->desc->unload(module->ctx, module))) { - // mark it as "unloaded" - module_unloaded(module); - - return err; - } - - } else { - // no unload procedure, just destroy it as soon as needed - module_unloaded(module); - - } - // ok - return SUCCESS; -} - -/** - * A wrapper for module_destroy suitable for use as a libevent callback - */ -static void _module_destroy (int fd, short what, void *arg) -{ - struct module *module = arg; - - (void) fd; - (void) what; - - // execute - module_destroy(module); -} - -void module_unloaded (struct module *module) -{ - struct timeval tv = { 0, 0 }; - assert(module->refcount > 0); - - // decrement, just return if still alive - if (--module->refcount > 0) - return; - - // schedule a deferred module_destroy - if (event_base_once(module->modules->nexus->ev_base, -1, EV_TIMEOUT, &_module_destroy, module, &tv)) - // XXX: how to reach? - log_fatal("event_base_once failed, unable to schedule deferred module_destroy"); -} - -void module_destroy (struct module *module) -{ - // XXX: warn about destroy with significant refcount... - if (module->refcount) - log_warn("destroying module %s with refcount>0: %zu", module_name(module), module->refcount); - else - log_debug("destroying module %s", module_name(module)); - - // still need to remove from modules_list? - if (!module->unloading) - TAILQ_REMOVE(&module->modules->list, module, modules_list); - - // run the destroy hook - if (module->desc && module->desc->destroy && module->ctx) - module->desc->destroy(module->ctx); - - // unload the dl handle - if (module->handle && dlclose(module->handle)) - log_warn("dlclose(%s): %s", module->info.name, dlerror()); - - // release the path buf, if any - free(module->path_buf); - - // free the module info - free(module); -} - -