src/spbot/module.c
branchnew-lib-errors
changeset 218 5229a5d098b2
parent 217 7728d6ec3abf
equal deleted inserted replaced
217:7728d6ec3abf 218:5229a5d098b2
     1 #include "module.h"
     1 #include "module.h"
     2 #include "log.h"
     2 #include <lib/log.h>
     3 
     3 
     4 #include <stdlib.h>
     4 #include <stdlib.h>
     5 #include <unistd.h>
     5 #include <unistd.h>
     6 #include <dlfcn.h>
     6 #include <dlfcn.h>
     7 #include <string.h>
     7 #include <string.h>
     8 #include <assert.h>
     8 #include <assert.h>
     9 
     9 
    10 const struct error_list module_errors = ERROR_LIST("module",
    10 const struct error_list module_errors = ERROR_LIST("module",
    11     ERROR_TYPE_STRING(  ERR_MODULE_NAME,        "invalid module name"       ),
    11     ERROR_TYPE_STRING(  ERR_MODULE_NAME,        "invalid module name"                       ),
    12     ERROR_TYPE(         ERR_MODULE_DUP,         "module already loaded"     ),
    12     ERROR_TYPE(         ERR_MODULE_DUP,         "module already loaded"                     ),
    13     ERROR_TYPE_STRING(  ERR_MODULE_PATH,        "invalid module path"       ),
    13     ERROR_TYPE_STRING(  ERR_MODULE_PATH,        "invalid module path"                       ),
    14     ERROR_TYPE_STRING(  ERR_MODULE_OPEN,        "module dlopen() failed"    ),
    14     ERROR_TYPE_STRING(  ERR_MODULE_OPEN,        "module dlopen() failed"                    ),
    15     ERROR_TYPE_STRING(  ERR_MODULE_SYM,         "module dlsym() failed"     ),
    15     ERROR_TYPE_STRING(  ERR_MODULE_SYM,         "module dlsym() failed"                     ),
    16     ERROR_TYPE_STRING(  ERR_MODULE_INIT_FUNC,   "invalid module init func"  ),
    16     ERROR_TYPE_STRING(  ERR_MODULE_INIT_FUNC,   "invalid module init func"                  ),
    17     ERROR_TYPE_STRING(  ERR_MODULE_CONF,        "module_conf"               )
    17     ERROR_TYPE_STRING(  ERR_MODULE_CONF,        "module_conf"                               ),
       
    18     ERROR_TYPE(         ERR_MODULE_STATE,       "module in wrong state for operation"       ),
       
    19     ERROR_TYPE(         ERR_MODULE_UNLOAD,      "unable to unload module"                   )
    18 );
    20 );
    19 
    21 
    20 err_t modules_create (struct modules **modules_ptr, struct nexus *nexus)
    22 err_t modules_create (struct modules **modules_ptr, struct nexus *nexus, error_t *err)
    21 {
    23 {
    22     struct modules *modules;
    24     struct modules *modules;
    23 
    25 
    24     // alloc
    26     // alloc
    25     if ((modules = calloc(1, sizeof(*modules))) == NULL)
    27     if ((modules = calloc(1, sizeof(*modules))) == NULL)
    26         return ERR_CALLOC;
    28         return SET_ERROR_MEM(err);
    27     
    29     
    28     // init
    30     // init
    29     TAILQ_INIT(&modules->list);
    31     TAILQ_INIT(&modules->list);
    30 
    32 
    31     // store
    33     // store
    83 }
    85 }
    84 
    86 
    85 err_t modules_unload (struct modules *modules)
    87 err_t modules_unload (struct modules *modules)
    86 {
    88 {
    87     struct module *module;
    89     struct module *module;
    88     err_t err;
    90     error_t err;
    89 
    91 
    90     // unload each module in turn
    92     // unload each module in turn
    91     while ((module = TAILQ_FIRST(&modules->list))) {
    93     while ((module = TAILQ_FIRST(&modules->list))) {
    92         if ((err = module_unload(module)))
    94         if (module_unload(module, &err))
    93             log_warn("module_unload(%s) failed: %s", module->info.name, error_name(err));
    95             log_warn_error(&err, "module_unload(%s) failed", module->info.name);
    94     }
    96     }
    95 
    97 
    96     // ok
    98     // ok
    97     return SUCCESS;
    99     return SUCCESS;
    98 }
   100 }
   206     if (modules_lookup(modules, _info->name))
   208     if (modules_lookup(modules, _info->name))
   207         return SET_ERROR(err, &module_errors, ERR_MODULE_DUP);
   209         return SET_ERROR(err, &module_errors, ERR_MODULE_DUP);
   208 
   210 
   209     // alloc
   211     // alloc
   210     if ((module = calloc(1, sizeof(*module))) == NULL)
   212     if ((module = calloc(1, sizeof(*module))) == NULL)
   211         return SET_ERROR(err, &module_errors, ERR_CALLOC);
   213         return SET_ERROR_MEM(err);
   212     
   214     
   213     // initialize
   215     // initialize
   214     module->info = *_info;
   216     module->info = *_info;
   215     module->modules = modules;
   217     module->modules = modules;
   216     module->refcount = 1;
   218     module->refcount = 1;
   238     // load it
   240     // load it
   239     if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL)
   241     if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL)
   240         JUMP_SET_ERROR_STR(err, &module_errors, ERR_MODULE_OPEN, dlerror());
   242         JUMP_SET_ERROR_STR(err, &module_errors, ERR_MODULE_OPEN, dlerror());
   241     
   243     
   242     // load the funcs symbol
   244     // load the funcs symbol
   243     if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module")))
   245     if (module_symbol(module, (void **) &module->desc, "module", err))
   244         JUMP_SET_ERROR_STR(err, &module_errors, ERROR_CODE(err), dlerror());
   246         goto error;
   245 
   247 
   246     // call the init func
   248     // call the init func
   247     if ((module->desc->init(modules->nexus, &module->ctx, err)))
   249     if ((module->desc->init(modules->nexus, &module->ctx, err)))
   248         goto error;
   250         goto error;
   249 
   251 
   277 
   279 
   278 err_t module_conf_raw (struct module *module, const char *name, char *value, error_t *err)
   280 err_t module_conf_raw (struct module *module, const char *name, char *value, error_t *err)
   279 {
   281 {
   280     // sanity-check
   282     // sanity-check
   281     if (!module->desc->config_options)
   283     if (!module->desc->config_options)
   282         RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options");
   284         return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options");
   283 
   285 
   284     // wrong state
   286     // wrong state
   285     if (module->unloading)
   287     if (module->unloading)
   286         RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
   288         return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
   287     
   289     
   288     // parse/apply using the module's stuff
   290     // parse/apply using the module's stuff
   289     // XXX: error namespaces?
   291     // XXX: error namespaces?
   290     return config_apply_raw(module->desc->config_options, module->modules->nexus, module->ctx, name, value, err);
   292     return config_apply_raw(module->desc->config_options, module->modules->nexus, module->ctx, name, value, err);
   291 }
   293 }
   306 
   308 
   307 err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, error_t *err)
   309 err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, error_t *err)
   308 {
   310 {
   309     // wrong state
   311     // wrong state
   310     if (module->unloading)
   312     if (module->unloading)
   311         RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
   313         return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
   312     
   314     
   313     // apply with the module's ctx
   315     // apply with the module's ctx
   314     // XXX: error namespaces?
   316     // XXX: error namespaces?
   315     return config_apply_opt(opt, module->ctx, value, err);
   317     return config_apply_opt(opt, module->ctx, value, err);
   316 }
   318 }
   317 
   319 
   318 err_t module_unload (struct module *module)
   320 err_t module_unload (struct module *module, error_t *err)
   319 {
   321 {
   320     err_t err;
       
   321     
       
   322     // wrong state
   322     // wrong state
   323     if (module->unloading)
   323     if (module->unloading)
   324         return ERR_MODULE_STATE;
   324         return SET_ERROR(err, &module_errors, ERR_MODULE_STATE);
   325 
   325 
   326     // remove from modules list
   326     // remove from modules list
   327     TAILQ_REMOVE(&module->modules->list, module, modules_list);
   327     TAILQ_REMOVE(&module->modules->list, module, modules_list);
   328     
   328     
   329     // update status
   329     // update status
   330     module->unloading = true;
   330     module->unloading = true;
   331 
   331 
   332     if (module->desc->unload) {
   332     if (module->desc->unload) {
   333         // invoke the unload func, passing it our reference
   333         // invoke the unload func, passing it our reference
   334         // note that the module might not exist anymore after calling this
   334         // note that the module might not exist anymore after calling this
   335         if ((err = module->desc->unload(module->ctx, module))) {
   335         if (module->desc->unload(module->ctx, module, err)) {
   336             // mark it as "unloaded"
   336             // mark it as "unloaded"
   337             module_unloaded(module);
   337             module_unloaded(module);
   338 
   338             
   339             return err;
   339             return PUSH_ERROR(err, &module_errors, ERR_MODULE_UNLOAD);
   340         }
   340         }
   341 
   341 
   342     } else {
   342     } else {
   343         // no unload procedure, just destroy it as soon as needed
   343         // no unload procedure, just destroy it as soon as needed
   344         module_unloaded(module);
   344         module_unloaded(module);