module load priority
authorDavid Vossel <dvossel@digium.com>
Tue, 9 Jun 2009 16:22:04 +0000 (16:22 +0000)
committerDavid Vossel <dvossel@digium.com>
Tue, 9 Jun 2009 16:22:04 +0000 (16:22 +0000)
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

include/asterisk/module.h
main/loader.c
res/res_timing_dahdi.c
res/res_timing_pthread.c
res/res_timing_timerfd.c

index 3ffe0b7..e7aec44 100644 (file)
@@ -189,6 +189,7 @@ struct ast_module_user_list;
 enum ast_module_flags {
        AST_MODFLAG_DEFAULT = 0,
        AST_MODFLAG_GLOBAL_SYMBOLS = (1 << 0),
+       AST_MODFLAG_LOAD_ORDER = (1 << 1),
 };
 
 struct ast_module_info {
@@ -219,6 +220,13 @@ struct ast_module_info {
 
        /*! The value of AST_BUILDOPT_SUM when this module was compiled */
        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 *);
index 8ce96be..48e9bbb 100644 (file)
@@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/features.h"
 #include "asterisk/dsp.h"
 #include "asterisk/udptl.h"
+#include "asterisk/heap.h"
 
 #include <dlfcn.h>
 
@@ -712,11 +713,57 @@ 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 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;
        enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
-       char tmp[256];
 
        if ((mod = find_resource(resource_name, 0))) {
                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;
 
-       if (mod->info->load)
-               res = mod->info->load();
-
-       switch (res) {
-       case AST_MODULE_LOAD_SUCCESS:
-               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;
+       if (resource_heap) {
+               ast_heap_push(resource_heap, mod);
+               res = AST_MODULE_LOAD_SKIP;
+       } else {
+               res = start_resource(mod);
        }
 
        return res;
@@ -791,7 +818,7 @@ int ast_load_resource(const char *resource_name)
 {
        int res;
        AST_LIST_LOCK(&module_list);
-       res = load_resource(resource_name, 0);
+       res = load_resource(resource_name, 0, NULL);
        AST_LIST_UNLOCK(&module_list);
 
        return res;
@@ -822,6 +849,77 @@ static struct load_order_entry *add_to_load_order(const char *resource, struct l
        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)
 {
        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);
 
        /* 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;
-               }
+       if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
+               goto done;
        }
-       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;
-               }
+       if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
+               goto done;
        }
-       AST_LIST_TRAVERSE_SAFE_END;
 
 done:
        while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
index ae95cf9..f8235db 100644 (file)
@@ -199,4 +199,8 @@ static int unload_module(void)
        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,
+               );
index 86ae1bb..53ceeb5 100644 (file)
@@ -521,5 +521,8 @@ static int unload_module(void)
 
        return res;
 }
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "pthread Timing Interface");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "pthread Timing Interface",
+               .load = load_module,
+               .unload = unload_module,
+               .load_pri = 10,
+               );
index fb35ffb..b2ff89c 100644 (file)
@@ -286,4 +286,8 @@ static int unload_module(void)
        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,
+               );