[asterisk-commits] kpfleming: branch group/new_loader_completion r40721 - in /team/group/new_loa...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Sun Aug 20 18:54:56 MST 2006


Author: kpfleming
Date: Sun Aug 20 20:54:56 2006
New Revision: 40721

URL: http://svn.digium.com/view/asterisk?rev=40721&view=rev
Log:
yes, it appears that we have a functional (but probably buggy) new loader

Modified:
    team/group/new_loader_completion/Makefile
    team/group/new_loader_completion/Makefile.rules
    team/group/new_loader_completion/build_tools/embed_modules.xml
    team/group/new_loader_completion/include/asterisk/linkedlists.h
    team/group/new_loader_completion/include/asterisk/module.h
    team/group/new_loader_completion/main/   (props changed)
    team/group/new_loader_completion/main/cli.c
    team/group/new_loader_completion/main/loader.c

Modified: team/group/new_loader_completion/Makefile
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/Makefile?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/Makefile (original)
+++ team/group/new_loader_completion/Makefile Sun Aug 20 20:54:56 2006
@@ -251,20 +251,20 @@
 	menuselect/menuselect --check-deps $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts
 
 $(MOD_SUBDIRS_EMBED_LDSCRIPT):
-	@echo "EMBED_LDSCRIPTS+="`$(MAKE) -s -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
+	@echo "EMBED_LDSCRIPTS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
 
 $(MOD_SUBDIRS_EMBED_LDFLAGS):
-	@echo "EMBED_LDFLAGS+="`$(MAKE) -s -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
+	@echo "EMBED_LDFLAGS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
 
 $(MOD_SUBDIRS_EMBED_LIBS):
