mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 04:11:08 +00:00
module load priority
This patch adds the option to give a module a load priority. The value represents the order in which a module's load() function is initialized. The lower the value, the higher the priority. The value is only checked if the AST_MODFLAG_LOAD_ORDER flag is set. If the AST_MODFLAG_LOAD_ORDER flag is not set, the value will never be read and the module will be given the lowest possible priority on load. Since some modules are reliant on a timing interface, the timing modules have been given a high load priorty. (closes issue #15191) Reported by: alecdavis Tested by: dvossel Review: https://reviewboard.asterisk.org/r/262/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@199743 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -189,6 +189,7 @@ struct ast_module_user_list;
|
|||||||
enum ast_module_flags {
|
enum ast_module_flags {
|
||||||
AST_MODFLAG_DEFAULT = 0,
|
AST_MODFLAG_DEFAULT = 0,
|
||||||
AST_MODFLAG_GLOBAL_SYMBOLS = (1 << 0),
|
AST_MODFLAG_GLOBAL_SYMBOLS = (1 << 0),
|
||||||
|
AST_MODFLAG_LOAD_ORDER = (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ast_module_info {
|
struct ast_module_info {
|
||||||
@@ -219,6 +220,13 @@ struct ast_module_info {
|
|||||||
|
|
||||||
/*! The value of AST_BUILDOPT_SUM when this module was compiled */
|
/*! The value of AST_BUILDOPT_SUM when this module was compiled */
|
||||||
const char buildopt_sum[33];
|
const char buildopt_sum[33];
|
||||||
|
|
||||||
|
/*! This value represents the order in which a module's load() function is initialized.
|
||||||
|
* The lower this value, the higher the priority. The value is only checked if the
|
||||||
|
* AST_MODFLAG_LOAD_ORDER flag is set. If the AST_MODFLAG_LOAD_ORDER flag is not set,
|
||||||
|
* this value will never be read and the module will be given the lowest possible priority
|
||||||
|
* on load. */
|
||||||
|
unsigned char load_pri;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ast_module_register(const struct ast_module_info *);
|
void ast_module_register(const struct ast_module_info *);
|
||||||
|
192
main/loader.c
192
main/loader.c
@@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/features.h"
|
#include "asterisk/features.h"
|
||||||
#include "asterisk/dsp.h"
|
#include "asterisk/dsp.h"
|
||||||
#include "asterisk/udptl.h"
|
#include "asterisk/udptl.h"
|
||||||
|
#include "asterisk/heap.h"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
@@ -712,11 +713,57 @@ static unsigned int inspect_module(const struct ast_module *mod)
|
|||||||
return 0;
|
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 start_resource(struct ast_module *mod)
|
||||||
|
{
|
||||||
|
char tmp[256];
|
||||||
|
enum ast_module_load_result res;
|
||||||
|
|
||||||
|
if (!mod->info->load) {
|
||||||
|
return AST_MODULE_LOAD_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mod->info->load();
|
||||||
|
|
||||||
|
switch (res) {
|
||||||
|
case AST_MODULE_LOAD_SUCCESS:
|
||||||
|
if (!ast_fully_booted) {
|
||||||
|
ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
|
||||||
|
if (ast_opt_console && !option_verbose)
|
||||||
|
ast_verbose( ".");
|
||||||
|
} else {
|
||||||
|
ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod->flags.running = 1;
|
||||||
|
|
||||||
|
ast_update_use_count();
|
||||||
|
break;
|
||||||
|
case AST_MODULE_LOAD_DECLINE:
|
||||||
|
mod->flags.declined = 1;
|
||||||
|
break;
|
||||||
|
case AST_MODULE_LOAD_FAILURE:
|
||||||
|
break;
|
||||||
|
case AST_MODULE_LOAD_SKIP:
|
||||||
|
/* modules should never return this value */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! loads a resource based upon resource_name. If global_symbols_only is set
|
||||||
|
* only modules with global symbols will be loaded.
|
||||||
|
*
|
||||||
|
* If the ast_heap is provided (not NULL) the module is found and added to the
|
||||||
|
* heap without running the module's load() function. By doing this, modules
|
||||||
|
* added to the resource_heap can be initilized later in order by priority.
|
||||||
|
*
|
||||||
|
* If the ast_heap is not provided, the module's load function will be executed
|
||||||
|
* immediately */
|
||||||
|
static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap)
|
||||||
{
|
{
|
||||||
struct ast_module *mod;
|
struct ast_module *mod;
|
||||||
enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
|
enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
|
||||||
char tmp[256];
|
|
||||||
|
|
||||||
if ((mod = find_resource(resource_name, 0))) {
|
if ((mod = find_resource(resource_name, 0))) {
|
||||||
if (mod->flags.running) {
|
if (mod->flags.running) {
|
||||||
@@ -757,31 +804,11 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi
|
|||||||
|
|
||||||
mod->flags.declined = 0;
|
mod->flags.declined = 0;
|
||||||
|
|
||||||
if (mod->info->load)
|
if (resource_heap) {
|
||||||
res = mod->info->load();
|
ast_heap_push(resource_heap, mod);
|
||||||
|
res = AST_MODULE_LOAD_SKIP;
|
||||||
switch (res) {
|
} else {
|
||||||
case AST_MODULE_LOAD_SUCCESS:
|
res = start_resource(mod);
|
||||||
if (!ast_fully_booted) {
|
|
||||||
ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
|
|
||||||
if (ast_opt_console && !option_verbose)
|
|
||||||
ast_verbose( ".");
|
|
||||||
} else {
|
|
||||||
ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description);
|
|
||||||
}
|
|
||||||
|
|
||||||
mod->flags.running = 1;
|
|
||||||
|
|
||||||
ast_update_use_count();
|
|
||||||
break;
|
|
||||||
case AST_MODULE_LOAD_DECLINE:
|
|
||||||
mod->flags.declined = 1;
|
|
||||||
break;
|
|
||||||
case AST_MODULE_LOAD_FAILURE:
|
|
||||||
break;
|
|
||||||
case AST_MODULE_LOAD_SKIP:
|
|
||||||
/* modules should never return this value */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -791,7 +818,7 @@ int ast_load_resource(const char *resource_name)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
AST_LIST_LOCK(&module_list);
|
AST_LIST_LOCK(&module_list);
|
||||||
res = load_resource(resource_name, 0);
|
res = load_resource(resource_name, 0, NULL);
|
||||||
AST_LIST_UNLOCK(&module_list);
|
AST_LIST_UNLOCK(&module_list);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -822,6 +849,77 @@ static struct load_order_entry *add_to_load_order(const char *resource, struct l
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mod_load_cmp(void *a, void *b)
|
||||||
|
{
|
||||||
|
struct ast_module *a_mod = (struct ast_module *) a;
|
||||||
|
struct ast_module *b_mod = (struct ast_module *) b;
|
||||||
|
int res = -1;
|
||||||
|
/* if load_pri is not set, default is 255. Lower is better*/
|
||||||
|
unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 255;
|
||||||
|
unsigned char b_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 255;
|
||||||
|
if (a_pri == b_pri) {
|
||||||
|
res = 0;
|
||||||
|
} else if (a_pri < b_pri) {
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! loads modules in order by load_pri, updates mod_count */
|
||||||
|
static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
|
||||||
|
{
|
||||||
|
struct ast_heap *resource_heap;
|
||||||
|
struct load_order_entry *order;
|
||||||
|
struct ast_module *mod;
|
||||||
|
int count = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first, add find and add modules to heap */
|
||||||
|
AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
|
||||||
|
switch (load_resource(order->resource, global_symbols, resource_heap)) {
|
||||||
|
case AST_MODULE_LOAD_SUCCESS:
|
||||||
|
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:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AST_LIST_TRAVERSE_SAFE_END;
|
||||||
|
|
||||||
|
/* second remove modules from heap sorted by priority */
|
||||||
|
while ((mod = ast_heap_pop(resource_heap))) {
|
||||||
|
switch (start_resource(mod)) {
|
||||||
|
case AST_MODULE_LOAD_SUCCESS:
|
||||||
|
count++;
|
||||||
|
case AST_MODULE_LOAD_DECLINE:
|
||||||
|
break;
|
||||||
|
case AST_MODULE_LOAD_FAILURE:
|
||||||
|
res = -1;
|
||||||
|
goto done;
|
||||||
|
case AST_MODULE_LOAD_SKIP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (mod_count) {
|
||||||
|
*mod_count += count;
|
||||||
|
}
|
||||||
|
ast_heap_destroy(resource_heap);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
int load_modules(unsigned int preload_only)
|
int load_modules(unsigned int preload_only)
|
||||||
{
|
{
|
||||||
struct ast_config *cfg;
|
struct ast_config *cfg;
|
||||||
@@ -941,44 +1039,14 @@ int load_modules(unsigned int preload_only)
|
|||||||
ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
|
ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
|
||||||
|
|
||||||
/* first, load only modules that provide global symbols */
|
/* first, load only modules that provide global symbols */
|
||||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
|
if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
|
||||||
switch (load_resource(order->resource, 1)) {
|
goto done;
|
||||||
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 */
|
/* now load everything else */
|
||||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
|
if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
|
||||||
switch (load_resource(order->resource, 0)) {
|
goto done;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AST_LIST_TRAVERSE_SAFE_END;
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
|
while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
|
||||||
|
@@ -199,4 +199,8 @@ static int unload_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI Timing Interface");
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "DAHDI Timing Interface",
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.load_pri = 10,
|
||||||
|
);
|
||||||
|
@@ -521,5 +521,8 @@ static int unload_module(void)
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "pthread Timing Interface",
|
||||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "pthread Timing Interface");
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.load_pri = 10,
|
||||||
|
);
|
||||||
|
@@ -286,4 +286,8 @@ static int unload_module(void)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Timerfd Timing Interface");
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface",
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.load_pri = 10,
|
||||||
|
);
|
||||||
|
Reference in New Issue
Block a user