[Asterisk-code-review] RFC: Rewrite module loader ordering. (asterisk[master])

Corey Farrell asteriskteam at digium.com
Fri Nov 3 15:14:20 CDT 2017


Corey Farrell has uploaded this change for review. ( https://gerrit.asterisk.org/6987


Change subject: RFC: Rewrite module loader ordering.
......................................................................

RFC: Rewrite module loader ordering.

* Add "requires" field to module info.
* Reimplement load_dynamic_module to reduce the number of times we run
  dlopen.
* Remove global symbols only startup stage.
* Implement automatic references for dependent modules.

New startup order:
On startup we read modules.conf, build a list of module names we will
load.  We then iterate the list attempting to dlopen all modules.  We
repeat this process suppressing all errors until we cannot dlopen any
further modules.  If we were unable to dlopen anything modules.conf
declared as required we abort.  All modules that were successfully
opened are added to a vector ordered by load priority.  We start modules
in priority order except when we find an unmet dependency.  This forces
the unmet dependency to start earlier.  Unloading modules is restricted
by dependencies references.

TODO:
* The dependency checking is currently unforgiving and does a poor job
  logging the reason.
* Telling modules.conf to require a module is only half effective.  It
  only enforces that the module successfully load, but by the time we
  start the module our knowledge of the require directive is lost.  This
  is an existing bug found while working on this.
* Perform all startup dlopen's during preload so preload vs regular will
  only change when the modules are started.  This way when a module is
  set to preload but depends on a module that is only set to regular
  load, we will be able to load the other module early.  Currently the
  preload phase would fail to find the non-preload file as it wouldn't
  be registered yet.
* Testing: so far this has only passed the smoke test - it starts and
  stops without error when autoload is enabled.
* Investigate better ways to set the "requires" field.  Can it be
  generated from MODULEINFO or can the build process which extracts
  MODULEINFO also find the "requires" field and generate the depends
  nodes?
* Investigate dependencies among modules I cannot compile.
* Investigate how this affects realtime / sorcery backends.  Improved or
  made worse?  Same for other types of modules like codecs and formats.
* Make this thread safe.  Not entirely sure it was before.
* Review new symbol names.
* Remove redundent checks for dependent modules.
* Remove redundent module self references, for example in res_pjsip
  registration functions.
* Audit module load priorities.

Change-Id: I979ffb7caecc696ce0afa939193dfa76b19248e7
---
M apps/app_speech_utils.c
M apps/app_stasis.c
M channels/chan_motif.c
M channels/chan_pjsip.c
M channels/chan_rtp.c
M funcs/func_pjsip_aor.c
M funcs/func_pjsip_contact.c
M funcs/func_pjsip_endpoint.c
M include/asterisk/module.h
M main/loader.c
M pbx/pbx_ael.c
M res/ari/resource_asterisk.c
M res/res_agi.c
M res/res_ari.c
M res/res_ari_applications.c
M res/res_ari_asterisk.c
M res/res_ari_bridges.c
M res/res_ari_channels.c
M res/res_ari_device_states.c
M res/res_ari_endpoints.c
M res/res_ari_events.c
M res/res_ari_mailboxes.c
M res/res_ari_playbacks.c
M res/res_ari_recordings.c
M res/res_ari_sounds.c
M res/res_fax_spandsp.c
M res/res_hep_rtcp.c
M res/res_mwi_external_ami.c
M res/res_pjsip.c
M res/res_pjsip_acl.c
M res/res_pjsip_authenticator_digest.c
M res/res_pjsip_caller_id.c
M res/res_pjsip_config_wizard.c
M res/res_pjsip_dialog_info_body_generator.c
M res/res_pjsip_diversion.c
M res/res_pjsip_dlg_options.c
M res/res_pjsip_dtmf_info.c
M res/res_pjsip_empty_info.c
M res/res_pjsip_endpoint_identifier_anonymous.c
M res/res_pjsip_endpoint_identifier_ip.c
M res/res_pjsip_endpoint_identifier_user.c
M res/res_pjsip_exten_state.c
M res/res_pjsip_header_funcs.c
M res/res_pjsip_history.c
M res/res_pjsip_logger.c
M res/res_pjsip_messaging.c
M res/res_pjsip_mwi.c
M res/res_pjsip_mwi_body_generator.c
M res/res_pjsip_nat.c
M res/res_pjsip_notify.c
M res/res_pjsip_one_touch_record_info.c
M res/res_pjsip_outbound_authenticator_digest.c
M res/res_pjsip_outbound_publish.c
M res/res_pjsip_outbound_registration.c
M res/res_pjsip_path.c
M res/res_pjsip_phoneprov_provider.c
M res/res_pjsip_pidf_body_generator.c
M res/res_pjsip_pidf_digium_body_supplement.c
M res/res_pjsip_pidf_eyebeam_body_supplement.c
M res/res_pjsip_publish_asterisk.c
M res/res_pjsip_pubsub.c
M res/res_pjsip_refer.c
M res/res_pjsip_registrar.c
M res/res_pjsip_registrar_expire.c
M res/res_pjsip_rfc3326.c
M res/res_pjsip_sdp_rtp.c
M res/res_pjsip_send_to_voicemail.c
M res/res_pjsip_session.c
M res/res_pjsip_sips_contact.c
M res/res_pjsip_t38.c
M res/res_pjsip_transport_management.c
M res/res_pjsip_transport_websocket.c
M res/res_pjsip_xpidf_body_generator.c
M res/res_stasis_answer.c
M res/res_stasis_device_state.c
M res/res_stasis_mailbox.c
M res/res_stasis_playback.c
M res/res_stasis_recording.c
M res/res_stasis_snoop.c
M rest-api-templates/res_ari_resource.c.mustache
M tests/test_ari.c
M tests/test_ari_model.c
M tests/test_res_pjsip_scheduler.c
M tests/test_res_stasis.c
M tests/test_stasis_endpoints.c
85 files changed, 487 insertions(+), 241 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/87/6987/1

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

-- 
To view, visit https://gerrit.asterisk.org/6987
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I979ffb7caecc696ce0afa939193dfa76b19248e7
Gerrit-Change-Number: 6987
Gerrit-PatchSet: 1
Gerrit-Owner: Corey Farrell <git at cfware.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171103/f279fbdd/attachment-0001.html>


More information about the asterisk-code-review mailing list