-	@echo "EMBED_LIBS+="`$(MAKE) -s -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
+	@echo "EMBED_LIBS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
 
 makeopts.embed_rules: menuselect.makeopts
 	@echo "Generating embedded module rules ..."
 	@rm -f $@
-	@$(MAKE) -s $(MOD_SUBDIRS_EMBED_LDSCRIPT)
-	@$(MAKE) -s $(MOD_SUBDIRS_EMBED_LDFLAGS)
-	@$(MAKE) -s $(MOD_SUBDIRS_EMBED_LIBS)
+	@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LDSCRIPT)
+	@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LDFLAGS)
+	@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LIBS)
 
 $(SUBDIRS): depend makeopts.embed_rules
 
@@ -275,10 +275,10 @@
 main: $(filter-out main,$(MOD_SUBDIRS))
 
 $(MOD_SUBDIRS):
-	@CFLAGS="$(MOD_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) -s -C $@ SUBDIR=$@ all
+	@CFLAGS="$(MOD_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) --no-print-directory -C $@ SUBDIR=$@ all
 
 $(OTHER_SUBDIRS):
-	@CFLAGS="$(OTHER_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) -s -C $@ SUBDIR=$@ all
+	@CFLAGS="$(OTHER_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) --no-print-directory -C $@ SUBDIR=$@ all
 
 defaults.h: makeopts
 	@build_tools/make_defaults_h > $@.tmp
@@ -302,10 +302,10 @@
 	@rm -f $@.tmp
 
 $(SUBDIRS_CLEAN_DEPEND):
-	@$(MAKE) -s -C $(@:-clean-depend=) clean-depend
+	@$(MAKE) --no-print-directory -C $(@:-clean-depend=) clean-depend
 
 $(SUBDIRS_CLEAN):
-	@$(MAKE) -s -C $(@:-clean=) clean
+	@$(MAKE) --no-print-directory -C $(@:-clean=) clean
 
 clean-depend: $(SUBDIRS_CLEAN_DEPEND)
 
@@ -587,13 +587,11 @@
 		echo "We could not install init scripts for your operating system."; \
 	fi
 
-dont-optimize: all
-
 $(MOD_SUBDIRS_DEPEND):
-	@CFLAGS="$(MOD_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) -s -C $(@:-depend=) depend
+	@CFLAGS="$(MOD_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) --no-print-directory -C $(@:-depend=) depend
 
 $(OTHER_SUBDIRS_DEPEND):
-	@CFLAGS="$(OTHER_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) -s -C $(@:-depend=) depend
+	@CFLAGS="$(OTHER_SUBDIR_CFLAGS)$(ASTCFLAGS)" $(MAKE) --no-print-directory -C $(@:-depend=) depend
 
 depend: include/asterisk/version.h include/asterisk/buildopts.h defaults.h $(SUBDIRS_DEPEND)
 
@@ -611,7 +609,7 @@
 	fi
 
 $(SUBDIRS_UNINSTALL):
-	@$(MAKE) -s -C $(@:-uninstall=) uninstall
+	@$(MAKE) --no-print-directory -C $(@:-uninstall=) uninstall
 
 _uninstall: $(SUBDIRS_UNINSTALL)
 	rm -f $(DESTDIR)$(MODULES_DIR)/*

Modified: team/group/new_loader_completion/Makefile.rules
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/Makefile.rules?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/Makefile.rules (original)
+++ team/group/new_loader_completion/Makefile.rules Sun Aug 20 20:54:56 2006
@@ -25,7 +25,7 @@
    CMD_PREFIX=
 endif
 
-ifeq ($(findstring dont-optimize,$(MAKECMDGOALS)),$(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)))
+ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
 # More GSM codec optimization
 # Uncomment to enable MMXTM optimizations for x86 architecture CPU's
 # which support MMX instructions.  This should be newer pentiums,

Modified: team/group/new_loader_completion/build_tools/embed_modules.xml
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/build_tools/embed_modules.xml?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/build_tools/embed_modules.xml (original)
+++ team/group/new_loader_completion/build_tools/embed_modules.xml Sun Aug 20 20:54:56 2006
@@ -3,7 +3,7 @@
 		</member>
 		<member name="cdr" displayname="Call Detail Recording" remove_on_change="cdr/*.o">
 		</member>
-		<member name="channels" displayname="Channels" remove_on_change="channels/*.o">
+		<member name="channels" displayname="Channels" remove_on_change="channels/*.o channels/misdn/*.o">
 		</member>
 		<member name="codecs" displayname="Coders/Decoders" remove_on_change="codecs/*.o">
 		</member>

Modified: team/group/new_loader_completion/include/asterisk/linkedlists.h
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/include/asterisk/linkedlists.h?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/linkedlists.h (original)
+++ team/group/new_loader_completion/include/asterisk/linkedlists.h Sun Aug 20 20:54:56 2006
@@ -220,7 +220,7 @@
 
 /*!
   \brief Returns the last entry contained in a list.
-  \param head This is a pointer to the list tail structure
+  \param head This is a pointer to the list head structure
  */
 #define	AST_LIST_LAST(head)	((head)->last)
 

Modified: team/group/new_loader_completion/include/asterisk/module.h
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/include/asterisk/module.h?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/module.h (original)
+++ team/group/new_loader_completion/include/asterisk/module.h Sun Aug 20 20:54:56 2006
@@ -60,6 +60,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 */
 	AST_MODULE_LOAD_FAILURE = -1,	/*!< Module could not be loaded properly */
 };
 
@@ -194,7 +195,7 @@
 	 */
 
 	const char *key;
-	const struct ast_flags flags;
+	unsigned int flags;
 };
 
 void ast_module_register(const struct ast_module_info *);
@@ -213,7 +214,7 @@
 
 #if defined(__cplusplus) || defined(c_plusplus)
 #define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func)	\
-	const static struct ast_module_info __mod_info = {	\
+	static struct ast_module_info __mod_info = {	\
 		NULL,					\
 		load_func,				\
 		unload_func,				\
@@ -222,7 +223,7 @@
 		desc,					\
 		keystr,					\
 		flags_to_set				\
-	};							\
+	};						\
 	static void  __attribute__ ((constructor)) __reg_module(void) \
 	{ \
 		ast_module_register(&__mod_info); \
@@ -246,9 +247,9 @@
 const static __attribute__((unused)) struct ast_module_info *ast_module_info;
 
 #define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)	\
-	const static struct ast_module_info __mod_info = {	\
+	static struct ast_module_info __mod_info = {		\
 		.name = AST_MODULE,				\
-		.flags = { flags_to_set },			\
+		.flags = flags_to_set,				\
 		.description = desc,				\
 		.key = keystr,					\
 		fields						\

Propchange: team/group/new_loader_completion/main/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Aug 20 20:54:56 2006
@@ -1,1 +1,2 @@
 asterisk
+.depend

Modified: team/group/new_loader_completion/main/cli.c
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/main/cli.c?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/main/cli.c (original)
+++ team/group/new_loader_completion/main/cli.c Sun Aug 20 20:54:56 2006
@@ -804,6 +804,11 @@
 	return ast_complete_channels(line, word, pos, state, 3);
 }
 
+static char *complete_mod_2_nr(const char *line, const char *word, int pos, int state)
+{
+	return ast_module_helper(line, word, pos, state, 1, 0);
+}
+
 static char *complete_mod_2(const char *line, const char *word, int pos, int state)
 {
 	return ast_module_helper(line, word, pos, state, 1, 1);
@@ -907,7 +912,7 @@
 	{ { "debug", "level", NULL }, handle_debuglevel, "Set global debug level", debuglevel_help },
 	{ { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", group_show_channels_help},
 	{ { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help, complete_help },
-	{ { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn },
+	{ { "load", NULL }, handle_load, "Load a module by name", load_help, complete_fn },
 	{ { "logger", "mute", NULL }, handle_logger_mute, "Toggle logging output to a console", logger_mute_help },
 	{ { "no", "debug", "channel", NULL }, handle_nodebugchan, "Disable debugging on a channel", nodebugchan_help, complete_ch_4 },
 	{ { "reload", NULL }, handle_reload, "Reload configuration", reload_help, complete_mod_2 },
@@ -919,7 +924,7 @@
 	{ { "show", "modules", "like", NULL }, handle_modlist, "List modules and info", modlist_help, complete_mod_4 },
  	{ { "show", "uptime", NULL }, handle_showuptime, "Show uptime information", uptime_help },
 	{ { "soft", "hangup", NULL }, handle_softhangup, "Request a hangup on a given channel", softhangup_help, complete_ch_3 },
-	{ { "unload", NULL }, handle_unload, "Unload a dynamic module by name", unload_help, complete_fn },
+	{ { "unload", NULL }, handle_unload, "Unload a module by name", unload_help, complete_mod_2_nr },
 	{ { NULL }, NULL, NULL, NULL }
 };
 

Modified: team/group/new_loader_completion/main/loader.c
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/main/loader.c?rev=40721&r1=40720&r2=40721&view=diff
==============================================================================
--- team/group/new_loader_completion/main/loader.c (original)
+++ team/group/new_loader_completion/main/loader.c Sun Aug 20 20:54:56 2006
@@ -27,7 +27,6 @@
  * - See ModMngMnt
  */
 
-#define MOD_LOADER	/* prevent some module-specific stuff from being compiled */
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -71,9 +70,7 @@
 	AST_LIST_ENTRY(ast_module_user) entry;
 };
 
-AST_LIST_HEAD(ast_module_user_list, ast_module_user);
-
-static unsigned int modlistver = 0; /* increase whenever the list changes, to protect reload */
+AST_LIST_HEAD(module_user_list, ast_module_user);
 
 static unsigned char expected_key[] =
 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
@@ -84,14 +81,15 @@
 				   */
 
 enum flags {
-	FLAG_EMBEDDED = (1 << 0),		/* module is embedded */
+	FLAG_RUNNING = (1 << 1),		/* module successfully initialized */
+	FLAG_DECLINED = (1 << 2),		/* module declined to initialize */
 };
 
 struct ast_module {
 	const struct ast_module_info *info;
 	void *lib;					/* the shared lib, or NULL if embedded */
 	int usecount;					/* the number of 'users' currently in this module */
-	struct ast_module_user_list users;		/* the list of users in the module */
+	struct module_user_list users;			/* the list of users in the module */
 	unsigned int flags;				/* flags for this module */
 	AST_LIST_ENTRY(ast_module) entry;
 	char resource[0];
@@ -104,34 +102,32 @@
 	AST_LIST_ENTRY(loadupdate) entry;
 };
 
+static AST_LIST_HEAD_STATIC(updaters, loadupdate);
+
+AST_MUTEX_DEFINE_STATIC(reloadlock);
+
 /* when dynamic modules are being loaded, ast_module_register() will
    need to know what filename the module was loaded from while it
    is being registered
 */
-const char *module_being_loaded = NULL;
-
-static AST_LIST_HEAD_STATIC(updaters, loadupdate);
-
-AST_MUTEX_DEFINE_STATIC(reloadlock);
+struct ast_module *resource_being_loaded;
+
+/* XXX: should we check for duplicate resource names here? */
 
 void ast_module_register(const struct ast_module_info *info)
 {
 	struct ast_module *mod;
-	size_t alloc_len;
-	const char *resource;
-
-	if (embedding)
-		resource = info->name;
-	else
-		resource = module_being_loaded;
-
-	if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(resource) + 1)))
-		return;
+
+	if (embedding) {
+		if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
+			return;
+		strcpy(mod->resource, info->name);
+	} else {
+		mod = resource_being_loaded;
+	}
 
 	mod->info = info;
-	strcpy(mod->resource, resource);
 	AST_LIST_HEAD_INIT(&mod->users);
-	ast_set2_flag(mod, embedding, FLAG_EMBEDDED);
 
 	/* during startup, before the loader has been initialized,
 	   there are no threads, so there is no need to take the lock
@@ -141,20 +137,29 @@
 	*/
 	if (!embedding)
 		AST_LIST_LOCK(&module_list);
-	/* it is paramount that the new entry be placed at the head of
+
+	/* it is paramount that the new entry be placed at the tail of
 	   the list, otherwise the code that uses dlopen() to load
 	   dynamic modules won't be able to find out if the module it
 	   just opened was registered or failed to load
 	*/
-	AST_LIST_INSERT_HEAD(&module_list, mod, entry);
+	AST_LIST_INSERT_TAIL(&module_list, mod, entry);
+
 	if (!embedding)
 		AST_LIST_UNLOCK(&module_list);
+
+	/* give the module a copy of its own handle, for later use in registrations and the like */
+	*((struct ast_module **) &(info->self)) = mod;
 }
 
 void ast_module_unregister(const struct ast_module_info *info)
 {
 	struct ast_module *mod = NULL;
 
+	/* it is assumed that the users list in the module structure
+	   will already be empty, or we cannot have gotten to this
+	   point
+	*/
 	AST_LIST_LOCK(&module_list);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
 		if (mod->info == info) {
@@ -180,9 +185,11 @@
 		return NULL;
 
 	u->chan = chan;
+
 	AST_LIST_LOCK(&mod->users);
 	AST_LIST_INSERT_HEAD(&mod->users, u, entry);
 	AST_LIST_UNLOCK(&mod->users);
+
 	ast_atomic_fetchadd_int(&mod->usecount, +1);
 
 	ast_update_use_count();
@@ -221,10 +228,10 @@
  * which are listed here together with the corresponding handlers.
  * This table is also used by the command completion code.
  */
-static struct reload_classes_t {
+static struct reload_classes {
 	const char *name;
 	int (*reload_fn)(void);
-} reload_classes[] = {	/* list in alpha order, longest match first */
+} reload_classes[] = {	/* list in alpha order, longest match first for cli completion */
 	{ "cdr",	ast_cdr_engine_reload },
 	{ "dnsmgr",	dnsmgr_reload },
 	{ "extconfig",	read_config_maps },
@@ -232,7 +239,7 @@
 	{ "manager",	reload_manager },
 	{ "rtp",	ast_rtp_reload },
 	{ "http",	ast_http_reload },
-	{ NULL, NULL }
+	{ NULL, 	NULL }
 };
 
 static int printdigest(const unsigned char *d)
@@ -242,6 +249,7 @@
 
 	for (pos = 0, x = 0; x < 16; x++)
 		pos += sprintf(buf + pos, " %02x", *d++);
+
 	ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
 
 	return 0;
@@ -252,7 +260,7 @@
 	int x;
 
 	for (x = 0; x < 16; x++) {
-		if (key1[x] != key2[x])	/* mismatch - fail now. */
+		if (key1[x] != key2[x])
 			return 0;
 	}
 
@@ -267,76 +275,176 @@
 	MD5Init(&c);
 	MD5Update(&c, key, strlen((char *)key));
 	MD5Final(digest, &c);
+
 	if (key_matches(expected_key, digest))
 		return 0;
+
 	printdigest(digest);
 
 	return -1;
 }
 
-static void free_module(struct ast_module *mod)
-{
-	struct ast_module_user *u;
-
-	while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry)))
-		free(u);
-	
-	AST_LIST_HEAD_DESTROY(&mod->users);
-	free(mod);
-}
+static int resource_name_match(const char *name1_in, const char *name2_in)
+{
+	char *name1 = (char *) name1_in;
+	char *name2 = (char *) name2_in;
+
+	/* trim off any .so extensions */
+	if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
+		name1 = ast_strdupa(name1);
+		name1[strlen(name1) - 3] = '\0';
+	}
+	if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
+		name2 = ast_strdupa(name2);
+		name2[strlen(name2) - 3] = '\0';
+	}
+
+	return strcasecmp(name1, name2);
+}
+
+static struct ast_module *find_resource(const char *resource, int do_lock)
+{
+	struct ast_module *cur;
+
+	if (do_lock)
+		AST_LIST_LOCK(&module_list);
+
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
+		if (!resource_name_match(resource, cur->resource))
+			break;
+	}
+
+	if (do_lock)
+		AST_LIST_UNLOCK(&module_list);
+
+	return cur;
+}
+
+#if LOADABLE_MODULES
+static void unload_dynamic_module(struct ast_module *mod)
+{
+	if (mod->lib)
+		dlclose(mod->lib);
+	/* WARNING: the structure pointed to by mod is now gone! */
+}
+
+static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
+{
+	char fn[256];
+	void *lib;
+	struct ast_module *mod;
+	unsigned int load_global = global_symbols_only;
+	char *resource = (char *) resource_in;
+
+	if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
+		resource = alloca(strlen(resource_in) + 3);
+	        strcpy(resource, resource_in);
+		strcat(resource, ".so");
+	}
+
+	snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
+
+tryload:
+	if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
+		return NULL;
+
+	strcpy(resource_being_loaded->resource, resource);
+
+	if (load_global)
+		lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL);
+	else
+		lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
+
+	if (!lib) {
+		ast_log(LOG_WARNING, "%s\n", dlerror());
+		free(resource_being_loaded);
+		return NULL;
+	}
+
+	/* the dlopen() succeeded, let's find out if the module
+	   registered itself */
+	/* note that this will only work properly as long as
+	   ast_module_register() (which is called by the module's
+	   constructor) places the new module at the tail of the
+	   module_list
+	*/
+	if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
+		/* no, it did not, so close it and return */
+		dlclose(lib);
+		free(resource_being_loaded);
+		return NULL;
+	}
+
+	resource_being_loaded = NULL;
+	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 (load_global && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
+		unload_dynamic_module(mod);
+		return NULL;
+	}
+
+	/* if we were not asked to load _only_ modules with global symbols, but
+	   this module wants to provide some, then we have to close and re-open
+	   in global mode
+	*/
+	if (!load_global && ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
+		unload_dynamic_module(mod);
+		load_global = 1;
+		goto tryload;
+	}
+
+	return mod;
+}
+#endif
 
 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
 {
-	struct ast_module *cur;
+	struct ast_module *mod;
 	int res = -1;
 	int error = 0;
 
 	AST_LIST_LOCK(&module_list);
 
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, cur, entry) {
-		if (strcasecmp(cur->resource, resource_name))	/* not us */
-			continue;
-
-		if (cur->usecount > 0) {
-			if (force) 
-				ast_log(LOG_WARNING, "Warning:  Forcing removal of module %s with use count %d\n",
-					resource_name, cur->usecount);
-			else {
-				ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
-					cur->usecount);
-				error = 1;
-				break;
-			}
-		}
-
-		__ast_module_user_hangup_all(cur);
-		res = cur->info->unload();
+	mod = find_resource(resource_name, 0);
+
+	if (!ast_test_flag(mod, FLAG_RUNNING | FLAG_DECLINED))
+		error = 1;
+
+	if (!error && (mod->usecount > 0)) {
+		if (force) 
+			ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
+				resource_name, mod->usecount);
+		else {
+			ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
+				mod->usecount);
+			error = 1;
+		}
+	}
+
+	if (!error) {
+		__ast_module_user_hangup_all(mod);
+		res = mod->info->unload();
 
 		if (res) {
 			ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
-			if (force <= AST_FORCE_FIRM) {
+			if (force <= AST_FORCE_FIRM)
 				error = 1;
-				break;
-			} else
+			else
 				ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
 		}
-
-		AST_LIST_REMOVE_CURRENT(&module_list, entry);
+	}
+
+	if (!error)
+		ast_clear_flag(mod, FLAG_RUNNING | FLAG_DECLINED);
+
+	AST_LIST_UNLOCK(&module_list);
 
 #if LOADABLE_MODULES
-		dlclose(cur->lib);
+	if (!error)
+		unload_dynamic_module(mod);
 #endif
-
-		free_module(cur);
-
-		break;
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	if (!error)
-		modlistver++;
-
-	AST_LIST_UNLOCK(&module_list);
 
 	if (!error)
 		ast_update_use_count();
@@ -378,7 +486,7 @@
 {
 	struct ast_module *cur;
 	int res = 0; /* return value. 0 = not found, others, see below */
-	int i, oldversion;
+	int i;
 
 	if (ast_mutex_trylock(&reloadlock)) {
 		ast_verbose("The previous reload command didn't finish yet\n");
@@ -398,11 +506,13 @@
 		return res;
 
 	AST_LIST_LOCK(&module_list);
-	oldversion = modlistver;
 	AST_LIST_TRAVERSE(&module_list, cur, entry) {
 		const struct ast_module_info *info = cur->info;
 
-		if (name && strcasecmp(name, cur->resource))	/* not ours */
+		if (name && resource_name_match(name, cur->resource))
+			continue;
+
+		if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED))
 			continue;
 
 		if (!info->reload) {	/* cannot be reloaded */
@@ -423,161 +533,141 @@
 	return res;
 }
 
-static int resource_exists(const char *resource, int do_lock)
-{
-	struct ast_module *cur;
-
-	if (do_lock)
-		AST_LIST_LOCK(&module_list);
-
-	AST_LIST_TRAVERSE(&module_list, cur, entry) {
-		if (!strcasecmp(resource, cur->resource))
-			break;
-	}
-
-	if (do_lock)
-		AST_LIST_UNLOCK(&module_list);
-
-	return cur ? -1 : 0;
-}
-
-/* assumes module_list will be locked */
-static struct ast_module * __load_resource(const char *resource_name)
-{
-	static char fn[256];
-	int errors=0;
-	struct ast_module *cur;
-	const struct ast_module_info *m;
-	unsigned char *key;
-	char tmp[80];
-
-	if (resource_exists(resource_name, 0)) {
-		ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
+static unsigned int inspect_module(const struct ast_module *mod)
+{
+	if (!mod->info->description) {
+		ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
+		return 1;
+	}
+
+	if (!mod->info->key) {
+		ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
+		return 1;
+	}
+
+	if (verify_key((unsigned char *) mod->info->key)) {
+		ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
+		return 1;
+	}
+
+	return 0;
+}
+
+static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
+{
+	struct ast_module *mod;
+	enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
+	char tmp[256];
+
+	if ((mod = find_resource(resource_name, 0))) {
+		if (ast_test_flag(mod, FLAG_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;
+#if LOADABLE_MODULES
+	} else {
+		if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
+			/* don't generate a warning message during load_modules() */
+			if (!global_symbols_only) {
+				ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
+				return AST_MODULE_LOAD_DECLINE;
+			} else {
+				return AST_MODULE_LOAD_SKIP;
+			}
+		}
+#endif
+	}
+
+	if (inspect_module(mod)) {
+		ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
+#if LOADABLE_MODULES
+		unload_dynamic_module(mod);
+#endif
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	ast_clear_flag(mod, FLAG_DECLINED);
+
+	if (mod->info->load)
+		res = mod->info->load();
+
+	switch (res) {
+	case AST_MODULE_LOAD_SUCCESS:
+		if (!ast_fully_booted) {
+			if (option_verbose) 
+				ast_verbose( " => (%s)\n", term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
+			if (ast_opt_console && !option_verbose)
+				ast_verbose( ".");
+		} else {
+			if (option_verbose)
+				ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
+		}
+
+		ast_set_flag(mod, FLAG_RUNNING);
+		
+		ast_update_use_count();
+		break;
+	case AST_MODULE_LOAD_DECLINE:
+		ast_set_flag(mod, FLAG_DECLINED);
+		break;
+	case AST_MODULE_LOAD_FAILURE:
+		break;
+	case AST_MODULE_LOAD_SKIP:
+		/* modules should never return this value */
+		break;
+	}
+
+	return res;
+}
+
+int ast_load_resource(const char *resource_name)
+{
+       AST_LIST_LOCK(&module_list);
+       load_resource(resource_name, 0);
+       AST_LIST_UNLOCK(&module_list);
+
+       return 0;
+}
+
+struct load_order_entry {
+	char *resource;
+	unsigned int embedded;
+	AST_LIST_ENTRY(load_order_entry) entry;
+};
+
+AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
+
+static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
+{
+	struct load_order_entry *order;
+
+	AST_LIST_TRAVERSE(load_order, order, entry) {
+		if (!resource_name_match(order->resource, resource))
+			return NULL;
+	}
+
+	if (!(order = ast_calloc(1, sizeof(*order))))
 		return NULL;
-	}
-	if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(resource_name) + 1))) {
-		return NULL;
-	}
-
-	strcpy(cur->resource, resource_name);
-
-	if (resource_name[0] == '/')
-		ast_copy_string(fn, resource_name, sizeof(fn));
-	else
-		snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource_name);
-
-#if LOADABLE_MODULES
-	cur->lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
-#endif
-	
-	if (!cur->lib) {
-#if LOADABLE_MODULES
-		ast_log(LOG_WARNING, "%s\n", dlerror());
-#endif
-		free(cur);
-		return NULL;
-	}
-
-	cur->info = m;
-
-	if (!m->load)
-		errors++;
-	if (!m->unload)
-		errors++;
-	if (!m->description)
-		errors++;
-	if (!m->key)
-		errors++;
-	if (!(key = (unsigned char *) m->key)) {
-		ast_log(LOG_WARNING, "Module %s does not contain a license key.\n", fn);
-		key = NULL;
-		errors++;
-	}
-	if (key && verify_key(key)) {
-		ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn);
-		errors++;
-	}
-	if (errors) {
-		ast_log(LOG_WARNING, "%d error%s loading module %s, aborted\n", errors, (errors != 1) ? "s" : "", fn);
-#if LOADABLE_MODULES
-		dlclose(cur->lib);
-#endif
-		free(cur);
-		return NULL;
-	}
-
-	/* init mutex and user list */
-	AST_LIST_HEAD_SET(&cur->users, NULL);
-
-	if (!ast_fully_booted) {
-		if (option_verbose) 
-			ast_verbose( " => (%s)\n", term_color(tmp, m->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
-		if (ast_opt_console && !option_verbose)
-			ast_verbose( ".");
-	} else {
-		if (option_verbose)
-			ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description);
-	}
-
-	/* add module to end of module_list chain
-  	   so reload commands will be issued in same order modules were loaded */
-	AST_LIST_INSERT_TAIL(&module_list, cur, entry);
-	
-	modlistver++;
-
-	/* give the module a copy of its own handle, for later use in registrations and the like */
-	*((struct ast_module **) &(m->self)) = cur;
-
-	ast_update_use_count();
-
-	return cur;
-}
-
-/*
- * load a single module (API call).
- * (recursive calls from load_module() succeed.
- */
-int ast_load_resource(const char *resource_name)
-{
-       struct ast_module *m;
-       int ret;
-
-       AST_LIST_LOCK(&module_list);
-       m = __load_resource(resource_name);
-       AST_LIST_UNLOCK(&module_list);
-
-       return ret;
-}
-
-/*! \brief if enabled, log and output on console the module's name, and try load it */
-static int print_and_load(const char *s, struct ast_config *cfg)
-{
-	char tmp[80];
-	int ret;
-
-	if (option_verbose) {
-		ast_verbose(VERBOSE_PREFIX_1 "[%s]",
-			    term_color(tmp, s, COLOR_BRWHITE, 0, sizeof(tmp)));
-		fflush(stdout);
-	} else if (option_debug) {
-		ast_log(LOG_DEBUG, "Loading module %s\n", s);
-	}
-
-	AST_LIST_LOCK(&module_list);
-	ret = __load_resource(s) ? 0 : -1;
-	AST_LIST_UNLOCK(&module_list);
-
-	if (ret)
-		ast_log(LOG_WARNING, "Loading module %s failed!\n", s);
-
-	return ret;
+
+	order->resource = ast_strdup(resource);
+	AST_LIST_INSERT_TAIL(load_order, order, entry);
+
+	return order;
 }
 
 int load_modules(void)
 {
 	struct ast_config *cfg;
-	struct dirent *d;
-	DIR *mods;
+	struct dirent *dirent;
+	DIR *dir;
+	struct ast_module *mod;
+	struct load_order_entry *order;
+	struct ast_variable *v;
+	unsigned int load_count;
+	struct load_order load_order;
+	int res = 0;
 
 	/* all embedded modules have registered themselves by now */
 	embedding = 0;
@@ -585,77 +675,133 @@
 	if (option_verbose)
 		ast_verbose("Asterisk Dynamic Loader Starting:\n");
 
-	cfg = ast_config_load(AST_MODULE_CONFIG);
-
-	if (cfg) {
-		struct ast_variable *v;
-
-		/* Load explicitly defined modules */
-		for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
-
-			if (strcasecmp(v->name, "load")) /* not what we are looking for */
-				continue;
-
-			if (print_and_load(v->value, cfg)) {
-				ast_config_destroy(cfg);
-				return -1;
+	AST_LIST_TRAVERSE(&module_list, mod, entry) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
+	}
+
+	if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
+		ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
+		return 0;
+	}
+
+	AST_LIST_HEAD_INIT_NOLOCK(&load_order);
+
+	/* first, find all the modules we have been explicitly requested to load */
+	for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
+		if (!strcasecmp(v->name, "load"))
+			add_to_load_order(v->value, &load_order);
+	}
+
+	/* check if 'autoload' is on */
+	if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
+		/* if so, first add all the embedded modules to the load order */
+		AST_LIST_TRAVERSE(&module_list, mod, entry) {
+			order = add_to_load_order(mod->resource, &load_order);
+
+			if (order)
+				order->embedded = 1;
+		}
+
+		/* if we are allowed to load dynamic modules, scan the directory for
+		   for all available modules and add them as well */
+#if LOADABLE_MODULES
+		if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
+			while ((dirent = readdir(dir))) {
+				int ld = strlen(dirent->d_name);
+				
+				/* Must end in .so to load it.  */
+
+				if (ld < 4)
+					continue;
+
+				if (strcasecmp(dirent->d_name + ld - 3, ".so"))
+				    continue;
+
+				add_to_load_order(dirent->d_name, &load_order);
+
 			}
-		}
-	}
-
-	if (cfg && !ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
-		/* no autoload */
-		goto done;
-	}
-
-	if (!(mods = opendir(ast_config_AST_MODULE_DIR))) {
-		if (!ast_opt_quiet)
-			ast_log(LOG_WARNING, "Unable to open modules directory %s.\n",
-				ast_config_AST_MODULE_DIR);
-		goto done;
-	}
-
-	while ((d = readdir(mods))) {
-		int ld = strlen(d->d_name);
-
-		/* Must end in .so to load it.  */
-		if (ld > 3 &&
-		    !strcasecmp(d->d_name + ld - 3, ".so") &&
-		    !resource_exists(d->d_name, 1)) {
-			/* It's a shared library, check if we are allowed to load it
-			 * (very inefficient, but oh well).
-			 */
-			if (cfg) {
-				struct ast_variable *v;
-
-				for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
-					if (!strcasecmp(v->name, "noload") &&
-					    !strcasecmp(v->value, d->d_name)) 
-						break;
-				}
-				if (v) {
-					if (option_verbose) {
-						ast_verbose(VERBOSE_PREFIX_1 "[skipping %s]\n",
-							    d->d_name);
-						fflush(stdout);
-					}
-					continue;
-				}
-				
+
+			closedir(dir);
+		} else {
+			if (!ast_opt_quiet)
+				ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
+					ast_config_AST_MODULE_DIR);
+		}
+#endif
+	}
+
+	/* now scan the config for any modules we are prohibited from loading and
+	   remove them from the load order */
+	for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
+		if (strcasecmp(v->name, "noload"))
+			continue;
+
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
+			if (!resource_name_match(order->resource, v->value)) {
+				AST_LIST_REMOVE_CURRENT(&load_order, entry);
+				free(order->resource);
+				free(order);
 			}
-			if (print_and_load(d->d_name, cfg)) {
-				closedir(mods);
-				ast_config_destroy(cfg);
-				return -1;
-			}
-		}
-	}
-	closedir(mods);
+		}
+		AST_LIST_TRAVERSE_SAFE_END;
+	}
+
+	/* we are done with the config now, all the information we need is in the
+	   load_order list */
+	ast_config_destroy(cfg);
+
+	load_count = 0;
+	AST_LIST_TRAVERSE(&load_order, order, entry)
+		load_count++;
+
+	ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
+
+	/* first, load only modules that provide global symbols */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
+		switch (load_resource(order->resource, 1)) {
+		case AST_MODULE_LOAD_SUCCESS:
+		case AST_MODULE_LOAD_DECLINE:
+			AST_LIST_REMOVE_CURRENT(&load_order, entry);
+			free(order->resource);
+			free(order);
+			break;
+		case AST_MODULE_LOAD_FAILURE:
+			res = -1;
+			goto done;
+		case AST_MODULE_LOAD_SKIP:
+			/* try again later */
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	/* now load everything else */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
+		switch (load_resource(order->resource, 0)) {
+		case AST_MODULE_LOAD_SUCCESS:
+		case AST_MODULE_LOAD_DECLINE:
+			AST_LIST_REMOVE_CURRENT(&load_order, entry);
+			free(order->resource);
+			free(order);
+			break;
+		case AST_MODULE_LOAD_FAILURE:
+			res = -1;
+			goto done;
+		case AST_MODULE_LOAD_SKIP:
+			/* should not happen */
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
 
 done:
-	ast_config_destroy(cfg);
-
-	return 0;
+	while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
+		free(order->resource);
+		free(order);
+	}
+
+	return res;
 }
 
 void ast_update_use_count(void)



More information about the asterisk-commits mailing list