<p>Corey Farrell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6987">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">RFC: Rewrite module loader ordering.<br><br>* Add "requires" field to module info.<br>* Reimplement load_dynamic_module to reduce the number of times we run<br>  dlopen.<br>* Remove global symbols only startup stage.<br>* Implement automatic references for dependent modules.<br><br>New startup order:<br>On startup we read modules.conf, build a list of module names we will<br>load.  We then iterate the list attempting to dlopen all modules.  We<br>repeat this process suppressing all errors until we cannot dlopen any<br>further modules.  If we were unable to dlopen anything modules.conf<br>declared as required we abort.  All modules that were successfully<br>opened are added to a vector ordered by load priority.  We start modules<br>in priority order except when we find an unmet dependency.  This forces<br>the unmet dependency to start earlier.  Unloading modules is restricted<br>by dependencies references.<br><br>TODO:<br>* The dependency checking is currently unforgiving and does a poor job<br>  logging the reason.<br>* Telling modules.conf to require a module is only half effective.  It<br>  only enforces that the module successfully load, but by the time we<br>  start the module our knowledge of the require directive is lost.  This<br>  is an existing bug found while working on this.<br>* Perform all startup dlopen's during preload so preload vs regular will<br>  only change when the modules are started.  This way when a module is<br>  set to preload but depends on a module that is only set to regular<br>  load, we will be able to load the other module early.  Currently the<br>  preload phase would fail to find the non-preload file as it wouldn't<br>  be registered yet.<br>* Testing: so far this has only passed the smoke test - it starts and<br>  stops without error when autoload is enabled.<br>* Investigate better ways to set the "requires" field.  Can it be<br>  generated from MODULEINFO or can the build process which extracts<br>  MODULEINFO also find the "requires" field and generate the depends<br>  nodes?<br>* Investigate dependencies among modules I cannot compile.<br>* Investigate how this affects realtime / sorcery backends.  Improved or<br>  made worse?  Same for other types of modules like codecs and formats.<br>* Make this thread safe.  Not entirely sure it was before.<br>* Review new symbol names.<br>* Remove redundent checks for dependent modules.<br>* Remove redundent module self references, for example in res_pjsip<br>  registration functions.<br>* Audit module load priorities.<br><br>Change-Id: I979ffb7caecc696ce0afa939193dfa76b19248e7<br>---<br>M apps/app_speech_utils.c<br>M apps/app_stasis.c<br>M channels/chan_motif.c<br>M channels/chan_pjsip.c<br>M channels/chan_rtp.c<br>M funcs/func_pjsip_aor.c<br>M funcs/func_pjsip_contact.c<br>M funcs/func_pjsip_endpoint.c<br>M include/asterisk/module.h<br>M main/loader.c<br>M pbx/pbx_ael.c<br>M res/ari/resource_asterisk.c<br>M res/res_agi.c<br>M res/res_ari.c<br>M res/res_ari_applications.c<br>M res/res_ari_asterisk.c<br>M res/res_ari_bridges.c<br>M res/res_ari_channels.c<br>M res/res_ari_device_states.c<br>M res/res_ari_endpoints.c<br>M res/res_ari_events.c<br>M res/res_ari_mailboxes.c<br>M res/res_ari_playbacks.c<br>M res/res_ari_recordings.c<br>M res/res_ari_sounds.c<br>M res/res_fax_spandsp.c<br>M res/res_hep_rtcp.c<br>M res/res_mwi_external_ami.c<br>M res/res_pjsip.c<br>M res/res_pjsip_acl.c<br>M res/res_pjsip_authenticator_digest.c<br>M res/res_pjsip_caller_id.c<br>M res/res_pjsip_config_wizard.c<br>M res/res_pjsip_dialog_info_body_generator.c<br>M res/res_pjsip_diversion.c<br>M res/res_pjsip_dlg_options.c<br>M res/res_pjsip_dtmf_info.c<br>M res/res_pjsip_empty_info.c<br>M res/res_pjsip_endpoint_identifier_anonymous.c<br>M res/res_pjsip_endpoint_identifier_ip.c<br>M res/res_pjsip_endpoint_identifier_user.c<br>M res/res_pjsip_exten_state.c<br>M res/res_pjsip_header_funcs.c<br>M res/res_pjsip_history.c<br>M res/res_pjsip_logger.c<br>M res/res_pjsip_messaging.c<br>M res/res_pjsip_mwi.c<br>M res/res_pjsip_mwi_body_generator.c<br>M res/res_pjsip_nat.c<br>M res/res_pjsip_notify.c<br>M res/res_pjsip_one_touch_record_info.c<br>M res/res_pjsip_outbound_authenticator_digest.c<br>M res/res_pjsip_outbound_publish.c<br>M res/res_pjsip_outbound_registration.c<br>M res/res_pjsip_path.c<br>M res/res_pjsip_phoneprov_provider.c<br>M res/res_pjsip_pidf_body_generator.c<br>M res/res_pjsip_pidf_digium_body_supplement.c<br>M res/res_pjsip_pidf_eyebeam_body_supplement.c<br>M res/res_pjsip_publish_asterisk.c<br>M res/res_pjsip_pubsub.c<br>M res/res_pjsip_refer.c<br>M res/res_pjsip_registrar.c<br>M res/res_pjsip_registrar_expire.c<br>M res/res_pjsip_rfc3326.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_send_to_voicemail.c<br>M res/res_pjsip_session.c<br>M res/res_pjsip_sips_contact.c<br>M res/res_pjsip_t38.c<br>M res/res_pjsip_transport_management.c<br>M res/res_pjsip_transport_websocket.c<br>M res/res_pjsip_xpidf_body_generator.c<br>M res/res_stasis_answer.c<br>M res/res_stasis_device_state.c<br>M res/res_stasis_mailbox.c<br>M res/res_stasis_playback.c<br>M res/res_stasis_recording.c<br>M res/res_stasis_snoop.c<br>M rest-api-templates/res_ari_resource.c.mustache<br>M tests/test_ari.c<br>M tests/test_ari_model.c<br>M tests/test_res_pjsip_scheduler.c<br>M tests/test_res_stasis.c<br>M tests/test_stasis_endpoints.c<br>85 files changed, 487 insertions(+), 241 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/87/6987/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/apps/app_speech_utils.c b/apps/app_speech_utils.c<br>index 3a6a191..11c57c8 100644<br>--- a/apps/app_speech_utils.c<br>+++ b/apps/app_speech_utils.c<br>@@ -1003,5 +1003,5 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_speech",<br>+ .requires = "res_speech",<br> );<br>diff --git a/apps/app_stasis.c b/apps/app_stasis.c<br>index 81c58e8..8d09349 100644<br>--- a/apps/app_stasis.c<br>+++ b/apps/app_stasis.c<br>@@ -144,5 +144,5 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis",<br>+ .requires = "res_stasis",<br> );<br>diff --git a/channels/chan_motif.c b/channels/chan_motif.c<br>index 210cf36..8cdea5a 100644<br>--- a/channels/chan_motif.c<br>+++ b/channels/chan_motif.c<br>@@ -2821,4 +2821,5 @@<br>  .unload = unload_module,<br>      .reload = reload,<br>     .load_pri = AST_MODPRI_CHANNEL_DRIVER,<br>+       .requires = "res_xmpp",<br> );<br>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c<br>index 7520c2b..7f1d058 100644<br>--- a/channels/chan_pjsip.c<br>+++ b/channels/chan_pjsip.c<br>@@ -3060,4 +3060,5 @@<br>    .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DRIVER,<br>+       .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c<br>index e1c29a2..5758d7c 100644<br>--- a/channels/chan_rtp.c<br>+++ b/channels/chan_rtp.c<br>@@ -431,4 +431,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DRIVER,<br>+       .requires = "res_rtp_multicast",<br> );<br>diff --git a/funcs/func_pjsip_aor.c b/funcs/func_pjsip_aor.c<br>index 799e9e4..589f667 100644<br>--- a/funcs/func_pjsip_aor.c<br>+++ b/funcs/func_pjsip_aor.c<br>@@ -181,4 +181,9 @@<br>         return ast_custom_function_register(&pjsip_aor_function);<br> }<br> <br>-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get information about a PJSIP AOR");<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get information about a PJSIP AOR",<br>+    .support_level = AST_MODULE_SUPPORT_CORE,<br>+    .load = load_module,<br>+ .unload = unload_module,<br>+     .requires = "res_pjsip",<br>+);<br>diff --git a/funcs/func_pjsip_contact.c b/funcs/func_pjsip_contact.c<br>index c840365..fac4cb6 100644<br>--- a/funcs/func_pjsip_contact.c<br>+++ b/funcs/func_pjsip_contact.c<br>@@ -198,4 +198,9 @@<br>         return ast_custom_function_register(&pjsip_contact_function);<br> }<br> <br>-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get information about a PJSIP contact");<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get information about a PJSIP contact",<br>+        .support_level = AST_MODULE_SUPPORT_CORE,<br>+    .load = load_module,<br>+ .unload = unload_module,<br>+     .requires = "res_pjsip",<br>+);<br>diff --git a/funcs/func_pjsip_endpoint.c b/funcs/func_pjsip_endpoint.c<br>index a64d93b..e4a6aba 100644<br>--- a/funcs/func_pjsip_endpoint.c<br>+++ b/funcs/func_pjsip_endpoint.c<br>@@ -156,4 +156,9 @@<br>     return ast_custom_function_register(&pjsip_endpoint_function);<br> }<br> <br>-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get information about a PJSIP endpoint");<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get information about a PJSIP endpoint",<br>+     .support_level = AST_MODULE_SUPPORT_CORE,<br>+    .load = load_module,<br>+ .unload = unload_module,<br>+     .requires = "res_pjsip",<br>+);<br>diff --git a/include/asterisk/module.h b/include/asterisk/module.h<br>index 69ebb26..22d18ce 100644<br>--- a/include/asterisk/module.h<br>+++ b/include/asterisk/module.h<br>@@ -68,8 +68,7 @@<br> enum ast_module_load_result {<br>       AST_MODULE_LOAD_SUCCESS = 0,    /*!< Module loaded and configured */<br>       AST_MODULE_LOAD_DECLINE = 1,    /*!< Module is not configured */<br>-  AST_MODULE_LOAD_SKIP = 2,       /*!< Module was skipped for some reason (For loader.c use only. Should never be returned by modules)*/<br>-    AST_MODULE_LOAD_PRIORITY = 3,   /*!< Module is not loaded yet, but is added to prioity heap */<br>+    AST_MODULE_LOAD_PRIORITY = 2,   /*!< Module is not loaded yet, but is added to priority list */<br>    AST_MODULE_LOAD_FAILURE = -1,   /*!< Module could not be loaded properly */<br> };<br> <br>@@ -338,9 +337,12 @@<br>  unsigned char load_pri;<br> <br>    /*! Modules which should be loaded first, in comma-separated string format.<br>-   * These are only required for loading, when the optional_api header file<br>-     * detects that the compiler does not support the optional API featureset. */<br>+         * These are only required if OPTIONAL_API is disabled. */<br>    const char *nonoptreq;<br>+<br>+    /*! Modules which must be started first, in comma-separated string format. */<br>+        const char *requires;<br>+<br>      /*! The support level for the given module */<br>         enum ast_module_support_level support_level;<br> };<br>diff --git a/main/loader.c b/main/loader.c<br>index add6a42..bb3e9d3 100644<br>--- a/main/loader.c<br>+++ b/main/loader.c<br>@@ -56,6 +56,7 @@<br> #include "asterisk/app.h"<br> #include "asterisk/test.h"<br> #include "asterisk/sounds_index.h"<br>+#include "asterisk/vector.h"<br> <br> #include <dlfcn.h><br> <br>@@ -115,6 +116,8 @@<br>  */<br> static int modules_loaded;<br> <br>+AST_VECTOR(module_vector, struct ast_module *);<br>+<br> struct ast_module {<br>         const struct ast_module_info *info;<br>   /* Used to get module references into refs log */<br>@@ -166,6 +169,20 @@<br>    is being registered<br> */<br> static struct ast_module *resource_being_loaded;<br>+<br>+static int module_requires_check(struct ast_module *mod, struct module_vector *deps, int all);<br>+<br>+#define CALLBACK_REF(dep_mod, mod) \<br>+       do { \<br>+               ast_debug(1, "Load of %s referencing %s\n", mod->resource, dep_mod->resource); \<br>+             __ast_module_ref(dep_mod, mod->resource, __LINE__, __PRETTY_FUNCTION__); \<br>+        } while (0)<br>+<br>+#define CALLBACK_UNREF(dep_mod, mod) \<br>+      do { \<br>+               ast_debug(1, "Unload of %s releasing %s\n", mod->resource, dep_mod->resource); \<br>+             __ast_module_unref(dep_mod, mod->resource, __LINE__, __PRETTY_FUNCTION__); \<br>+      } while (0)<br> <br> /* XXX: should we check for duplicate resource names here? */<br> <br>@@ -488,43 +505,42 @@<br> #endif<br> }<br> <br>-static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required);<br>-<br>-#define MODULE_LOCAL_ONLY (void *)-1<br>-<br>-static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap)<br>+/*!<br>+ * \internal<br>+ * \brief Perform actual calls to dlopen for a module.<br>+ *<br>+ * \param resource_in The module name to load.<br>+ * \param so_ext ".so" or blank if ".so" is already part of resource_in.<br>+ * \param flags Passed directly to dlopen.<br>+ * \param suppress_logging Do not log any error from dlopen.<br>+ *<br>+ * \return Pointer to opened module, NULL on error.<br>+ */<br>+static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext,<br>+   int flags, unsigned int suppress_logging)<br> {<br>-        char fn[PATH_MAX] = "";<br>-    void *lib = NULL;<br>     struct ast_module *mod;<br>-      unsigned int wants_global;<br>-   int space;      /* room needed for the descriptor */<br>- int missing_so = 0;<br>+  void *lib;<br>+   char fn[PATH_MAX];<br> <br>-        space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;<br>-    if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {<br>-            missing_so = 1;<br>-              space += 3;     /* room for the extra ".so" */<br>+     mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);<br>+        if (!mod) {<br>+          return NULL;<br>  }<br> <br>- snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");<br>+  sprintf(mod->resource, "%s%s", resource_in, so_ext);<br>+    snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);<br> <br>-    /* make a first load of the module in 'quiet' mode... don't try to resolve<br>-          any symbols, and don't export any symbols. this will allow us to peek into<br>-       the module's info block (if available) to see what flags it has set */<br>+        resource_being_loaded = mod;<br>+ lib = dlopen(fn, flags);<br>+     resource_being_loaded = NULL;<br> <br>-     resource_being_loaded = ast_calloc(1, space);<br>-        if (!resource_being_loaded)<br>-          return NULL;<br>- strcpy(resource_being_loaded->resource, resource_in);<br>-     if (missing_so)<br>-              strcat(resource_being_loaded->resource, ".so");<br>-<br>-      if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) {<br>+  if (!lib) {<br>           if (!suppress_logging) {<br>                      ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());<br>            }<br>-            ast_free(resource_being_loaded);<br>+             ast_free(mod);<br>+<br>             return NULL;<br>  }<br> <br>@@ -535,7 +551,7 @@<br>        constructor) places the new module at the tail of the<br>         module_list<br>        */<br>-   if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) {<br>+    if (mod != AST_DLLIST_LAST(&module_list)) {<br>               ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);<br>             /* no, it did not, so close it and return */<br>          logged_dlclose(resource_in, lib);<br>@@ -544,40 +560,39 @@<br>              return NULL;<br>  }<br> <br>- wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);<br>+      mod->lib = lib;<br> <br>-        /* if we are being asked only to load modules that provide global symbols,<br>-      and this one does not, then close it and return */<br>-        if (global_symbols_only && !wants_global) {<br>-          logged_dlclose(resource_in, lib);<br>-            return MODULE_LOCAL_ONLY;<br>+    return mod;<br>+}<br>+<br>+static struct ast_module *load_dynamic_module(const char *name, unsigned int suppress_logging)<br>+{<br>+      struct ast_module *mod;<br>+      size_t name_len = strlen(name);<br>+      const char *so_ext = "";<br>+<br>+        if (name_len < 4 || strcasecmp(name + name_len - 3, ".so")) {<br>+           so_ext = ".so";<br>     }<br> <br>- logged_dlclose(resource_in, lib);<br>-    resource_being_loaded = NULL;<br>-<br>-     /* start the load process again */<br>-   resource_being_loaded = ast_calloc(1, space);<br>-        if (!resource_being_loaded)<br>-          return NULL;<br>- strcpy(resource_being_loaded->resource, resource_in);<br>-     if (missing_so)<br>-              strcat(resource_being_loaded->resource, ".so");<br>-<br>-      if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {<br>-           ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());<br>-           ast_free(resource_being_loaded);<br>+     /* Most modules do not export symbols, start with that. */<br>+   mod = load_dlopen(name, so_ext, RTLD_NOW | RTLD_LOCAL, suppress_logging);<br>+    if (!mod) {<br>           return NULL;<br>  }<br> <br>- /* since the module was successfully opened, and it registered itself<br>-           the previous time we did that, we're going to assume it worked this<br>-      time too :) */<br>+    if (!ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {<br>+              return mod;<br>+  }<br> <br>- AST_DLLIST_LAST(&module_list)->lib = lib;<br>-     resource_being_loaded = NULL;<br>+        logged_dlclose(name, mod->lib);<br> <br>-        return AST_DLLIST_LAST(&module_list);<br>+    mod = load_dlopen(name, so_ext, RTLD_NOW | RTLD_GLOBAL, 0);<br>+  if (!mod) {<br>+          return NULL;<br>+ }<br>+<br>+ return mod;<br> }<br> <br> int modules_shutdown(void)<br>@@ -601,6 +616,8 @@<br>          somethingchanged = 0;<br> <br>              AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {<br>+                     struct module_vector deps;<br>+<br>                         if (!final && mod->usecount) {<br>                             ast_debug(1, "Passing on %s: its use count is %d\n",<br>                                        mod->resource, mod->usecount);<br>@@ -610,7 +627,16 @@<br>                    if (mod->flags.running && !mod->flags.declined && mod->info->unload) {<br>                            ast_verb(1, "Unloading %s\n", mod->resource);<br>                            mod->info->unload();<br>+<br>                         }<br>+<br>+                 if (mod->flags.running && !mod->flags.declined) {<br>+                              AST_VECTOR_INIT(&deps, 4);<br>+                               module_requires_check(mod, &deps, 1);<br>+                            AST_VECTOR_CALLBACK_VOID(&deps, CALLBACK_UNREF, mod);<br>+                            AST_VECTOR_FREE(&deps);<br>+                  }<br>+<br>                  AST_LIST_HEAD_DESTROY(&mod->users);<br>                    ao2_cleanup(mod->ref_debug);<br>                       ast_free(mod);<br>@@ -639,6 +665,7 @@<br>   struct ast_module *mod;<br>       int res = -1;<br>         int error = 0;<br>+       struct module_vector deps;<br> <br>         AST_DLLIST_LOCK(&module_list);<br> <br>@@ -689,8 +716,14 @@<br>           }<br>     }<br> <br>- if (!error)<br>+  if (!error) {<br>                 mod->flags.running = mod->flags.declined = 0;<br>+  }<br>+<br>+ AST_VECTOR_INIT(&deps, 4);<br>+       module_requires_check(mod, &deps, 1);<br>+    AST_VECTOR_CALLBACK_VOID(&deps, CALLBACK_UNREF, mod);<br>+    AST_VECTOR_FREE(&deps);<br> <br>        AST_DLLIST_UNLOCK(&module_list);<br> <br>@@ -1056,10 +1089,89 @@<br>      return 0;<br> }<br> <br>+static int module_vector_cmp(struct ast_module *a, struct ast_module *b)<br>+{<br>+      /* if load_pri is not set, default is 128.  Lower is better */<br>+       int a_pri = ast_test_flag(a->info, AST_MODFLAG_LOAD_ORDER) ? a->info->load_pri : 128;<br>+       int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER) ? b->info->load_pri : 128;<br>+<br>+    /*<br>+    * Returns comparison values for a min-heap<br>+   * <0 a_pri > b_pri<br>+     * =0 a_pri == b_pri<br>+  * >0 a_pri < b_pri<br>+     */<br>+  return a_pri - b_pri;<br>+}<br>+<br>+static int requires_string_check(const char *input, struct module_vector *deps,<br>+       int getrunning, int optional_api)<br>+{<br>+        char *list = ast_strdupa(input);<br>+     char *tmp;<br>+<br>+        if (!list) {<br>+         return -1;<br>+   }<br>+<br>+ while ((tmp = strsep(&list, ","))) {<br>+           struct ast_module *dep;<br>+<br>+           dep = find_resource(tmp, 0);<br>+         if (!dep) {<br>+                  ast_debug(1, "dep %s not found, optional_api=%d\n", tmp, optional_api);<br>+<br>+                 return optional_api ? 0 : -1;<br>+                }<br>+<br>+         if (getrunning && !dep->flags.running) {<br>+                  /* getrunning means all deps need to be running. */<br>+                  ast_debug(1, "We need %s running but didn't get it.\n", dep->resource);<br>+                     return -1;<br>+           }<br>+<br>+         if (!dep->flags.running || getrunning) {<br>+                  if (!deps) {<br>+                         ast_debug(1, "no 'deps' list and dep is not running: %s.", dep->resource);<br>+                              return -1;<br>+                   }<br>+<br>+                 /* Ignore duplicates */<br>+                      if (!AST_VECTOR_GET_CMP(deps, dep, AST_VECTOR_ELEM_DEFAULT_CMP)) {<br>+                           AST_VECTOR_APPEND(deps, dep);<br>+                        }<br>+            }<br>+    };<br>+<br>+        return 0;<br>+}<br>+<br>+#ifdef OPTIONAL_API<br>+#define NONOPT_IS_OPTIONAL 1<br>+#else<br>+#define NONOPT_IS_OPTIONAL 0<br>+#endif<br>+<br>+static int module_requires_check(struct ast_module *mod, struct module_vector *deps, int all)<br>+{<br>+ if (mod->info->requires && requires_string_check(mod->info->requires, deps, all, 0)) {<br>+           ast_debug(1, "%s is missing requires: %s\n", mod->resource, mod->info->requires);<br>+         return -1;<br>+   }<br>+<br>+ if (mod->info->nonoptreq && requires_string_check(mod->info->nonoptreq, deps, all, NONOPT_IS_OPTIONAL)) {<br>+                ast_debug(1, "%s is missing nonoptreq: %s\n", mod->resource, mod->info->nonoptreq);<br>+               return -1;<br>+   }<br>+<br>+ return 0;<br>+}<br>+<br> static enum ast_module_load_result start_resource(struct ast_module *mod)<br> {<br>      char tmp[256];<br>        enum ast_module_load_result res;<br>+     struct module_vector deps;<br> <br>         if (mod->flags.running) {<br>          return AST_MODULE_LOAD_SUCCESS;<br>@@ -1068,6 +1180,18 @@<br>       if (!mod->info->load) {<br>                 return AST_MODULE_LOAD_FAILURE;<br>       }<br>+<br>+ AST_VECTOR_INIT(&deps, 4);<br>+       /* This returns an error if any required dep isn't running, otherwise returns full list. */<br>+      if (module_requires_check(mod, &deps, 1)) {<br>+              mod->flags.declined = 1;<br>+          AST_VECTOR_FREE(&deps);<br>+<br>+               return -1;<br>+   }<br>+<br>+ /* This grabs a reference to all the required modules. */<br>+    AST_VECTOR_CALLBACK_VOID(&deps, CALLBACK_REF, mod);<br> <br>    if (!ast_fully_booted) {<br>              ast_verb(1, "Loading %s.\n", mod->resource);<br>@@ -1088,12 +1212,16 @@<br>            break;<br>        case AST_MODULE_LOAD_DECLINE:<br>                 mod->flags.declined = 1;<br>-          break;<br>+               /* fall-through */<br>    case AST_MODULE_LOAD_FAILURE:<br>-        case AST_MODULE_LOAD_SKIP: /* modules should never return this value */<br>+              /* We're not running so release the references. */<br>+               AST_VECTOR_CALLBACK_VOID(&deps, CALLBACK_UNREF, mod);<br>+            break;<br>        case AST_MODULE_LOAD_PRIORITY:<br>                break;<br>        }<br>+<br>+ AST_VECTOR_FREE(&deps);<br> <br>        /* Make sure the newly started module is at the end of the list */<br>    AST_DLLIST_LOCK(&module_list);<br>@@ -1104,36 +1232,27 @@<br>   return res;<br> }<br> <br>-/*! loads a resource based upon resource_name. If global_symbols_only is set<br>- *  only modules with global symbols will be loaded.<br>+/*! loads a resource based upon resource_name.<br>  *<br>- *  If the ast_heap is provided (not NULL) the module is found and added to the<br>- *  heap without running the module's load() function.  By doing this, modules<br>- *  added to the resource_heap can be initialized later in order by priority.<br>+ *  If the module_vector is provided (not NULL) the module is found and added to the<br>+ *  vector without running the module's load() function.  By doing this, modules<br>+ *  can be initialized later in order by priority and dependencies.<br>  *<br>- *  If the ast_heap is not provided, the module's load function will be executed<br>+ *  If the module_vector is not provided, the module's load function will be executed<br>  *  immediately */<br>-static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required)<br>+static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging, struct module_vector *module_vector, int required)<br> {<br>       struct ast_module *mod;<br>-      enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;<br>+   enum ast_module_load_result res;<br> <br>   if ((mod = find_resource(resource_name, 0))) {<br>                if (mod->flags.running) {<br>                  ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);<br>                       return AST_MODULE_LOAD_DECLINE;<br>               }<br>-            if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))<br>-                 return AST_MODULE_LOAD_SKIP;<br>  } else {<br>-             mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging, resource_heap);<br>-              if (mod == MODULE_LOCAL_ONLY) {<br>-                              return AST_MODULE_LOAD_SKIP;<br>-         }<br>+            mod = load_dynamic_module(resource_name, suppress_logging);<br>           if (!mod) {<br>-                  if (!global_symbols_only) {<br>-                          ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);<br>-                 }<br>                     return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;<br>          }<br>     }<br>@@ -1146,8 +1265,8 @@<br> <br>   mod->flags.declined = 0;<br> <br>-       if (resource_heap) {<br>-         ast_heap_push(resource_heap, mod);<br>+   if (module_vector) {<br>+         AST_VECTOR_ADD_SORTED(module_vector, mod, module_vector_cmp);<br>                 res = AST_MODULE_LOAD_PRIORITY;<br>       } else {<br>              res = start_resource(mod);<br>@@ -1160,7 +1279,7 @@<br> {<br>         int res;<br>      AST_DLLIST_LOCK(&module_list);<br>-   res = load_resource(resource_name, 0, 0, NULL, 0);<br>+   res = load_resource(resource_name, 0, NULL, 0);<br>       if (!res) {<br>           ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);<br>         }<br>@@ -1200,91 +1319,192 @@<br>   return order;<br> }<br> <br>-static int mod_load_cmp(void *a, void *b)<br>+/*!<br>+ * \brief Recursively check dependencies, optionally populating a vector.<br>+ *<br>+ * \retval 0 All dependencies resolved.<br>+ * \retval -1 Failed to resolve some dependencies.<br>+ *<br>+ * An error from this function usually means a required module is not even loaded.<br>+ *<br>+ * This function is safe from infinate recursion, but dependency loops are not<br>+ * reported as an error from here.<br>+ */<br>+static int find_missingdeps(struct ast_module *mod, struct module_vector *missingdeps)<br> {<br>-       struct ast_module *a_mod = (struct ast_module *) a;<br>-  struct ast_module *b_mod = (struct ast_module *) b;<br>-  /* if load_pri is not set, default is 128.  Lower is better */<br>-       int a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;<br>-       int b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;<br>+       int i = 0;<br>+   int res;<br>+     struct module_vector localdeps;<br>+      struct ast_module *tmp;<br> <br>-   /*<br>-    * Returns comparison values for a min-heap<br>-   * <0 a_pri > b_pri<br>-     * =0 a_pri == b_pri<br>-  * >0 a_pri < b_pri<br>-     */<br>-  return b_pri - a_pri;<br>+        AST_VECTOR_INIT(&localdeps, 4);<br>+  if (module_requires_check(mod, &localdeps, 0)) {<br>+         AST_VECTOR_FREE(&localdeps);<br>+<br>+          return -1;<br>+   }<br>+<br>+ while (i < AST_VECTOR_SIZE(&localdeps)) {<br>+             tmp = AST_VECTOR_GET(&localdeps, i);<br>+<br>+          if (AST_VECTOR_GET_CMP(missingdeps, tmp, AST_VECTOR_ELEM_DEFAULT_CMP)) {<br>+                     AST_VECTOR_REMOVE(&localdeps, i, 0);<br>+             } else {<br>+                     /* missingdeps is the real list so keep it sorted. */<br>+                        AST_VECTOR_ADD_SORTED(missingdeps, tmp, module_vector_cmp);<br>+                  i++;<br>+         }<br>+    }<br>+<br>+ res = 0;<br>+     while (!res && AST_VECTOR_SIZE(&localdeps)) {<br>+            tmp = AST_VECTOR_GET(&localdeps, 0);<br>+             AST_VECTOR_REMOVE(&localdeps, 0, 1);<br>+             res = find_missingdeps(tmp, missingdeps);<br>+            if (res) {<br>+                   break;<br>+               }<br>+    }<br>+<br>+ AST_VECTOR_FREE(&localdeps);<br>+<br>+  return res;<br> }<br> <br>-AST_LIST_HEAD_NOLOCK(load_retries, load_order_entry);<br>+static int try_module_start(struct ast_module *mod, int *count)<br>+{<br>+     static enum ast_module_load_result lres;<br>+<br>+  /* Quick non-recursive check. */<br>+     if (module_requires_check(mod, NULL, 0)) {<br>+           ast_debug(1, "Module %s is missing dependencies\n", mod->resource);<br>+             return -1;<br>+   }<br>+<br>+ lres = start_resource(mod);<br>+  ast_debug(3, "START: %-46s[%d] %d\n",<br>+              mod->resource,<br>+            ast_test_flag(mod->info, AST_MODFLAG_LOAD_ORDER) ? mod->info->load_pri : AST_MODPRI_DEFAULT,<br>+                lres);<br>+       if (lres == AST_MODULE_LOAD_FAILURE) {<br>+               ast_log(LOG_ERROR, "*** Failed to load module %s\n", mod->resource);<br>+<br>+         return -1;<br>+   }<br>+<br>+ if (lres == AST_MODULE_LOAD_SUCCESS) {<br>+               (*count)++;<br>+  }<br>+<br>+ return 0;<br>+}<br>+<br>+static int start_module_vector(struct module_vector *resources, int *mod_count)<br>+{<br>+       struct module_vector missingdeps;<br>+    int res = 0;<br>+<br>+      AST_VECTOR_INIT(&missingdeps, 0);<br>+        while (AST_VECTOR_SIZE(resources)) {<br>+         struct ast_module *mod = AST_VECTOR_REMOVE(resources, 0, 1);<br>+<br>+              if (!try_module_start(mod, mod_count)) {<br>+                     /* No missing dependencies, successful. */<br>+                   continue;<br>+            }<br>+<br>+         res = find_missingdeps(mod, &missingdeps);<br>+               if (res) {<br>+                   ast_debug(1, "Error from find_missingdeps for %s\n", mod->resource);<br>+                    /* This module likely requires something that isn't loaded. */<br>+                   break;<br>+               }<br>+<br>+         if (!AST_VECTOR_SIZE(&missingdeps)) {<br>+                    ast_log(LOG_WARNING, "%s isn't missing any dependencies but still didn't start\n", mod->resource);<br>+                      /* Dependencies were met but the module failed to start. */<br>+                  res = -1;<br>+                    break;<br>+               }<br>+<br>+         ast_debug(1, "%s has %d dependencies\n", mod->resource, (int)AST_VECTOR_SIZE(&missingdeps));<br>+                while (AST_VECTOR_SIZE(&missingdeps)) {<br>+                  int didwork = 0;<br>+                     int i = 0;<br>+<br>+                        while (i < AST_VECTOR_SIZE(&missingdeps)) {<br>+                           struct ast_module *tmp = AST_VECTOR_GET(&missingdeps, i);<br>+<br>+                             ast_debug(1, "%s trying to start %s\n", mod->resource, tmp->resource);<br>+                               if (!try_module_start(tmp, mod_count)) {<br>+                                     ast_debug(1, "%s started %s\n", mod->resource, tmp->resource);<br>+                                       AST_VECTOR_REMOVE(&missingdeps, i, 1);<br>+                                   AST_VECTOR_REMOVE_CMP_ORDERED(resources, tmp,<br>+                                                AST_VECTOR_ELEM_DEFAULT_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP);<br>+                                  didwork++;<br>+                                   continue;<br>+                            }<br>+                            ast_debug(1, "%s failed to start %s\n", mod->resource, tmp->resource);<br>+                               i++;<br>+                 }<br>+<br>+                 if (!didwork) {<br>+                              break;<br>+                       }<br>+            }<br>+<br>+         if (AST_VECTOR_SIZE(&missingdeps)) {<br>+                     ast_log(LOG_ERROR, "Failed to load %s due to unfilled dependencies.\n", mod->resource);<br>+                 /* We've failed to mod and it's load deps.  Really abort? */<br>+                 res = -1;<br>+                    break;<br>+               } else {<br>+                     res = try_module_start(mod, mod_count);<br>+                      if (res) {<br>+                           ast_log(LOG_ERROR, "Failed to load %s: %d\n", mod->resource, res);<br>+                              break;<br>+                       }<br>+            }<br>+    }<br>+<br>+ AST_VECTOR_FREE(&missingdeps);<br>+<br>+        return res;<br>+}<br> <br> /*! loads modules in order by load_pri, updates mod_count<br>        \return -1 on failure to load module, -2 on failure to load required module, otherwise 0<br> */<br>-static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)<br>+static int load_resource_list(struct load_order *load_order, int *mod_count)<br> {<br>- struct ast_heap *resource_heap;<br>-      struct load_order_entry *order;<br>-      struct ast_module *mod;<br>-      struct load_retries load_retries;<br>-    int count = 0;<br>+       struct module_vector resources;<br>       int res = 0;<br>  int i = 0;<br>-#define LOAD_RETRIES 4<br>+  int try_again = 1;<br>+   int action_taken = 0;<br> <br>-     AST_LIST_HEAD_INIT_NOLOCK(&load_retries);<br>+        AST_VECTOR_INIT(&resources, 10);<br> <br>-      if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {<br>-                return -1;<br>-   }<br>+    /*<br>+    * This loops until one iteration after nothing is done. Once we iterate the<br>+  * full load_order list without loading anything it's impossible to make further<br>+  * progress.  We run the loop again so we can log messages for any required<br>+   * modules that failed.<br>+       */<br>+  do {<br>+         struct load_order_entry *order;<br> <br>-   /* first, add find and add modules to heap */<br>-        AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {<br>-             enum ast_module_load_result lres;<br>-<br>-         /* Suppress log messages unless this is the last pass */<br>-             lres = load_resource(order->resource, global_symbols, 1, resource_heap, order->required);<br>-              ast_debug(3, "PASS 0: %-46s %d %d\n", order->resource, lres, global_symbols);<br>-           switch (lres) {<br>-              case AST_MODULE_LOAD_SUCCESS:<br>-                        /* We're supplying a heap so SUCCESS isn't possible but we still have to test for it. */<br>-                     break;<br>-               case AST_MODULE_LOAD_FAILURE:<br>-                case AST_MODULE_LOAD_DECLINE:<br>-                        /*<br>-                    * DECLINE or FAILURE means there was an issue with dlopen or module_register<br>-                         * which might be retryable.  LOAD_FAILURE only happens for required modules<br>-                  * but we're still going to retry.  We need to remove the entry from the<br>-                  * load_order list and add it to the load_retries list.<br>-                       */<br>-                  AST_LIST_REMOVE_CURRENT(entry);<br>-                      AST_LIST_INSERT_TAIL(&load_retries, order, entry);<br>-                       break;<br>-               case AST_MODULE_LOAD_SKIP:<br>-                   /*<br>-                    * SKIP means that dlopen worked but global_symbols was set and this module doesn't qualify.<br>-                      * Leave it in load_order for the next call of load_resource_list.<br>-                    */<br>-                  break;<br>-               case AST_MODULE_LOAD_PRIORITY:<br>-                       /* load_resource worked and the module was added to the priority heap */<br>-                     AST_LIST_REMOVE_CURRENT(entry);<br>-                      ast_free(order->resource);<br>-                        ast_free(order);<br>-                     break;<br>+               if (!action_taken && i) {<br>+                    try_again = 0;<br>                }<br>-    }<br>-    AST_LIST_TRAVERSE_SAFE_END;<br>+          action_taken = 0;<br> <br>- /* Retry the failures until the list is empty or we reach LOAD_RETRIES */<br>-    for (i = 0; !AST_LIST_EMPTY(&load_retries) && i < LOAD_RETRIES; i++) {<br>-                AST_LIST_TRAVERSE_SAFE_BEGIN(&load_retries, order, entry) {<br>+              AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {<br>                      enum ast_module_load_result lres;<br> <br>                  /* Suppress log messages unless this is the last pass */<br>-                     lres = load_resource(order->resource, global_symbols, (i < LOAD_RETRIES - 1), resource_heap, order->required);<br>-                      ast_debug(3, "PASS %d %-46s %d %d\n", i + 1, order->resource, lres, global_symbols);<br>+                    lres =  load_resource(order->resource, try_again, &resources, order->required);<br>+                    ast_debug(3, "PASS %d %-46s %d\n", i, order->resource, lres);<br>                    switch (lres) {<br>                       /* These are all retryable. */<br>                        case AST_MODULE_LOAD_SUCCESS:<br>@@ -1292,66 +1512,33 @@<br>                                break;<br>                        case AST_MODULE_LOAD_FAILURE:<br>                                 /* LOAD_FAILURE only happens for required modules */<br>-                         if (i == LOAD_RETRIES - 1) {<br>-                                 /* This was the last chance to load a required module*/<br>+                              if (!try_again) {<br>                                     ast_log(LOG_ERROR, "*** Failed to load module %s - Required\n", order->resource);<br>                                        fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);<br>                                   res =  -2;<br>-                                   goto done;<br>                            }<br>-                            break;;<br>-                      case AST_MODULE_LOAD_SKIP:<br>-                           /*<br>-                            * SKIP means that dlopen worked but global_symbols was set and this module<br>-                           * doesn't qualify.  Put it back in load_order for the next call of<br>-                               * load_resource_list.<br>-                                */<br>-                          AST_LIST_REMOVE_CURRENT(entry);<br>-                              AST_LIST_INSERT_TAIL(load_order, order, entry);<br>                               break;<br>                        case AST_MODULE_LOAD_PRIORITY:<br>-                               /* load_resource worked and the module was added to the priority heap */<br>+                             /* load_resource worked and the module was added to the priority vector */<br>                            AST_LIST_REMOVE_CURRENT(entry);<br>                               ast_free(order->resource);<br>                                 ast_free(order);<br>+                             action_taken++;<br>                               break;<br>                        }<br>             }<br>             AST_LIST_TRAVERSE_SAFE_END;<br>-  }<br> <br>- /* second remove modules from heap sorted by priority */<br>-     while ((mod = ast_heap_pop(resource_heap))) {<br>-                enum ast_module_load_result lres;<br>-<br>-         lres = start_resource(mod);<br>-          ast_debug(3, "START: %-46s %d %d\n", mod->resource, lres, global_symbols);<br>-              switch (lres) {<br>-              case AST_MODULE_LOAD_SUCCESS:<br>-                        count++;<br>-             case AST_MODULE_LOAD_DECLINE:<br>-                        break;<br>-               case AST_MODULE_LOAD_FAILURE:<br>-                        ast_log(LOG_ERROR, "*** Failed to load module %s\n", mod->resource);<br>-                    res = -1;<br>+            if (res == -2) {<br>                      goto done;<br>-           case AST_MODULE_LOAD_SKIP:<br>-           case AST_MODULE_LOAD_PRIORITY:<br>-                       break;<br>                }<br>-    }<br> <br>+         i++;<br>+ } while (try_again);<br>+<br>+      res = start_module_vector(&resources, mod_count);<br> done:<br>-<br>-     while ((order = AST_LIST_REMOVE_HEAD(&load_retries, entry))) {<br>-           ast_free(order->resource);<br>-                ast_free(order);<br>-     }<br>-<br>- if (mod_count) {<br>-             *mod_count += count;<br>- }<br>-    ast_heap_destroy(resource_heap);<br>+     AST_VECTOR_FREE(&resources);<br> <br>   return res;<br> }<br>@@ -1453,15 +1640,7 @@<br>       if (load_count)<br>               ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);<br> <br>-        /* first, load only modules that provide global symbols */<br>-   if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {<br>-               goto done;<br>-   }<br>-<br>- /* now load everything else */<br>-       if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {<br>-               goto done;<br>-   }<br>+    res = load_resource_list(&load_order, &modulecount);<br> <br> done:<br>       while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {<br>diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c<br>index 8ad4914..71cec1d 100644<br>--- a/pbx/pbx_ael.c<br>+++ b/pbx/pbx_ael.c<br>@@ -292,6 +292,7 @@<br>    .load = load_module,<br>  .unload = unload_module,<br>      .reload = reload,<br>+    .requires = "res_ael_share",<br> );<br> <br> #ifdef AAL_ARGCHECK<br>diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c<br>index e76eb02..d357093 100644<br>--- a/res/ari/resource_asterisk.c<br>+++ b/res/ari/resource_asterisk.c<br>@@ -533,11 +533,6 @@<br>                       response, 409, "Conflict",<br>                  "Module load declined");<br>            return;<br>-      } else if (load_result == AST_MODULE_LOAD_SKIP) {<br>-            ast_ari_response_error(<br>-                      response, 409, "Conflict",<br>-                 "Module was skipped");<br>-             return;<br>       } else if (load_result == AST_MODULE_LOAD_FAILURE) {<br>          ast_ari_response_error(<br>                       response, 409, "Conflict",<br>diff --git a/res/res_agi.c b/res/res_agi.c<br>index 4660635..1be8685 100644<br>--- a/res/res_agi.c<br>+++ b/res/res_agi.c<br>@@ -4721,4 +4721,5 @@<br>      .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_speech",<br> );<br>diff --git a/res/res_ari.c b/res/res_ari.c<br>index 5145499..362f5d5 100644<br>--- a/res/res_ari.c<br>+++ b/res/res_ari.c<br>@@ -1195,5 +1195,6 @@<br>  .unload = unload_module,<br>      .reload = reload_module,<br>      .nonoptreq = "res_http_websocket",<br>+ .requires = "res_stasis",<br>   .load_pri = AST_MODPRI_APP_DEPEND,<br> );<br>diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c<br>index cf700c4..323bdb3 100644<br>--- a/res/res_ari_applications.c<br>+++ b/res/res_ari_applications.c<br>@@ -518,5 +518,5 @@<br>         .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c<br>index eb0617b..9f76f93 100644<br>--- a/res/res_ari_asterisk.c<br>+++ b/res/res_ari_asterisk.c<br>@@ -1239,5 +1239,5 @@<br>        .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c<br>index 35fd3bd..34b9d89 100644<br>--- a/res/res_ari_bridges.c<br>+++ b/res/res_ari_bridges.c<br>@@ -1579,5 +1579,5 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c<br>index f6befcc..7862c10 100644<br>--- a/res/res_ari_channels.c<br>+++ b/res/res_ari_channels.c<br>@@ -2869,5 +2869,5 @@<br>        .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c<br>index f393935..ec8890b 100644<br>--- a/res/res_ari_device_states.c<br>+++ b/res/res_ari_device_states.c<br>@@ -349,5 +349,5 @@<br>      .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c<br>index d1242c0..07197ca 100644<br>--- a/res/res_ari_endpoints.c<br>+++ b/res/res_ari_endpoints.c<br>@@ -473,5 +473,5 @@<br>      .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_events.c b/res/res_ari_events.c<br>index f916d0e..f750a54 100644<br>--- a/res/res_ari_events.c<br>+++ b/res/res_ari_events.c<br>@@ -473,5 +473,5 @@<br>  .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c<br>index 1f6d2cc..6469f93 100644<br>--- a/res/res_ari_mailboxes.c<br>+++ b/res/res_ari_mailboxes.c<br>@@ -355,5 +355,5 @@<br>      .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c<br>index 40099cf..0148a74 100644<br>--- a/res/res_ari_playbacks.c<br>+++ b/res/res_ari_playbacks.c<br>@@ -307,5 +307,5 @@<br>      .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c<br>index fe3d343..531ff65 100644<br>--- a/res/res_ari_recordings.c<br>+++ b/res/res_ari_recordings.c<br>@@ -891,5 +891,5 @@<br>  .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c<br>index 8d5928a..5c27ebd 100644<br>--- a/res/res_ari_sounds.c<br>+++ b/res/res_ari_sounds.c<br>@@ -237,5 +237,5 @@<br>  .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br>diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c<br>index 540a902..93c699b 100644<br>--- a/res/res_fax_spandsp.c<br>+++ b/res/res_fax_spandsp.c<br>@@ -1266,4 +1266,5 @@<br>    .support_level = AST_MODULE_SUPPORT_EXTENDED,<br>         .load = load_module,<br>  .unload = unload_module,<br>+     .requires = "res_fax",<br> );<br>diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c<br>index 31b9c48..380c7de 100644<br>--- a/res/res_hep_rtcp.c<br>+++ b/res/res_hep_rtcp.c<br>@@ -185,4 +185,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_DEFAULT,<br>+      .requires = "res_hep",<br> );<br>diff --git a/res/res_mwi_external_ami.c b/res/res_mwi_external_ami.c<br>index 516969b..5516475 100644<br>--- a/res/res_mwi_external_ami.c<br>+++ b/res/res_mwi_external_ami.c<br>@@ -370,5 +370,7 @@<br>   .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>+     .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,<br>+   .requires = "res_mwi_external",<br> );<br> <br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index 7499ded..8e89820 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -4960,4 +4960,5 @@<br>         .unload = unload_module,<br>      .reload = reload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,<br>+   .requires = "res_pjproject",<br> );<br>diff --git a/res/res_pjsip_acl.c b/res/res_pjsip_acl.c<br>index 5c10e57..9269864 100644<br>--- a/res/res_pjsip_acl.c<br>+++ b/res/res_pjsip_acl.c<br>@@ -321,4 +321,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c<br>index ef57e37..b6f2b74 100644<br>--- a/res/res_pjsip_authenticator_digest.c<br>+++ b/res/res_pjsip_authenticator_digest.c<br>@@ -554,4 +554,5 @@<br>         .unload = unload_module,<br>      .reload = reload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c<br>index 64191a7..1673147 100644<br>--- a/res/res_pjsip_caller_id.c<br>+++ b/res/res_pjsip_caller_id.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>     <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -764,4 +763,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c<br>index 1526dc2..f85ff5b 100644<br>--- a/res/res_pjsip_config_wizard.c<br>+++ b/res/res_pjsip_config_wizard.c<br>@@ -1336,4 +1336,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_REALTIME_DRIVER,<br>+      .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c<br>index 7c386e3..866ea9d 100644<br>--- a/res/res_pjsip_dialog_info_body_generator.c<br>+++ b/res/res_pjsip_dialog_info_body_generator.c<br>@@ -20,7 +20,6 @@<br>   <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>        <depend>res_pjsip_pubsub</depend><br>-        <depend>res_pjsip_exten_state</depend><br>    <support_level>core</support_level><br>  ***/<br> <br>@@ -219,4 +218,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c<br>index efb5489..84c42dc 100644<br>--- a/res/res_pjsip_diversion.c<br>+++ b/res/res_pjsip_diversion.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>    <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -429,4 +428,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_dlg_options.c b/res/res_pjsip_dlg_options.c<br>index e2ed29a..ac230af 100644<br>--- a/res/res_pjsip_dlg_options.c<br>+++ b/res/res_pjsip_dlg_options.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>     <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br> ***/<br> <br>@@ -102,4 +101,5 @@<br>        .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c<br>index e534f3e..68df617 100644<br>--- a/res/res_pjsip_dtmf_info.c<br>+++ b/res/res_pjsip_dtmf_info.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>     <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -178,4 +177,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c<br>index 774f9de..c67835c 100644<br>--- a/res/res_pjsip_empty_info.c<br>+++ b/res/res_pjsip_empty_info.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>         <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -84,4 +83,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_endpoint_identifier_anonymous.c b/res/res_pjsip_endpoint_identifier_anonymous.c<br>index a529466..207d2cf 100644<br>--- a/res/res_pjsip_endpoint_identifier_anonymous.c<br>+++ b/res/res_pjsip_endpoint_identifier_anonymous.c<br>@@ -129,4 +129,5 @@<br>     .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_DEFAULT,<br>+      .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c<br>index 8b92cef..2b59663 100644<br>--- a/res/res_pjsip_endpoint_identifier_ip.c<br>+++ b/res/res_pjsip_endpoint_identifier_ip.c<br>@@ -728,4 +728,5 @@<br>         .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c<br>index 369cb62..7f22a7f 100644<br>--- a/res/res_pjsip_endpoint_identifier_user.c<br>+++ b/res/res_pjsip_endpoint_identifier_user.c<br>@@ -210,4 +210,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c<br>index 95a4082..14f086d 100644<br>--- a/res/res_pjsip_exten_state.c<br>+++ b/res/res_pjsip_exten_state.c<br>@@ -1012,4 +1012,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5,<br>+   .requires = "res_pjsip,res_pjsip_pubsub,res_pjsip_outbound_publish",<br> );<br>diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c<br>index 648f1c8..06fba06 100644<br>--- a/res/res_pjsip_header_funcs.c<br>+++ b/res/res_pjsip_header_funcs.c<br>@@ -629,4 +629,5 @@<br>     .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c<br>index 4e7dbd0..91eb559 100644<br>--- a/res/res_pjsip_history.c<br>+++ b/res/res_pjsip_history.c<br>@@ -1387,4 +1387,5 @@<br>                 .load = load_module,<br>          .unload = unload_module,<br>              .load_pri = AST_MODPRI_APP_DEPEND,<br>+           .requires = "res_pjsip",<br>    );<br>diff --git a/res/res_pjsip_logger.c b/res/res_pjsip_logger.c<br>index d29a6e2..460b6a3 100644<br>--- a/res/res_pjsip_logger.c<br>+++ b/res/res_pjsip_logger.c<br>@@ -262,4 +262,5 @@<br>      .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c<br>index b6e7a64..3739bcf 100644<br>--- a/res/res_pjsip_messaging.c<br>+++ b/res/res_pjsip_messaging.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>     <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -850,4 +849,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c<br>index 5423038..92dc7dc 100644<br>--- a/res/res_pjsip_mwi.c<br>+++ b/res/res_pjsip_mwi.c<br>@@ -1397,4 +1397,5 @@<br>   .unload = unload_module,<br>      .reload = reload,<br>     .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5,<br>+   .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c<br>index e827910..65ac600 100644<br>--- a/res/res_pjsip_mwi_body_generator.c<br>+++ b/res/res_pjsip_mwi_body_generator.c<br>@@ -116,4 +116,5 @@<br>        .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c<br>index e1d56e6..4231a1e 100644<br>--- a/res/res_pjsip_nat.c<br>+++ b/res/res_pjsip_nat.c<br>@@ -378,4 +378,5 @@<br>    .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c<br>index 8de88c7..5b18148 100644<br>--- a/res/res_pjsip_notify.c<br>+++ b/res/res_pjsip_notify.c<br>@@ -1032,4 +1032,5 @@<br>       .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c<br>index ec5f9be..ef59fca 100644<br>--- a/res/res_pjsip_one_touch_record_info.c<br>+++ b/res/res_pjsip_one_touch_record_info.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>      <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br> ***/<br> <br>@@ -129,4 +128,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c<br>index 7e2d711..54bba08 100644<br>--- a/res/res_pjsip_outbound_authenticator_digest.c<br>+++ b/res/res_pjsip_outbound_authenticator_digest.c<br>@@ -224,4 +224,5 @@<br>     .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c<br>index 0fac8ad..1f4f9ab 100644<br>--- a/res/res_pjsip_outbound_publish.c<br>+++ b/res/res_pjsip_outbound_publish.c<br>@@ -1700,4 +1700,5 @@<br>       .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjproject,res_pjsip",<br> );<br>diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c<br>index 4697e5c..01d35d3 100644<br>--- a/res/res_pjsip_outbound_registration.c<br>+++ b/res/res_pjsip_outbound_registration.c<br>@@ -2288,4 +2288,5 @@<br>     .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c<br>index e170a75..b245f15 100644<br>--- a/res/res_pjsip_path.c<br>+++ b/res/res_pjsip_path.c<br>@@ -264,4 +264,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_phoneprov_provider.c b/res/res_pjsip_phoneprov_provider.c<br>index eef3a08..642d71d 100644<br>--- a/res/res_pjsip_phoneprov_provider.c<br>+++ b/res/res_pjsip_phoneprov_provider.c<br>@@ -417,4 +417,5 @@<br>         .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip,res_phoneprov",<br> );<br>diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c<br>index 29c9e6b..6426dfa 100644<br>--- a/res/res_pjsip_pidf_body_generator.c<br>+++ b/res/res_pjsip_pidf_body_generator.c<br>@@ -135,4 +135,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_pidf_digium_body_supplement.c b/res/res_pjsip_pidf_digium_body_supplement.c<br>index 93e4982..f855e21 100644<br>--- a/res/res_pjsip_pidf_digium_body_supplement.c<br>+++ b/res/res_pjsip_pidf_digium_body_supplement.c<br>@@ -114,4 +114,5 @@<br>    .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c<br>index 4047084..6629aa3 100644<br>--- a/res/res_pjsip_pidf_eyebeam_body_supplement.c<br>+++ b/res/res_pjsip_pidf_eyebeam_body_supplement.c<br>@@ -111,4 +111,5 @@<br>        .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c<br>index fa5e4ce..5bb5cee 100644<br>--- a/res/res_pjsip_publish_asterisk.c<br>+++ b/res/res_pjsip_publish_asterisk.c<br>@@ -932,4 +932,5 @@<br>        .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5,<br>+   .requires = "res_pjsip,res_pjsip_outbound_publish,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c<br>index 62b1879..773b1ef 100644<br>--- a/res/res_pjsip_pubsub.c<br>+++ b/res/res_pjsip_pubsub.c<br>@@ -5491,4 +5491,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c<br>index 62f8b67..f823385 100644<br>--- a/res/res_pjsip_refer.c<br>+++ b/res/res_pjsip_refer.c<br>@@ -1229,4 +1229,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c<br>index 3290601..6551917 100644<br>--- a/res/res_pjsip_registrar.c<br>+++ b/res/res_pjsip_registrar.c<br>@@ -1116,4 +1116,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3,<br>+   .requires = "res_pjproject,res_pjsip",<br> );<br>diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c<br>index fe4a60d..85e3fb8 100644<br>--- a/res/res_pjsip_registrar_expire.c<br>+++ b/res/res_pjsip_registrar_expire.c<br>@@ -150,4 +150,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_rfc3326.c b/res/res_pjsip_rfc3326.c<br>index d49a170..8b8035e 100644<br>--- a/res/res_pjsip_rfc3326.c<br>+++ b/res/res_pjsip_rfc3326.c<br>@@ -19,7 +19,6 @@<br> /*** MODULEINFO<br>     <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>-       <depend>res_pjsip_session</depend><br>        <support_level>core</support_level><br>  ***/<br> <br>@@ -156,4 +155,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c<br>index a877582..7bff88f 100644<br>--- a/res/res_pjsip_sdp_rtp.c<br>+++ b/res/res_pjsip_sdp_rtp.c<br>@@ -1969,4 +1969,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DRIVER,<br>+       .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c<br>index 1cd28ce..06c3edc 100644<br>--- a/res/res_pjsip_send_to_voicemail.c<br>+++ b/res/res_pjsip_send_to_voicemail.c<br>@@ -236,4 +236,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 4724d46..455e889 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -4152,4 +4152,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_sips_contact.c b/res/res_pjsip_sips_contact.c<br>index 7579be6..41b26df 100644<br>--- a/res/res_pjsip_sips_contact.c<br>+++ b/res/res_pjsip_sips_contact.c<br>@@ -104,4 +104,5 @@<br>         .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c<br>index 48cbab3..203f043 100644<br>--- a/res/res_pjsip_t38.c<br>+++ b/res/res_pjsip_t38.c<br>@@ -1044,4 +1044,5 @@<br>   .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DRIVER,<br>+       .requires = "res_pjsip,res_pjsip_session",<br> );<br>diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c<br>index eb92eb7..acffb86 100644<br>--- a/res/res_pjsip_transport_management.c<br>+++ b/res/res_pjsip_transport_management.c<br>@@ -397,4 +397,5 @@<br>       .reload = reload_module,<br>      .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,<br>+   .requires = "res_pjsip",<br> );<br>diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c<br>index 22ec195..7c8ec08 100644<br>--- a/res/res_pjsip_transport_websocket.c<br>+++ b/res/res_pjsip_transport_websocket.c<br>@@ -520,4 +520,5 @@<br>     .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_APP_DEPEND,<br>+   .requires = "res_pjsip,res_http_websocket",<br> );<br>diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c<br>index 41f6224..f7c84db 100644<br>--- a/res/res_pjsip_xpidf_body_generator.c<br>+++ b/res/res_pjsip_xpidf_body_generator.c<br>@@ -20,7 +20,6 @@<br>        <depend>pjproject</depend><br>        <depend>res_pjsip</depend><br>        <depend>res_pjsip_pubsub</depend><br>-        <depend>res_pjsip_exten_state</depend><br>    <support_level>core</support_level><br>  ***/<br> <br>@@ -177,4 +176,5 @@<br>       .load = load_module,<br>  .unload = unload_module,<br>      .load_pri = AST_MODPRI_CHANNEL_DEPEND,<br>+       .requires = "res_pjsip,res_pjsip_pubsub",<br> );<br>diff --git a/res/res_stasis_answer.c b/res/res_stasis_answer.c<br>index 407a631..6ec50c8 100644<br>--- a/res/res_stasis_answer.c<br>+++ b/res/res_stasis_answer.c<br>@@ -73,5 +73,5 @@<br>      .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis"<br>+  .requires = "res_stasis",<br> );<br>diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c<br>index 276a98b..1c209e8 100644<br>--- a/res/res_stasis_device_state.c<br>+++ b/res/res_stasis_device_state.c<br>@@ -482,5 +482,5 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis"<br>+  .requires = "res_stasis",<br> );<br>diff --git a/res/res_stasis_mailbox.c b/res/res_stasis_mailbox.c<br>index 4522adc..eb618cb 100644<br>--- a/res/res_stasis_mailbox.c<br>+++ b/res/res_stasis_mailbox.c<br>@@ -160,5 +160,5 @@<br>        .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis,res_mwi_external"<br>+ .requires = "res_stasis,res_mwi_external"<br> );<br>diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c<br>index c6f2136..aeb6d0e 100644<br>--- a/res/res_stasis_playback.c<br>+++ b/res/res_stasis_playback.c<br>@@ -755,5 +755,5 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis,res_stasis_recording"<br>+     .requires = "res_stasis,res_stasis_recording"<br> );<br>diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c<br>index 56984cb..17213aa 100644<br>--- a/res/res_stasis_recording.c<br>+++ b/res/res_stasis_recording.c<br>@@ -655,6 +655,6 @@<br>    .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis",<br>+ .requires = "res_stasis",<br>   .load_pri = AST_MODPRI_APP_DEPEND<br> );<br>diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c<br>index f797a9b..b234de1 100644<br>--- a/res/res_stasis_snoop.c<br>+++ b/res/res_stasis_snoop.c<br>@@ -445,5 +445,5 @@<br>  .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis"<br>+  .requires = "res_stasis",<br> );<br>diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache<br>index d4ccda9..c1f680f 100644<br>--- a/rest-api-templates/res_ari_resource.c.mustache<br>+++ b/rest-api-templates/res_ari_resource.c.mustache<br>@@ -324,6 +324,6 @@<br>        .support_level = AST_MODULE_SUPPORT_CORE,<br>     .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari,res_stasis",<br>+ .requires = "res_ari,res_ari_model,res_stasis",<br> );<br> {{/api_declaration}}<br>diff --git a/tests/test_ari.c b/tests/test_ari.c<br>index bce5f95..a5db228 100644<br>--- a/tests/test_ari.c<br>+++ b/tests/test_ari.c<br>@@ -573,5 +573,5 @@<br> AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ARI testing",<br>         .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_ari",<br>+    .requires = "res_ari",<br> );<br>diff --git a/tests/test_ari_model.c b/tests/test_ari_model.c<br>index caf4118..e5a96cd 100644<br>--- a/tests/test_ari_model.c<br>+++ b/tests/test_ari_model.c<br>@@ -452,4 +452,9 @@<br>   return AST_MODULE_LOAD_SUCCESS;<br> }<br> <br>-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Test");<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skeleton (sample) Test",<br>+        .support_level = AST_MODULE_SUPPORT_CORE,<br>+    .load = load_module,<br>+ .unload = unload_module,<br>+     .requires = "res_ari_model",<br>+);<br>diff --git a/tests/test_res_pjsip_scheduler.c b/tests/test_res_pjsip_scheduler.c<br>index da51d43..47a7034 100644<br>--- a/tests/test_res_pjsip_scheduler.c<br>+++ b/tests/test_res_pjsip_scheduler.c<br>@@ -396,4 +396,9 @@<br>     return 0;<br> }<br> <br>-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "res_pjsip scheduler test module");<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "res_pjsip scheduler test module",<br>+    .support_level = AST_MODULE_SUPPORT_CORE,<br>+    .load = load_module,<br>+ .unload = unload_module,<br>+     .requires = "res_pjsip",<br>+);<br>diff --git a/tests/test_res_stasis.c b/tests/test_res_stasis.c<br>index cb79fa6..077cc4c 100644<br>--- a/tests/test_res_stasis.c<br>+++ b/tests/test_res_stasis.c<br>@@ -195,5 +195,5 @@<br> AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Stasis Core testing",<br>   .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis",<br>+ .requires = "res_stasis",<br> );<br>diff --git a/tests/test_stasis_endpoints.c b/tests/test_stasis_endpoints.c<br>index 134738f..42c7532 100644<br>--- a/tests/test_stasis_endpoints.c<br>+++ b/tests/test_stasis_endpoints.c<br>@@ -306,5 +306,5 @@<br> AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint stasis-related testing",<br>      .load = load_module,<br>  .unload = unload_module,<br>-     .nonoptreq = "res_stasis_test",<br>+    .requires = "res_stasis_test",<br> );<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6987">change 6987</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6987"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I979ffb7caecc696ce0afa939193dfa76b19248e7 </div>
<div style="display:none"> Gerrit-Change-Number: 6987 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>