[asterisk-commits] branch group/new_loader_completion r21036 - in /team/group/new_loader_complet...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Apr 17 17:12:08 MST 2006


Author: kpfleming
Date: Mon Apr 17 19:12:06 2006
New Revision: 21036

URL: http://svn.digium.com/view/asterisk?rev=21036&view=rev
Log:
create branch for loader completion work

Added:
    team/group/new_loader_completion/
      - copied from r21034, trunk/
Modified:
    team/group/new_loader_completion/cli.c
    team/group/new_loader_completion/file.c
    team/group/new_loader_completion/include/asterisk.h
    team/group/new_loader_completion/include/asterisk/file.h
    team/group/new_loader_completion/include/asterisk/linkedlists.h
    team/group/new_loader_completion/include/asterisk/module.h
    team/group/new_loader_completion/include/asterisk/translate.h
    team/group/new_loader_completion/loader.c
    team/group/new_loader_completion/res/res_adsi.c
    team/group/new_loader_completion/res/res_agi.c
    team/group/new_loader_completion/res/res_clioriginate.c
    team/group/new_loader_completion/res/res_config_odbc.c
    team/group/new_loader_completion/res/res_config_pgsql.c
    team/group/new_loader_completion/res/res_convert.c
    team/group/new_loader_completion/res/res_crypto.c
    team/group/new_loader_completion/translate.c

Modified: team/group/new_loader_completion/cli.c
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/cli.c?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/cli.c (original)
+++ team/group/new_loader_completion/cli.c Mon Apr 17 19:12:06 2006
@@ -40,8 +40,11 @@
 #include "asterisk/options.h"
 #include "asterisk/cli.h"
 #include "asterisk/linkedlists.h"
-#define	MOD_LOADER
+
+#define	NOT_A_MODULE
 #include "asterisk/module.h"
+#undef NOT_A_MODULE
+
 #include "asterisk/pbx.h"
 #include "asterisk/channel.h"
 #include "asterisk/manager.h"

Modified: team/group/new_loader_completion/file.c
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/file.c?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/file.c (original)
+++ team/group/new_loader_completion/file.c Mon Apr 17 19:12:06 2006
@@ -51,8 +51,10 @@
 #include "asterisk/app.h"
 #include "asterisk/pbx.h"
 #include "asterisk/linkedlists.h"
-#define	MOD_LOADER
-#include "asterisk/module.h"	/* ast_update_use_count() */
+
+#define NOT_A_MODULE
+#include "asterisk/module.h"
+#undef NOT_A_MODULE
 
 /*
  * The following variable controls the layout of localized sound files.
@@ -316,9 +318,8 @@
                 ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
 	else {
 		/* preliminary checks succeed. update usecount */
-		ast_atomic_fetchadd_int(&f->module->usecnt, +1);
+		ast_module_ref(f->module);
 		ret = 0;
-		ast_update_use_count();
 	}
         return ret;
 }
@@ -741,8 +742,7 @@
 	fclose(f->f);
 	if (f->vfs)
 		ast_closestream(f->vfs);
-	ast_atomic_fetchadd_int(&f->fmt->module->usecnt, -1);
-	ast_update_use_count();
+	ast_module_unref(f->fmt->module);
 	free(f);
 	return 0;
 }

Modified: team/group/new_loader_completion/include/asterisk.h
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/include/asterisk.h?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk.h (original)
+++ team/group/new_loader_completion/include/asterisk.h Mon Apr 17 19:12:06 2006
@@ -3,7 +3,7 @@
  *
  * General Definitions for Asterisk top level program
  * 
- * Copyright (C) 1999-2005, Mark Spencer
+ * Copyright (C) 1999-2006, Mark Spencer
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -50,8 +50,8 @@
 
 /* Provided by asterisk.c */
 int ast_set_priority(int);
-/* Provided by module.c */
-int load_modules(const int preload_only);
+/* Provided by loader.c */
+int load_modules(void);
 /* Provided by pbx.c */
 int load_pbx(void);
 /* Provided by logger.c */
@@ -74,6 +74,9 @@
 void dnsmgr_start_refresh(void);
 int dnsmgr_reload(void);
 
+/* Many headers need 'ast_channel' to be defined */
+struct ast_channel;
+
 /*!
  * \brief Reload asterisk modules.
  * \param name the name of the module to reload

Modified: team/group/new_loader_completion/include/asterisk/file.h
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/include/asterisk/file.h?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/file.h (original)
+++ team/group/new_loader_completion/include/asterisk/file.h Mon Apr 17 19:12:06 2006
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2006, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -106,7 +106,7 @@
 	int buf_size;			/*! size of frame buffer, if any, aligned to 8 bytes. */
 	int desc_size;			/*! size of private descriptor, if any */
 
-	struct module_symbols *module;
+	struct ast_module *module;
 };
 
 /*

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=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/linkedlists.h (original)
+++ team/group/new_loader_completion/include/asterisk/linkedlists.h Mon Apr 17 19:12:06 2006
@@ -28,7 +28,7 @@
 */
 
 /*!
-  \brief Attempts to lock a list.
+  \brief Locks a list.
   \param head This is a pointer to the list head structure
 
   This macro attempts to place an exclusive lock in the
@@ -37,6 +37,17 @@
 */
 #define AST_LIST_LOCK(head)						\
 	ast_mutex_lock(&(head)->lock) 
