diff options
Diffstat (limited to 'main/loader.c')
-rw-r--r-- | main/loader.c | 118 |
1 files changed, 72 insertions, 46 deletions
diff --git a/main/loader.c b/main/loader.c index 3fd424d48..9190c743b 100644 --- a/main/loader.c +++ b/main/loader.c @@ -117,6 +117,19 @@ static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item); */ struct ast_module *resource_being_loaded; +/*! \brief Load modules in this order. */ +enum module_load_pass { + /*! \brief AST_MODFLAG_LOAD_FIRST */ + LOAD_FIRST, + /*! \brief AST_MODFLAG_GLOBAL_SYMBOLS */ + LOAD_GLOBAL_SYMBOLS, + /*! \brief everything that is left */ + LOAD_ALL, + + /*! \brief Must remain at the end. */ + LOAD_DONE, +}; + /* XXX: should we check for duplicate resource names here? */ void ast_module_register(const struct ast_module_info *info) @@ -339,13 +352,13 @@ static void unload_dynamic_module(struct ast_module *mod) while (!dlclose(lib)); } -static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only) +static struct ast_module *load_dynamic_module(const char *resource_in, enum module_load_pass load_pass) { char fn[256]; void *lib; struct ast_module *mod; char *resource = (char *) resource_in; - unsigned int wants_global; + unsigned int wants_global = 0, not_yet = 0; if (strcasecmp(resource + strlen(resource) - 3, ".so")) { resource = alloca(strlen(resource_in) + 3); @@ -386,11 +399,22 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned return NULL; } - wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); + switch (load_pass) { + case LOAD_FIRST: + not_yet = !ast_test_flag(mod->info, AST_MODFLAG_LOAD_FIRST); + break; + case LOAD_GLOBAL_SYMBOLS: + wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); + not_yet = !wants_global; + break; + case LOAD_ALL: + break; + case LOAD_DONE: + ast_log(LOG_ERROR, "Satan just bought a snowblower! (This should never happen, btw.)\n"); + break; + } - /* if we are being asked only to load modules that provide global symbols, - and this one does not, then close it and return */ - if (global_symbols_only && !wants_global) { + if (not_yet) { while (!dlclose(lib)); return NULL; } @@ -700,7 +724,7 @@ static unsigned int inspect_module(const struct ast_module *mod) return 0; } -static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only) +static enum ast_module_load_result load_resource(const char *resource_name, enum module_load_pass load_pass) { struct ast_module *mod; enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; @@ -711,13 +735,29 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); return AST_MODULE_LOAD_DECLINE; } - if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) - return AST_MODULE_LOAD_SKIP; + + switch (load_pass) { + case LOAD_FIRST: + if (!ast_test_flag(mod->info, AST_MODFLAG_LOAD_FIRST)) { + return AST_MODULE_LOAD_SKIP; + } + break; + case LOAD_GLOBAL_SYMBOLS: + if (!ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) { + return AST_MODULE_LOAD_SKIP; + } + break; + case LOAD_ALL: + break; + case LOAD_DONE: + ast_log(LOG_ERROR, "This should never happen, -EFLAMES!\n"); + break; + } } else { #ifdef LOADABLE_MODULES - if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { + if (!(mod = load_dynamic_module(resource_name, load_pass))) { /* don't generate a warning message during load_modules() */ - if (!global_symbols_only) { + if (load_pass == LOAD_ALL) { ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); return AST_MODULE_LOAD_DECLINE; } else { @@ -832,6 +872,7 @@ int load_modules(unsigned int preload_only) unsigned int load_count; struct load_order load_order; int res = 0; + int load_pass; int translate_status; char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */ @@ -941,43 +982,28 @@ int load_modules(unsigned int preload_only) if (load_count) ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); - /* first, load only modules that provide global symbols */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { - switch (load_resource(order->resource, 1)) { - case AST_MODULE_LOAD_SUCCESS: - case AST_MODULE_LOAD_DECLINE: - AST_LIST_REMOVE_CURRENT(&load_order, entry); - free(order->resource); - free(order); - break; - case AST_MODULE_LOAD_FAILURE: - res = -1; - goto done; - case AST_MODULE_LOAD_SKIP: - /* try again later */ - break; - } - } - AST_LIST_TRAVERSE_SAFE_END; - - /* now load everything else */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { - switch (load_resource(order->resource, 0)) { - case AST_MODULE_LOAD_SUCCESS: - case AST_MODULE_LOAD_DECLINE: - AST_LIST_REMOVE_CURRENT(&load_order, entry); - free(order->resource); - free(order); - break; - case AST_MODULE_LOAD_FAILURE: - res = -1; - goto done; - case AST_MODULE_LOAD_SKIP: - /* should not happen */ - break; + for (load_pass = 0; load_pass < LOAD_DONE; load_pass++) { + AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { + switch (load_resource(order->resource, load_pass)) { + case AST_MODULE_LOAD_SUCCESS: + case AST_MODULE_LOAD_DECLINE: + AST_LIST_REMOVE_CURRENT(&load_order, entry); + free(order->resource); + free(order); + break; + case AST_MODULE_LOAD_FAILURE: + res = -1; + goto done; + case AST_MODULE_LOAD_SKIP: + /* + * Try again later. This result is received when a module is + * deferred because it is not a part of the current pass. + */ + break; + } } + AST_LIST_TRAVERSE_SAFE_END; } - AST_LIST_TRAVERSE_SAFE_END; done: while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { |