[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