diff --git a/formats/format_g723.c b/formats/format_g723.c index 6e57b4fa85..8580631f9c 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -149,4 +149,7 @@ static int unload_module(void) return ast_format_unregister(g723_1_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "G.723.1 Simple Timestamp File Format"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "G.723.1 Simple Timestamp File Format", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_g726.c b/formats/format_g726.c index e27476fedd..c8b6233da0 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -258,4 +258,7 @@ static int unload_module(void) return(0); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw G.726 (16/24/32/40kbps) data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw G.726 (16/24/32/40kbps) data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_g729.c b/formats/format_g729.c index 8df463d81a..09a9caba4e 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -145,4 +145,7 @@ static int unload_module(void) return ast_format_unregister(g729_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw G729 data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw G729 data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_gsm.c b/formats/format_gsm.c index d8a0813b65..073d5d6063 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -169,4 +169,7 @@ static int unload_module(void) return ast_format_unregister(gsm_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw GSM data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw GSM data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_h263.c b/formats/format_h263.c index b0b5cb27db..709f3c2ffe 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -183,4 +183,7 @@ static int unload_module(void) return ast_format_unregister(h263_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw H.263 data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw H.263 data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_h264.c b/formats/format_h264.c index 06def313cd..2d09177a81 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -172,4 +172,7 @@ static int unload_module(void) return ast_format_unregister(h264_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw H.264 data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw H.264 data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index fac2149bc9..1f0b8ce0bf 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -143,4 +143,7 @@ static int unload_module(void) return ast_format_unregister(ilbc_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw iLBC data"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw iLBC data", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c index 4d8d7855d4..3613b364fb 100644 --- a/formats/format_jpeg.c +++ b/formats/format_jpeg.c @@ -112,4 +112,7 @@ static int unload_module(void) return 0; } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JPEG (Joint Picture Experts Group) Image Format"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "JPEG (Joint Picture Experts Group) Image Format", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index c2dc977b6c..ea36a7c67c 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -556,5 +556,8 @@ static int unload_module(void) return ast_format_unregister(vorbis_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OGG/Vorbis audio"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "OGG/Vorbis audio", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_pcm.c b/formats/format_pcm.c index a9c44d5026..1530a5dc92 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -494,4 +494,7 @@ static int unload_module(void) || ast_format_unregister(g722_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw/Sun uLaw/ALaw 8KHz (PCM,PCMA,AU), G.722 16Khz"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw/Sun uLaw/ALaw 8KHz (PCM,PCMA,AU), G.722 16Khz", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_sln.c b/formats/format_sln.c index 51f796271e..212b203783 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -127,4 +127,7 @@ static int unload_module(void) return ast_format_unregister(slin_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw Signed Linear Audio support (SLN)"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw Signed Linear Audio support (SLN)", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_sln16.c b/formats/format_sln16.c index 50349f2dd9..6cdd392be9 100644 --- a/formats/format_sln16.c +++ b/formats/format_sln16.c @@ -135,4 +135,7 @@ static int unload_module(void) return ast_format_unregister(slin_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Raw Signed Linear 16KHz Audio support (SLN16)"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw Signed Linear 16KHz Audio support (SLN16)", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_vox.c b/formats/format_vox.c index f22b4881a8..9bb76de264 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -132,4 +132,7 @@ static int unload_module(void) return ast_format_unregister(vox_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialogic VOX (ADPCM) File Format"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Dialogic VOX (ADPCM) File Format", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_wav.c b/formats/format_wav.c index 94980477ae..3a43c39bcd 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -491,4 +491,7 @@ static int unload_module(void) return ast_format_unregister(wav_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Microsoft WAV format (8000Hz Signed Linear)"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Microsoft WAV format (8000Hz Signed Linear)", + .load = load_module, + .unload = unload_module, +); diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index 9c71c591ec..7c63d280f3 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -548,4 +548,7 @@ static int unload_module(void) return ast_format_unregister(wav49_f.name); } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Microsoft WAV format (Proprietary GSM)"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Microsoft WAV format (Proprietary GSM)", + .load = load_module, + .unload = unload_module, +); diff --git a/include/asterisk/module.h b/include/asterisk/module.h index a46f3319cb..2e308bc79e 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -189,6 +189,14 @@ struct ast_module_user_list; enum ast_module_flags { AST_MODFLAG_DEFAULT = 0, AST_MODFLAG_GLOBAL_SYMBOLS = (1 << 0), + /*! + * \brief Load this module in the first pass on auto loading + * + * When module auto loading is used, modules with this flag set will + * be loaded after preloaded modules, but before all modules being + * automatically loaded without this flag set on them. + */ + AST_MODFLAG_LOAD_FIRST = (1 << 2), }; struct ast_module_info { diff --git a/main/loader.c b/main/loader.c index 0772db14c2..2a7d356157 100644 --- a/main/loader.c +++ b/main/loader.c @@ -125,6 +125,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) @@ -348,12 +361,12 @@ 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[PATH_MAX] = ""; void *lib = NULL; struct ast_module *mod; - unsigned int wants_global; + unsigned int wants_global = 0, not_yet = 0; int space; /* room needed for the descriptor */ int missing_so = 0; @@ -398,11 +411,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; } @@ -709,7 +733,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; @@ -720,13 +744,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 { @@ -830,6 +870,7 @@ int load_modules(unsigned int preload_only) int res = 0; struct ast_flags config_flags = { 0 }; int modulecount = 0; + int load_pass; #ifdef LOADABLE_MODULES struct dirent *dirent; @@ -936,45 +977,29 @@ 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: - modulecount++; - case AST_MODULE_LOAD_DECLINE: - AST_LIST_REMOVE_CURRENT(entry); - ast_free(order->resource); - ast_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: - modulecount++; - case AST_MODULE_LOAD_DECLINE: - AST_LIST_REMOVE_CURRENT(entry); - ast_free(order->resource); - ast_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: + modulecount++; + case AST_MODULE_LOAD_DECLINE: + AST_LIST_REMOVE_CURRENT(entry); + ast_free(order->resource); + ast_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))) {