+	
+/*!
+  \brief Locks a list, without blocking if the list is locked.
+  \param head This is a pointer to the list head structure
+
+  This macro attempts to place an exclusive lock in the
+  list head structure pointed to by head.
+  Returns non-zero on success, 0 on failure
+*/
+#define AST_LIST_TRYLOCK(head)						\
+	ast_mutex_trylock(&(head)->lock) 
 	
 /*!
   \brief Attempts to unlock a list.

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=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/module.h (original)
+++ team/group/new_loader_completion/include/asterisk/module.h Mon Apr 17 19:12:06 2006
@@ -4,6 +4,8 @@
  * Copyright (C) 1999 - 2006, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
+ * Kevin P. Fleming <kpfleming at digium.com>
+ * Luigi Rizzo <rizzo at icir.org>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -26,18 +28,11 @@
 #ifndef _ASTERISK_MODULE_H
 #define _ASTERISK_MODULE_H
 
-#ifdef STATIC_MODULE
-#error STATIC_MODULE should not be defined
-#endif
-#define STATIC_MODULE --- this is an error
-#define	LOCAL_USER_DECL	/* --- this is an error --- */
-
 #include "asterisk/utils.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
-
 
 /*! \brief The text the key() function should return. */
 #define ASTERISK_GPL_KEY \
@@ -55,7 +50,7 @@
 
 #define AST_MODULE_CONFIG "modules.conf" /*!< \brief Module configuration file */
 
-enum unload_mode {
+enum ast_module_unload_mode {
 	AST_FORCE_SOFT = 0, /*! Softly unload a module, only if not in use */
 	AST_FORCE_FIRM = 1, /*! Firmly unload a module, even if in use */
 	AST_FORCE_HARD = 2, /*! as FIRM, plus dlclose() on the module. Not recommended
@@ -87,7 +82,7 @@
  *
  * \return Zero on success, -1 on error.
  */
-int ast_unload_resource(const char *resource_name, enum unload_mode);
+int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode);
 
 /*! 
  * \brief Notify when usecount has been changed.
@@ -151,24 +146,16 @@
  */
 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload);
 
-/* Local user routines keep track of which channels are using a given module
+/* Opaque type for module handles generated by the loader */
+
+struct ast_module;
+
+/* User count routines keep track of which channels are using a given module
    resource.  They can help make removing modules safer, particularly if
    they're in use at the time they have been requested to be removed */
 
-struct localuser {
-	struct localuser *next;
-	struct ast_channel *chan;
-};
-
-struct module_symbols;	/* forward declaration */
-struct localuser *ast_localuser_add(struct module_symbols *, struct ast_channel *);
-void ast_localuser_remove(struct module_symbols *, struct localuser *);
-void ast_hangup_localusers(struct module_symbols *);
-
-/* XXX deprecated macros, only for backward compatibility */
-#define	LOCAL_USER_ADD(u) do { u = ast_localuser_add(__mod_desc, chan); } while (0)
-#define	LOCAL_USER_REMOVE(u) ast_localuser_remove(__mod_desc, u)
-#define	STANDARD_HANGUP_LOCALUSERS ast_hangup_localusers(__mod_desc)
+struct ast_module_user;
+struct ast_module_user_list;
 
 /*! \page ModMngmnt The Asterisk Module management interface
  * \par The following is part of the new module management code.
@@ -266,11 +253,11 @@
  *       bugs due to unresolved symbols or name conflicts.
  */
 
-struct symbol_entry {
+struct ast_module_symbol {
 	const char *name;
 	void *value;
 	int size;
-	struct module *src;	/* module sourcing it, filled by loader */
+	struct ast_module *src;	/* module sourcing it, filled by loader */
 };
 
 /*
@@ -286,75 +273,74 @@
 #define	MOD_FIELD(f)    . ## f = f
 #define	METHOD_BASE(_base, _name)       . ## _name = _base ## _name
 
-/*
- * Each 'registerable' entity has a pointer in the
- * struct ast_registry, which points to an array of objects of
- * the same type. The ast_*_register() function will be able to
- * derive the size of these entries.
- */
-struct ast_registry {
+enum ast_module_flags {
+	AST_MODULE_DEFAULT = 0,
+	AST_MODULE_TRACK_USECOUNT = (1 << 0),
+	AST_MODULE_TRACK_USERS = (1 << 1),
+	AST_MODULE_UNLOAD_FORCE_ONLY = (1 << 2),
+};
+
+/* The 'self' pointer for a module; it will be set by the loader before
+   it calls the module's load_module() entrypoint, and used by various
+   other macros that need to identify the module.
+*/
+
+#ifndef NOT_A_MODULE
+static struct ast_module *__module_self;
+#endif /* !NOT_A_MODULE */
+
+struct ast_module_info {
+
+	struct ast_module **self;
+
+	int (*load)(void);	/* register stuff etc. Optional. */
+
+	int (*reload)(void);	/* config etc. Optional. */
+
+	int (*unload)(void);	/* unload. called with the module locked */
+
+	const char *description;		/* textual id of the module. */
+
+	/*! 
+	 * This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of
+	 * the Asterisk license as stated in the ASTERISK_GPL_KEY.  Your module will not
+	 * load if it does not return the EXACT key string.
+	 */
+
+	const char *key;
+
+	const struct ast_flags flags;
+
+	struct ast_module_symbol *exported_symbols;
+	struct ast_module_symbol *required_symbols;
 	struct ast_cli_entry *clis;
 };
 
-struct module_symbols {
-	/* load, reload and unload receive as argument a pointer to a module descriptor
-	 * to be stored locally and used for local calls and so on.
-	 * They all return 0 on success, non zero (-1) on failure.
-	 */
-
-	int (*load_module)(void *);	/* register stuff etc. Optional. */
-
-	int (*reload)(void *);	/* reload config etc. Optional. */
-
-	int (*unload_module)(void *);	/* unload. called with the module locked */
-
-	const char *(*description)(void);	/* textual id of the module. */
-
-	/*! 
-	 * This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of
-	 * the GPL stated in the ASTERISK_GPL_KEY.  Your module will not load if it does
-	 * not return the EXACT message:
-	 */
-	const char *(*key)(void);	/*! the asterisk key */
-
-	enum module_flags {
-		MOD_0 = 0x0,	/* old module style */
-		MOD_1 = 0x1,	/* old style, but symbols here */
-		MOD_2 = 0x2,	/* new style, exported symbols */
-		MOD_MASK = 0xf,	/* mask for module types */
-		NO_USECOUNT = 0x10,	/* do not track usecount */
-		NO_UNLOAD = 0x20,	/* only forced unload allowed */
-		DO_LOCALUSERS = 0x40,	/* track localusers */
-	} flags;
-	/* the following two fields should go in the astobj. */
-	ast_mutex_t lock;		
-	int usecnt;	/* number of active clients */
-
-	/* list of clients */
-	struct localuser *lu_head;
-	struct ast_registry *reg;		/* list of things to register. */
-	struct symbol_entry *exported_symbols;
-	struct symbol_entry *required_symbols;
-};
-
-#ifndef MOD_LOADER	/* the loader does not use these */
-struct module_symbols mod_data;	/* forward declaration */
-static struct module_symbols *__mod_desc __attribute__ ((__unused__)) = &mod_data; /* used by localuser */
-
-#define STD_MOD(t, reload_fn, exp, req)			\
-struct module_symbols mod_data = {			\
-        .load_module = load_module,			\
-        .unload_module = unload_module,			\
-        .description = description,			\
-        .key = key,					\
-        .reload = reload_fn,				\
-	.flags = t,					\
-	.exported_symbols = exp,			\
-	.required_symbols = req				\
-};
-
-#define	STD_MOD1	STD_MOD(MOD_1, NULL, NULL, NULL)
-#endif
+struct ast_module_user *__ast_module_user_add(struct ast_module *, struct ast_channel *);
+void __ast_module_user_remove(struct ast_module *, struct ast_module_user *);
+void __ast_module_user_hangup_all(struct ast_module *);
+
+#define ast_module_user_add(chan) __ast_module_user_add(__module_self, chan)
+#define ast_module_user_remove(user) __ast_module_user_remove(__module_self, user)
+#define ast_module_user_hangup_all() __ast_module_user_hangup_all(__module_self)
+
+struct ast_module *ast_module_ref(struct ast_module *);
+void ast_module_unref(struct ast_module *);
+
+#define AST_MODULE_INFO(desc, keystr, flags_to_set, fields...)		\
+	const struct ast_module_info ast_module_info = {	\
+		.self = &__module_self,				\
+		.flags = { flags_to_set },			\
+		.description = desc,				\
+		.key = keystr,					\
+		fields						\
+	}
+
+#define AST_MODULE_INFO_STANDARD(desc, keystr)		\
+	AST_MODULE_INFO(desc, keystr, AST_MODULE_DEFAULT,	\
+			.load = load_module,			\
+			.unload = unload_module,			\
+		       )
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: team/group/new_loader_completion/include/asterisk/translate.h
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/include/asterisk/translate.h?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/include/asterisk/translate.h (original)
+++ team/group/new_loader_completion/include/asterisk/translate.h Mon Apr 17 19:12:06 2006
@@ -98,7 +98,7 @@
 	int plc_samples;	/* set to the plc block size if used, 0 otherwise */
 	int useplc;		/* current status of plc, changed at runtime */
 
-	void *module;		/* opaque reference to the parent module */
+	struct ast_module *module;		/* opaque reference to the parent module */
 
 	int cost;		/*! Cost in milliseconds for encoding/decoding 1 second of sound */
 	AST_LIST_ENTRY(ast_translator) list;	/*! link field */
@@ -147,7 +147,7 @@
  * This registers a codec translator with asterisk
  * \return 0 on success, -1 on failure
  */
-int ast_register_translator(struct ast_translator *t, void *module);
+int ast_register_translator(struct ast_translator *t, struct ast_module *module);
 
 /*!
  * \brief Unregister a translator

Modified: team/group/new_loader_completion/loader.c
URL: http://svn.digium.com/view/asterisk/team/group/new_loader_completion/loader.c?rev=21036&r1=21034&r2=21036&view=diff
==============================================================================
--- team/group/new_loader_completion/loader.c (original)
+++ team/group/new_loader_completion/loader.c Mon Apr 17 19:12:06 2006
@@ -4,6 +4,8 @@
  * Copyright (C) 1999 - 2006, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
+ * Kevin P. Fleming <kpfleming at digium.com>
+ * Luigi Rizzo <rizzo at icir.org>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -19,8 +21,9 @@
 /*! \file
  *
  * \brief Module Loader
- *
  * \author Mark Spencer <markster at digium.com> 
+ * \author Kevin P. Fleming <kpfleming at digium.com>
+ * \author Luigi Rizzo <rizzo at icir.org>
  * - See ModMngMnt
  */
 
@@ -28,15 +31,19 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
 
-#define MOD_LOADER	/* prevent some module-specific stuff from being compiled */
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/linkedlists.h"
+
+#define NOT_A_MODULE
 #include "asterisk/module.h"
+#undef NOT_A_MODULE
+
 #include "asterisk/options.h"
 #include "asterisk/config.h"
 #include "asterisk/logger.h"
@@ -48,11 +55,13 @@
 #include "asterisk/rtp.h"
 #include "asterisk/http.h"
 #include "asterisk/lock.h"
+
 #ifdef DLFCNCOMPAT
 #include "asterisk/dlfcn-compat.h"
 #else
 #include <dlfcn.h>
 #endif
+
 #include "asterisk/md5.h"
 #include "asterisk/utils.h"
 
@@ -60,7 +69,14 @@
 #define RTLD_NOW 0
 #endif
 
-static int modlistver = 0; /* increase whenever the list changes, to protect reload */
+struct ast_module_user {
+	struct ast_channel *chan;
+	AST_LIST_ENTRY(ast_module_user) entry;
+};
+
+AST_LIST_HEAD_NOLOCK(ast_module_user_list, ast_module_user);
+
+static unsigned int modlistver = 0; /* increase whenever the list changes, to protect reload */
 
 static unsigned char expected_key[] =
 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
@@ -93,22 +109,25 @@
  *
  * A second lock, reloadlock, is used to prevent concurrent reloads
  */
-struct module {
-	AST_LIST_ENTRY(module) next;
-	struct module_symbols *cb;
-	void *lib;		/* the shared lib */
-	char resource[256];
+struct ast_module {
+	const struct ast_module_info *mod;
+	ast_mutex_t lock;				/* protects usecount, export_refcount and users */
+	void *lib;					/* the shared lib */
 
 	enum st_t state;
-	int export_refcount;	/* how many users of exported symbols */
+	int export_refcount;				/* how many users of exported symbols */
+	int usecount;					/* the number of 'users' currently in this module */
+	struct ast_module_user_list users;		/* the list of users in the module */
+	AST_LIST_ENTRY(ast_module) entry;
+	char resource[0];
 };
 
 struct loadupdate {
-	AST_LIST_ENTRY(loadupdate) next;
 	int (*updater)(void);
+	AST_LIST_ENTRY(loadupdate) entry;
 };
 
-static AST_LIST_HEAD_STATIC(module_list, module);
+static AST_LIST_HEAD_STATIC(module_list, ast_module);
 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
 AST_MUTEX_DEFINE_STATIC(reloadlock);
 
@@ -119,85 +138,58 @@
  * the extra function call will be totally negligible in all cases.
  */
 
-struct localuser *ast_localuser_add(struct module_symbols *me,
-	struct ast_channel *chan)
-{
-	struct localuser *u = ast_calloc(1, sizeof(*u));
-	if (u == NULL)
+struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
+					      struct ast_channel *chan)
+{
+	struct ast_module_user *u = ast_calloc(1, sizeof(*u));
+
+	if (!u)
 		return NULL;
+
 	u->chan = chan;
-	ast_mutex_lock(&me->lock);
-	u->next = me->lu_head;
-	me->lu_head = u;
-	ast_mutex_unlock(&me->lock);
-	ast_atomic_fetchadd_int(&me->usecnt, +1);
+	ast_mutex_lock(&mod->lock);
+	AST_LIST_INSERT_HEAD(&mod->users, u, entry);
+	ast_mutex_unlock(&mod->lock);
+	ast_atomic_fetchadd_int(&mod->usecount, +1);
+
 	ast_update_use_count();
+
 	return u;
 }
 
-void ast_localuser_remove(struct module_symbols *me, struct localuser *u)
-{
-	struct localuser *x, *prev = NULL;
-	ast_mutex_lock(&me->lock);
-	/* unlink from the list */
-	for (x = me->lu_head; x; prev = x, x = x->next) {
-		if (x == u) {
-			if (prev)
-				prev->next = x->next;
-			else
-				me->lu_head = x->next;
-			break;
-		}
-	}
-	ast_mutex_unlock(&me->lock);
-	ast_atomic_fetchadd_int(&me->usecnt, -1);
+void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
+{
+	ast_mutex_lock(&mod->lock);
+	AST_LIST_REMOVE(&mod->users, u, entry);
+	ast_mutex_unlock(&mod->lock);
+	ast_atomic_fetchadd_int(&mod->usecount, -1);
 	free(u);
+
 	ast_update_use_count();
 }
 
-void ast_hangup_localusers(struct module_symbols *me)
-{
-	struct localuser *u, *next;
-	ast_mutex_lock(&me->lock);
-	for (u = me->lu_head; u; u = next) {
-		next = u->next;
+void __ast_module_user_hangup_all(struct ast_module *mod)
+{
+	struct ast_module_user *u;
+
+	ast_mutex_lock(&mod->lock);
+	while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
 		ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
-		ast_atomic_fetchadd_int(&me->usecnt, -1);
+		ast_atomic_fetchadd_int(&mod->usecount, -1);
 		free(u);
 	}
-	ast_mutex_unlock(&me->lock);
+	ast_mutex_unlock(&mod->lock);
+
         ast_update_use_count();
 }
-
-/*--- new-style loader routines ---*/
-
-/*
- * For backward compatibility, we have 3 types of loadable modules:
- *
- * MOD_0 these are the 'old style' modules, which export a number
- *       of callbacks, and their full interface, as globally visible
- *       symbols. The module needs to be loaded with RTLD_LAZY and
- *       RTLD_GLOBAL to make symbols visible to other modules, and
- *       to avoid load failures due to cross dependencies.
- *
- * MOD_1 The generic callbacks are all into a structure, mod_data.
- *
- * MOD_2 this is the 'new style' format for modules. The module must
- *       explictly declare which simbols are exported and which
- *       symbols from other modules are used, and the code in this
- *       loader will implement appropriate checks to load the modules
- *       in the correct order. Also this allows to load modules
- *       with RTLD_NOW and RTLD_LOCAL so there is no chance of run-time
- *       bugs due to unresolved symbols or name conflicts.
- */
 
 /*
  * helper routine to print the symbolic name associated to a state
  */
 static const char *st_name(enum st_t state)
 {
-	/* try to resolve required symbols */
 	const char *st;
+
 	switch (state) {
 #define ST(x)  case x: st = # x; break;
 	ST(MS_NEW);
@@ -222,16 +214,18 @@
  * Must be called with the lock held.
  */
 static void *module_symbol_helper(const char *name,
-		int delta, struct module **src)
+				  int delta, struct ast_module **src)
 {
 	void *ret = NULL;
-	struct module *m;
-
-	AST_LIST_TRAVERSE(&module_list, m, next) {
-		struct symbol_entry *es;
+	struct ast_module *m;
+
+	AST_LIST_TRAVERSE(&module_list, m, entry) {
+		struct ast_module_symbol *es;
+
 		if (delta > 0 && m->state == MS_FAILED)
 			continue; /* cannot 'get' a symbol from a failed module */
-		for (es = m->cb->exported_symbols; ret == NULL && es && es->name; es++) {
+
+		for (es = m->mod->exported_symbols; ret == NULL && es && es->name; es++) {
 			if (!strcmp(es->name, name)) {
 				ret = es->value;
 				m->export_refcount += delta;
@@ -243,8 +237,10 @@
 		if (ret)
 			break;
 	}
-	if (ret == NULL)
+
+	if (!ret)
 		ast_log(LOG_WARNING, "symbol %s not found\n", name);
+
 	return ret;
 }
 
@@ -253,7 +249,7 @@
 	return module_symbol_helper(name, -1, NULL);
 }
 
-static void *get_module_symbol(const char *name, struct module **src)
+static void *get_module_symbol(const char *name, struct ast_module **src)
 {
 	return module_symbol_helper(name, +1, src);
 }
@@ -262,12 +258,12 @@
  * \brief Release refcounts to all imported symbols,
  * and change module state to MS_FAILED.
  */
-static void release_module(struct module *m)
-{
-	struct symbol_entry *s;
-
-	for (s = m->cb->required_symbols; s && s->name != NULL; s++) {
-		if (s->value != NULL) {
+static void release_module(struct ast_module *m)
+{
+	struct ast_module_symbol *s;
+
+	for (s = m->mod->required_symbols; s && s->name; s++) {
+		if (s->value) {
 			release_module_symbol(s->name);
 			s->value = NULL;
 		}
@@ -276,28 +272,26 @@
 }
 
 /*! \brief check that no NULL symbols are exported  - the algorithms rely on that. */
-static int check_exported(struct module *m)
-{
-	struct symbol_entry *es = m->cb->exported_symbols;
+static int check_exported(struct ast_module *m)
+{
+	struct ast_module_symbol *es = m->mod->exported_symbols;
 	int errors = 0;
 
-	if (es == NULL)
+	if (!es)
 		return 0;
-	ast_log(LOG_WARNING, "module %s exports the following symbols\n",
-		es->name);
+
 	for (; es->name; es++) {
 		void **p = es->value;
 		int i;
 
-		ast_log(LOG_WARNING, "\taddr %p size %8d %s\n",
-			es->value, es->size, es->name);
 		for (i = 0; i <  es->size / sizeof(void *); i++, p++) {
-			if (*p == NULL) {
+			if (!*p) {
 				ast_log(LOG_WARNING, "\t *** null field at offset %d\n", i);
 					errors++;
 			}
 		}
 	}
+
 	return errors;
 }
 
@@ -310,23 +304,25 @@
  * If all suppliers are MS_ACTIVE, move to MS_CANLOAD
  * otherwise move to MS_RESOLVED.
  */
-static int resolve(struct module *m)
-{
-	struct symbol_entry *s;
+static int resolve(struct ast_module *m)
+{
+	struct ast_module_symbol *s;
 
 	if (m->state == MS_FAILED || m->state == MS_ACTIVE || m->state == MS_CANLOAD)
 		return 0;	/* already decided what to do */
+
 	/* now it's either MS_NEW or MS_RESOLVED.
 	 * Be optimistic and put it in MS_CANLOAD, then try to
 	 * resolve and verify symbols, and downgrade as appropriate.
 	 */
 	m->state = MS_CANLOAD;
-	for (s = m->cb->required_symbols; s && s->name != NULL; s++) {
+	for (s = m->mod->required_symbols; s && s->name; s++) {
 		void **p = (void **)(s->value);
 
-		if (*p == NULL)		/* symbol not resolved yet */
+		if (!*p)		/* symbol not resolved yet */
 			*p = get_module_symbol(s->name, &s->src);
-		if (*p == NULL || s->src->state == MS_FAILED) {        /* fail */
+
+		if (!*p || s->src->state == MS_FAILED) {        /* fail */
 			ast_log(LOG_WARNING,
 				"Unresolved symbol %s for module %s\n",
 				s->name, m->resource);
@@ -336,6 +332,7 @@
 		if (s->src->state != MS_ACTIVE)
 			m->state = MS_RESOLVED; /* downgrade */
 	}
+
 	return 1;
 }
 
@@ -364,14 +361,14 @@
  */
 static int fixup(const char *caller)
 {
-	struct module *m;
+	struct ast_module *m;
 	int total = 0, new = 0, cycle = 0;
 	static int in_fixup = 0;        /* disable recursive calls */
 
-	if (in_fixup)
+	if (++in_fixup > 1)
 		return 0;
-	in_fixup++;
-	AST_LIST_TRAVERSE(&module_list, m, next) {
+
+	AST_LIST_TRAVERSE(&module_list, m, entry) {
 		total++;
 		if (m->state == MS_FAILED)
 			m->state = MS_NEW;
@@ -379,32 +376,30 @@
 			new++;
 		/* print some debugging info for new modules */
 		if (m->state == MS_NEW &&
-		    (m->cb->exported_symbols || m->cb->required_symbols))
+		    (m->mod->exported_symbols || m->mod->required_symbols))
 			ast_log(LOG_NOTICE,
 			    "module %-30s exports %p requires %p state %s(%d)\n",
-				m->resource, m->cb->exported_symbols,
-				m->cb->required_symbols,
+				m->resource, m->mod->exported_symbols,
+				m->mod->required_symbols,
 				st_name(m->state), m->state);
 	}
-	ast_log(LOG_DEBUG, "---- fixup (%s): %d modules, %d new ---\n",
-		caller, total, new);
-	for (;;cycle++) {
+
+	for (; ;cycle++) {
 		int again = 0;	/* set if we need another round */
 		
-		ast_log(LOG_DEBUG, "---- fixup: cycle %d ---\n", cycle);
-		AST_LIST_TRAVERSE(&module_list, m, next) {
+		AST_LIST_TRAVERSE(&module_list, m, entry) {
 			if (resolve(m))
 				again = 1;	/* something changed */
+
 			if (m->state != MS_CANLOAD)	/* for now, done with this module */
 				continue;
+
 			/* try to run the load routine */
-			if (m->cb->load_module(m)) { /* error */
+			if (m->mod->load()) {
 				ast_log(LOG_WARNING, "load_module %s fail\n",
 					m->resource);
 				release_module(m); /* and set to MS_FAIL */
 			} else {
-				ast_log(LOG_WARNING, "load_module %s success\n",
-					m->resource);
 				m->state = MS_ACTIVE;
 			}
 			again = 1;	/* something has changed */
@@ -412,7 +407,7 @@
 		/* Modules in MS_RESOLVED mean a possible cyclic dependency.
 		 * Break the indecision by setting one to CANLOAD, and repeat.
 		 */
-		AST_LIST_TRAVERSE(&module_list, m, next) {
+		AST_LIST_TRAVERSE(&module_list, m, entry) {
 			if (m->state == MS_RESOLVED) {
 				m->state = MS_CANLOAD;
 				again = 1;
@@ -422,11 +417,13 @@
 		if (!again)	/* we are done */
 			break;
 	}
-	ast_log(LOG_DEBUG, "---- fixup complete ---\n");
+
 	in_fixup--;
+
 	return 0;
 }
 
+#if 0
 /* test routines to see which modules depend on global symbols
  * exported by other modules.
  */
@@ -453,7 +450,7 @@
 		dlclose(lib);
 	}
 }
-/*--- end new-style routines ---*/
+#endif
 
 /*! \note
  * In addition to modules, the reload command handles some extra keywords
@@ -482,16 +479,19 @@
 	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;
 }
 
 static int key_matches(const unsigned char *key1, const unsigned char *key2)
 {
 	int x;
+
 	for (x=0; x<16; x++) {
 		if (key1[x] != key2[x])	/* mismatch - fail now. */
 			return 0;
 	}
+
 	return 1;
 }
 
@@ -499,38 +499,55 @@
 {
 	struct MD5Context c;
 	unsigned char digest[16];
+
 	MD5Init(&c);
 	MD5Update(&c, key, strlen((char *)key));
 	MD5Final(digest, &c);
 	if (key_matches(expected_key, digest))
 		return 0;
 	printdigest(digest);
+
 	return -1;
 }
 
-int ast_unload_resource(const char *resource_name, enum unload_mode force)
-{
-	struct module *cur;
+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_mutex_destroy(&mod->lock);
+	free(mod);
+}
+
+int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
+{
+	struct ast_module *cur;
 	int res = -1;
 	int error = 0;
-	if (AST_LIST_LOCK(&module_list)) /* XXX should fail here ? */
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, cur, next) {
-		struct module_symbols *m = cur->cb;
-		
+
+	AST_LIST_LOCK(&module_list);
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, cur, entry) {
 		if (strcasecmp(cur->resource, resource_name))	/* not us */
 			continue;
-		if (m->usecnt > 0 || m->flags & NO_UNLOAD)  {
+
+		if (cur->usecount > 0 || ast_test_flag(&cur->mod->flags, AST_MODULE_UNLOAD_FORCE_ONLY)) {
 			if (force) 
-				ast_log(LOG_WARNING, "Warning:  Forcing removal of module %s with use count %d\n", resource_name, res);
+				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, res);
+				ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
+					cur->usecount);
 				error = 1;
 				break;
 			}
 		}
-		ast_hangup_localusers(m);
-		res = m->unload_module(m);
+
+		__ast_module_user_hangup_all(cur);
+		res = cur->mod->unload();
+
 		if (res) {
 			ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
 			if (force <= AST_FORCE_FIRM) {
@@ -539,50 +556,62 @@
 			} else
 				ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
 		}
-		release_module(cur);	/* XXX */
-		AST_LIST_REMOVE_CURRENT(&module_list, next);
+
+		release_module(cur);
+
+		AST_LIST_REMOVE_CURRENT(&module_list, entry);
+
 		dlclose(cur->lib);
-		free(cur);
+		free_module(cur);
+
 		break;
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
+
 	if (!error)
 		modlistver++;
+
 	AST_LIST_UNLOCK(&module_list);
-	if (!error)	/* XXX maybe within the lock ? */
+
+	if (!error)
 		ast_update_use_count();
+
 	return res;
 }
 
 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
 {
-	struct module *cur;
+	struct ast_module *cur;
 	int i, which=0, l = strlen(word);
 	char *ret = NULL;
 
 	if (pos != rpos)
 		return NULL;
+
 	AST_LIST_LOCK(&module_list);
-	AST_LIST_TRAVERSE(&module_list, cur, next) {
-		if (!strncasecmp(word, cur->resource, l) && (cur->cb->reload || !needsreload) &&
-				++which > state) {
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
+		if (!strncasecmp(word, cur->resource, l) &&
+		    (cur->mod->reload || !needsreload) &&
+		    ++which > state) {
 			ret = strdup(cur->resource);
 			break;
 		}
 	}
 	AST_LIST_UNLOCK(&module_list);
+
 	if (!ret) {
 		for (i=0; !ret && reload_classes[i].name; i++) {
 			if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
 				ret = strdup(reload_classes[i].name);
 		}
 	}
+
 	return ret;
 }
 
 int ast_module_reload(const char *name)
 {
-	struct module *cur;
+	struct ast_module *cur;
 	int res = 0; /* return value. 0 = not found, others, see below */
 	int i, oldversion;
 
@@ -590,6 +619,7 @@
 		ast_verbose("The previous reload command didn't finish yet\n");
 		return -1;	/* reload already in progress */
 	}
+
 	/* Call "predefined" reload here first */
 	for (i = 0; reload_classes[i].name; i++) {
 		if (!name || !strcasecmp(name, reload_classes[i].name)) {
@@ -599,48 +629,53 @@
 	}
 	ast_lastreloadtime = time(NULL);
 
+	if (name && res)
+		return res;
+
 	AST_LIST_LOCK(&module_list);
 	oldversion = modlistver;
-	AST_LIST_TRAVERSE(&module_list, cur, next) {
-		struct module_symbols *m = cur->cb;
+	AST_LIST_TRAVERSE(&module_list, cur, entry) {
+		const struct ast_module_info *mod = cur->mod;
+
 		if (name && strcasecmp(name, cur->resource))	/* not ours */
 			continue;
-		if (!m->reload) {	/* cannot be reloaded */
+
+		if (!mod->reload) {	/* cannot be reloaded */
 			if (res < 1)	/* store result if possible */
 				res = 1;	/* 1 = no reload() method */
 			continue;
 		}
-		/* drop the lock and try a reload. if successful, break */
-		AST_LIST_UNLOCK(&module_list);
+
 		res = 2;
 		if (option_verbose > 2) 
-			ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, m->description());
-		m->reload(m);
-		AST_LIST_LOCK(&module_list);
-		if (oldversion != modlistver) /* something changed, abort */
-			break;
+			ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, mod->description);
+		mod->reload();
 	}
 	AST_LIST_UNLOCK(&module_list);
+
 	ast_mutex_unlock(&reloadlock);
+
 	return res;
 }
 
 static int resource_exists(const char *resource, int do_lock)
 {
-	struct module *cur;
+	struct ast_module *cur;
+
 	if (do_lock && AST_LIST_LOCK(&module_list))
 		ast_log(LOG_WARNING, "Failed to lock\n");
-	AST_LIST_TRAVERSE(&module_list, cur, next) {
+	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;
 }
 
 /* lookup a symbol with or without leading '_', accept either form in input */
-static void *find_symbol(struct module *m, const char *name, int verbose)
+static void *find_symbol(struct ast_module *m, const char *name, int verbose)
 {
 	char *n1;
 	void *s;
@@ -660,88 +695,58 @@
 	return s;
 }
 
-/* XXX cfg is only used for !res_* and #ifdef RTLD_GLOBAL */
-static struct module * __load_resource(const char *resource_name,
-	const struct ast_config *cfg)
+/* assumes module_list will be locked */
+static struct ast_module * __load_resource(const char *resource_name)
 {
 	static char fn[256];
 	int errors=0;
-	int res;
-	struct module *cur;
-	struct module_symbols *m = NULL;
-	int flags = RTLD_NOW;
+	struct ast_module *cur;
+	const struct ast_module_info *m;
 	unsigned char *key;
 	char tmp[80];
 
-#ifndef RTLD_GLOBAL
-#define RTLD_GLOBAL	0	/* so it is a No-op */
-#endif
-	if (strncasecmp(resource_name, "res_", 4) && cfg) {
-		char *val = ast_variable_retrieve(cfg, "global", resource_name);
-		if (val && ast_true(val))
-			flags |= RTLD_GLOBAL;
-	} else {
-		/* Resource modules are always loaded global and lazy */
-		flags = (RTLD_GLOBAL | RTLD_LAZY);
-	}
-	
-	if (AST_LIST_LOCK(&module_list))
-		ast_log(LOG_WARNING, "Failed to lock\n");
 	if (resource_exists(resource_name, 0)) {
 		ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
-		AST_LIST_UNLOCK(&module_list);
 		return NULL;
 	}
-	if (!(cur = ast_calloc(1, sizeof(*cur)))) {
-		AST_LIST_UNLOCK(&module_list);
+	if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(resource_name) + 1))) {
 		return NULL;
 	}
-	ast_copy_string(cur->resource, resource_name, sizeof(cur->resource));
+
+	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);
 
-	/* open in a sane way */
-	cur->lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
-	if (cur->lib &&
-		    ((m = find_symbol(cur, "mod_data", 0)) == NULL || (m->flags & MOD_MASK) == MOD_0)) {
-		/* old-style module, close and reload with standard flags */
-		dlclose(cur->lib);
-		cur->lib = NULL;
-		m = NULL;
-	}
-	if (cur->lib == NULL)	/* try reopen with the old style */
-		cur->lib = dlopen(fn, flags);
-
-	if (!cur->lib) {
+	if (!(cur->lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL))) {
 		ast_log(LOG_WARNING, "%s\n", dlerror());
 		free(cur);
-		AST_LIST_UNLOCK(&module_list);
 		return NULL;
 	}
-	if (m == NULL)	/* MOD_0 modules may still have a mod_data entry */
-		m = find_symbol(cur, "mod_data", 0);
-	if (m != NULL) {	/* new style module */
-		ast_log(LOG_WARNING, "new style %s (0x%x) loaded RTLD_LOCAL\n",
-			resource_name, m->flags);
-		cur->cb = m;	/* use the mod_data from the module itself */
-		errors = check_exported(cur);
-	} else {
-		ast_log(LOG_WARNING, "misstng mod_data for %s\n",
+
+	if (!(m = find_symbol(cur, "ast_module_info", 0))) {
+		ast_log(LOG_WARNING, "Module '%s' does not provide the proper module information for this version of Asterisk.\n",
 			resource_name);
+		dlclose(cur->lib);
+		free(cur);
+		return NULL;
+	}
+
+	cur->mod = m;
+	errors = check_exported(cur);
+
+	if (!m->load)
 		errors++;
-	}
-	if (!m->load_module)
-		errors++;
-	if (!m->unload_module && !(m->flags & NO_UNLOAD) )
+	if (!m->unload)
 		errors++;
 	if (!m->description)
 		errors++;
 	if (!m->key)
 		errors++;
-	if (!m->key || !(key = (unsigned char *) m->key())) {
-		ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn);
+	if (!(key = (unsigned char *) m->key)) {
+		ast_log(LOG_WARNING, "Module %s does not contain a license key.\n", fn);
 		key = NULL;
 		errors++;
 	}
@@ -753,217 +758,172 @@
 		ast_log(LOG_WARNING, "%d error%s loading module %s, aborted\n", errors, (errors != 1) ? "s" : "", fn);
 		dlclose(cur->lib);
 		free(cur);
-		AST_LIST_UNLOCK(&module_list);
 		return NULL;
 	}
-	/* init mutex and usecount */
-	ast_mutex_init(&cur->cb->lock);
-	cur->cb->lu_head = NULL;
+
+	/* init mutex and user list */
+	ast_mutex_init(&cur->lock);
+	AST_LIST_HEAD_INIT_NOLOCK(&cur->users);
 
 	if (!ast_fully_booted) {
 		if (option_verbose) 
-			ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
+			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());
-	}
-
-	AST_LIST_INSERT_TAIL(&module_list, cur, next);
+			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++;
-	if ( (m->flags & MOD_MASK) == MOD_2) {
-		ast_log(LOG_WARNING, "new-style module %s, deferring load()\n",
-			resource_name);
-		cur->state = MS_NEW;
-	} else
-		cur->state = MS_CANLOAD;
-	/* XXX make sure the usecount is 1 before releasing the lock */
-	AST_LIST_UNLOCK(&module_list);
-	

[... 919 lines stripped ...]


More information about the asterisk-commits mailing list