aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2008-07-15 13:14:07 +0000
committermurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2008-07-15 13:14:07 +0000
commit0fe0bac06aee27353c279009b1c2dc74b20043c2 (patch)
treebdef23b6cbba2974e714c2b74c02ec455e70f1b2
parent560edcd1346f6ecaf7f39c48bb096bcaf039d5a8 (diff)
Merged revisions 130145 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk Merging this rev from trunk to 1.6.0 was not simple. Why? Because we've enhanced trunk to do a [fast] merge-and-delete operation which also solved problems with contexts having entries from different registrars. Fast as in the amount of time the contexts are locked down. That *is* fast, but traversing the entire dialplan looking for priorities to delete takes more time overall. This particular fix involved pulling in those enhancements from trunk, along with all the various fixes and refinements made along the way. Merging all this from trunk into 1.6 involved: a. mergetrunk6 in the stuff from 130145; b. revert all but the prop changes c. catalog all revisions to pbx.c since 1.6.0 was forked (at rev 105596). d. catalog all revisions to pbx.c in trunk since 1.6.0 was forked, making special note of all revs that were not merged into 1.6.0. e. study each rev in trunk not applied to 1.6.0, and determine if it was involved in the merge_and_delete enhancements in trunk. 25 commits were done in 1.6.0, all but one (106306) was a merge from trunk. Trunk had 22 additional changes, of which 7 were involved in the merge_and_delete enhancements: 106757 108894 109169 116461 123358 130145 130297 f. Go to trunk and collect patches, one by one, of the changes made by each rev across the entire source tree, using svn diff -c <num> > pfile g. Apply each patch in order to 1.6.0, and resolve all failures and compilation problems before proceding to the next patch. h. test the stuff. i. profit! ........ r130145 | murf | 2008-07-11 12:24:31 -0600 (Fri, 11 Jul 2008) | 40 lines (closes issue #13041) Reported by: eliel Tested by: murf (closes issue #12960) Reported by: mnicholson In this 'omnibus' fix, I **think** I solved both the problem in 13041, where unloading pbx_ael.so caused crashes, or incomplete removal of previous registrar'ed entries. And I added code to completely remove all includes, switches, and ignorepats that had a matching registrar entry, which should appease 12960. I also added a lot of seemingly useless brackets around single statement if's, which helped debug so much that I'm leaving them there. I added a routine to check the correlation between the extension tree lists and the hashtab tables. It can be amazingly helpful when you have lots of dialplan stuff, and need to narrow down where a problem is occurring. It's ifdef'd out by default. I cleaned up the code around the new CIDmatch code. It was leaving hanging extens with bad ptrs, getting confused over which objects to remove, etc. I tightened up the code and changed the call to remove_exten in the merge_and_delete code. I added more conditions to check for empty context worthy of deletion. It's not empty if there are any includes, switches, or ignorepats present. If I've missed anything, please re-open this bug, and be prepared to supply example dialplan code. ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@130946 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_dial.c4
-rw-r--r--apps/app_meetme.c4
-rw-r--r--apps/app_queue.c4
-rw-r--r--apps/app_stack.c2
-rw-r--r--channels/chan_iax2.c3
-rw-r--r--channels/chan_sip.c9
-rw-r--r--channels/chan_skinny.c3
-rw-r--r--include/asterisk/pbx.h40
-rw-r--r--include/asterisk/pval.h3
-rw-r--r--main/features.c15
-rw-r--r--main/pbx.c949
-rw-r--r--pbx/pbx_ael.c12
-rw-r--r--pbx/pbx_config.c16
-rw-r--r--res/ael/ael.flex4
-rw-r--r--res/ael/ael.tab.c502
-rw-r--r--res/ael/ael.tab.h2
-rw-r--r--res/ael/ael.y2
-rw-r--r--res/ael/ael_lex.c141
-rw-r--r--res/ael/pval.c6
-rw-r--r--utils/Makefile4
-rw-r--r--utils/ael_main.c32
-rw-r--r--utils/conf2ael.c45
-rw-r--r--utils/extconf.c1480
23 files changed, 1921 insertions, 1361 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index b3d0a05ba..60b1611c7 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -2084,9 +2084,7 @@ static int load_module(void)
int res;
struct ast_context *con;
- con = ast_context_find("app_dial_gosub_virtual_context");
- if (!con)
- con = ast_context_create(NULL, "app_dial_gosub_virtual_context", "app_dial");
+ con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
if (!con)
ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
else
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index cb5301f2f..418d56b36 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -5298,7 +5298,7 @@ static int sla_build_trunk(struct ast_config *cfg, const char *cat)
if (!ast_strlen_zero(trunk->autocontext)) {
struct ast_context *context;
- context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
+ context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
if (!context) {
ast_log(LOG_ERROR, "Failed to automatically find or create "
"context '%s' for SLA!\n", trunk->autocontext);
@@ -5435,7 +5435,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
if (!ast_strlen_zero(station->autocontext)) {
struct ast_context *context;
struct sla_trunk_ref *trunk_ref;
- context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
+ context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
if (!context) {
ast_log(LOG_ERROR, "Failed to automatically find or create "
"context '%s' for SLA!\n", station->autocontext);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 9e5f8736f..acf259c83 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -6368,9 +6368,7 @@ static int load_module(void)
if (!reload_queues(0))
return AST_MODULE_LOAD_DECLINE;
- con = ast_context_find("app_queue_gosub_virtual_context");
- if (!con)
- con = ast_context_create(NULL, "app_queue_gosub_virtual_context", "app_queue");
+ con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
if (!con)
ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
else
diff --git a/apps/app_stack.c b/apps/app_stack.c
index 3dc06904f..f77080849 100644
--- a/apps/app_stack.c
+++ b/apps/app_stack.c
@@ -520,7 +520,7 @@ static int load_module(void)
}
if (agi_loaded) {
- con = ast_context_find_or_create(NULL, "app_stack_gosub_virtual_context", "app_stack");
+ con = ast_context_find_or_create(NULL, NULL, "app_stack_gosub_virtual_context", "app_stack");
if (!con) {
ast_log(LOG_ERROR, "Virtual context 'app_stack_gosub_virtual_context' does not exist and unable to create\n");
return AST_MODULE_LOAD_DECLINE;
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 8fb226c4b..de0073ef8 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -11023,8 +11023,7 @@ static int set_config(char *config_file, int reload)
} else if (!strcasecmp(v->name, "regcontext")) {
ast_copy_string(regcontext, v->value, sizeof(regcontext));
/* Create context if it doesn't exist already */
- if (!ast_context_find(regcontext))
- ast_context_create(NULL, regcontext, "IAX2");
+ ast_context_find_or_create(NULL, NULL, regcontext, "IAX2");
} else if (!strcasecmp(v->name, "tos")) {
if (ast_str2tos(v->value, &tos))
ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 90b15e161..79b1e1889 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -3441,6 +3441,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
{
char multi[256];
char *stringp, *ext, *context;
+ struct pbx_find_info q = { .stacklen = 0 };
/* XXX note that global_regcontext is both a global 'enable' flag and
* the name of the global regexten context, if not specified
@@ -3461,11 +3462,12 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
} else {
context = global_regcontext;
}
- if (onoff)
+ if (onoff) {
ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
ast_strdup(peer->name), ast_free_ptr, "SIP");
- else
+ } else if (pbx_find_extension(NULL, NULL, &q, context, ext, 1, NULL, "", E_MATCH)) {
ast_context_remove_extension(context, ext, 1, NULL);
+ }
}
}
@@ -20616,8 +20618,7 @@ static int reload_config(enum channelreloadreason reason)
/* Create contexts if they don't exist already */
while ((context = strsep(&stringp, "&"))) {
ast_copy_string(used_context, context, sizeof(used_context));
- if (!ast_context_find(context))
- ast_context_create(NULL, context, "SIP");
+ ast_context_find_or_create(NULL, NULL, context, "SIP");
}
ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext));
} else if (!strcasecmp(v->name, "regextenonqualify")) {
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 0c9827baf..8dab03f9f 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -5913,8 +5913,7 @@ static int reload_config(void)
/* Create contexts if they don't exist already */
while ((context = strsep(&stringp, "&"))) {
ast_copy_string(used_context, context, sizeof(used_context));
- if (!ast_context_find(context))
- ast_context_create(NULL, context, "Skinny");
+ ast_context_find_or_create(NULL, NULL, context, "Skinny");
}
ast_copy_string(regcontext, v->value, sizeof(regcontext));
} else if (!strcasecmp(v->name, "dateformat")) {
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index d8fcbae07..574a4b312 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -25,6 +25,7 @@
#include "asterisk/sched.h"
#include "asterisk/chanvars.h"
+#include "asterisk/hashtab.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -167,45 +168,36 @@ struct ast_app *pbx_findapp(const char *app);
int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
/*!
- * \brief Register a new context
- *
- * \param extcontexts pointer to the ast_context structure pointer
- * \param name name of the new context
- * \param registrar registrar of the context
- *
- * This will first search for a context with your name. If it exists already, it will not
- * create a new one. If it does not exist, it will create a new one with the given name
- * and registrar.
- *
- * \return NULL on failure, and an ast_context structure on success
- */
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-/*!
* \brief Register a new context or find an existing one
*
* \param extcontexts pointer to the ast_context structure pointer
+ * \param exttable pointer to the hashtable that contains all the elements in extcontexts
* \param name name of the new context
* \param registrar registrar of the context
*
+ * This function allows you to play in two environments: the global contexts (active dialplan)
+ * or an external context set of your choosing. To act on the external set, make sure extcontexts
+ * and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.
+ *
* This will first search for a context with your name. If it exists already, it will not
* create a new one. If it does not exist, it will create a new one with the given name
* and registrar.
*
* \return NULL on failure, and an ast_context structure on success
*/
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar);
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar);
/*!
* \brief Merge the temporary contexts into a global contexts list and delete from the
* global list the ones that are being added
*
- * \param extcontexts pointer to the ast_context structure pointer
+ * \param extcontexts pointer to the ast_context structure
+ * \param exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
* \param registrar of the context; if it's set the routine will delete all contexts
* that belong to that registrar; if NULL only the contexts that are specified
* in extcontexts
*/
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
/*!
* \brief Destroy a context (matches the specified context (or ANY context if NULL)
@@ -775,6 +767,8 @@ const char *ast_get_include_name(struct ast_include *include);
const char *ast_get_ignorepat_name(struct ast_ignorepat *ip);
const char *ast_get_switch_name(struct ast_sw *sw);
const char *ast_get_switch_data(struct ast_sw *sw);
+int ast_get_switch_eval(struct ast_sw *sw);
+
/*! @} */
/*! @name Other Extension stuff */
@@ -997,8 +991,18 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
struct ast_context *bypass, struct pbx_find_info *q,
const char *context, const char *exten, int priority,
const char *label, const char *callerid, enum ext_match_t action);
+
+
+/* every time a write lock is obtained for contexts,
+ a counter is incremented. You can check this via the
+ following func */
+
+int ast_wrlock_contexts_version(void);
+/* hashtable functions for contexts */
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
#if defined(__cplusplus) || defined(c_plusplus)
}
diff --git a/include/asterisk/pval.h b/include/asterisk/pval.h
index 2dff24ddc..acc9b30e1 100644
--- a/include/asterisk/pval.h
+++ b/include/asterisk/pval.h
@@ -1,6 +1,7 @@
#ifndef _ASTERISK_PVAL_H
#define _ASTERISK_PVAL_H
+/* whatever includes this, better include asterisk/lock.h and asterisk/hashtab.h */
typedef enum
{
@@ -143,7 +144,7 @@ void destroy_extensions(struct ael_extension *exten);
static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context ); */
void set_priorities(struct ael_extension *exten);
void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
void destroy_pval(pval *item);
void destroy_pval_item(pval *item);
int is_float(char *arg );
diff --git a/main/features.c b/main/features.c
index eca00f65d..6f3b31fb0 100644
--- a/main/features.c
+++ b/main/features.c
@@ -490,9 +490,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
ast_adsi_unload_session(peer);
}
- con = ast_context_find(parking_con);
- if (!con)
- con = ast_context_create(NULL, parking_con, registrar);
+ con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
if (!con) /* Still no context? Bad */
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
/* Tell the peer channel the number of the parking space */
@@ -2205,12 +2203,9 @@ static void *do_parking_thread(void *ignore)
if (peername_flat[i] == '/')
peername_flat[i]= '0';
}
- con = ast_context_find(parking_con_dial);
- if (!con) {
- con = ast_context_create(NULL, parking_con_dial, registrar);
- if (!con)
- ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
- }
+ con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
+ if (!con)
+ ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
if (con) {
char returnexten[AST_MAX_EXTENSION];
struct ast_datastore *features_datastore;
@@ -2799,7 +2794,7 @@ static int load_config(void)
ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
}
- if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
+ if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
return -1;
}
diff --git a/main/pbx.c b/main/pbx.c
index b847e9031..7de2e46f6 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cdr.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
+#include "asterisk/time.h"
#include "asterisk/manager.h"
#include "asterisk/ast_expr.h"
#include "asterisk/linkedlists.h"
@@ -142,8 +143,8 @@ struct ast_exten {
void *data; /*!< Data to use (arguments) */
void (*datad)(void *); /*!< Data destructor */
struct ast_exten *peer; /*!< Next higher priority with our extension */
- struct ast_hashtab *peer_tree; /*!< Priorities list in tree form -- only on the head of the peer list */
- struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
+ struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */
+ struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
const char *registrar; /*!< Registrar */
struct ast_exten *next; /*!< Extension with a greater ID */
char stuff[0];
@@ -204,12 +205,13 @@ struct scoreboard /* make sure all fields are 0 before calling new_find_extensi
struct ast_context {
ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
struct ast_exten *root; /*!< The root of the list of extensions */
- struct ast_hashtab *root_tree; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
+ struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
struct ast_context *next; /*!< Link them together */
struct ast_include *includes; /*!< Include other contexts */
struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
- const char *registrar; /*!< Registrar */
+ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
+ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */
AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
char name[0]; /*!< Name of the context */
@@ -329,14 +331,15 @@ static struct match_char *add_pattern_node(struct ast_context *con, struct match
static void create_match_char_tree(struct ast_context *con);
static struct ast_exten *get_canmatch_exten(struct match_char *node);
static void destroy_pattern_tree(struct match_char *pattern_tree);
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
-static unsigned int hashtab_hash_contexts(const void *obj);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
static unsigned int hashtab_hash_extens(const void *obj);
static unsigned int hashtab_hash_priority(const void *obj);
static unsigned int hashtab_hash_labels(const void *obj);
+static void __ast_internal_context_destroy( struct ast_context *con);
/* a func for qsort to use to sort a char array */
static int compare_char(const void *a, const void *b)
@@ -352,7 +355,7 @@ static int compare_char(const void *a, const void *b)
}
/* labels, contexts are case sensitive priority numbers are ints */
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
{
const struct ast_context *ac = ah_a;
const struct ast_context *bc = ah_b;
@@ -365,8 +368,10 @@ static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
const struct ast_exten *ac = ah_a;
const struct ast_exten *bc = ah_b;
int x = strcmp(ac->exten, bc->exten);
- if (x) /* if exten names are diff, then return */
+ if (x) { /* if exten names are diff, then return */
return x;
+ }
+
/* but if they are the same, do the cidmatch values match? */
if (ac->matchcid && bc->matchcid) {
return strcmp(ac->cidmatch,bc->cidmatch);
@@ -391,7 +396,7 @@ static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
return strcmp(ac->label, bc->label);
}
-static unsigned int hashtab_hash_contexts(const void *obj)
+unsigned int ast_hashtab_hash_contexts(const void *obj)
{
const struct ast_context *ac = obj;
return ast_hashtab_hash_string(ac->name);
@@ -708,7 +713,7 @@ static struct pbx_builtin {
};
static struct ast_context *contexts;
-static struct ast_hashtab *contexts_tree = NULL;
+static struct ast_hashtab *contexts_table = NULL;
AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
@@ -726,6 +731,185 @@ static int stateid = 1;
static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
struct ast_state_cb *statecbs;
+#ifdef CONTEXT_DEBUG
+
+/* these routines are provided for doing run-time checks
+ on the extension structures, in case you are having
+ problems, this routine might help you localize where
+ the problem is occurring. It's kinda like a debug memory
+ allocator's arena checker... It'll eat up your cpu cycles!
+ but you'll see, if you call it in the right places,
+ right where your problems began...
+*/
+
+/* you can break on the check_contexts_trouble()
+routine in your debugger to stop at the moment
+there's a problem */
+void check_contexts_trouble(void);
+
+void check_contexts_trouble(void)
+{
+ int x = 1;
+ x = 2;
+}
+
+static struct ast_context *find_context_locked(const char *context);
+int check_contexts(char *, int);
+
+int check_contexts(char *file, int line )
+{
+ struct ast_hashtab_iter *t1;
+ struct ast_context *c1, *c2;
+ int found = 0;
+ struct ast_exten *e1, *e2, *e3;
+ struct ast_exten ex;
+
+ /* try to find inconsistencies */
+ /* is every context in the context table in the context list and vice-versa ? */
+
+ if (!contexts_table) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
+ usleep(500000);
+ }
+
+ t1 = ast_hashtab_start_traversal(contexts_table);
+ while( (c1 = ast_hashtab_next(t1))) {
+ for(c2=contexts;c2;c2=c2->next) {
+ if (!strcmp(c1->name, c2->name)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
+ check_contexts_trouble();
+ }
+ }
+ ast_hashtab_end_traversal(t1);
+ for(c2=contexts;c2;c2=c2->next) {
+ c1 = find_context_locked(c2->name);
+ if (!c1) {
+ ast_log(LOG_NOTICE,"Could not find the %s context in the hashtab\n", c2->name);
+ check_contexts_trouble();
+ } else
+ ast_unlock_contexts();
+ }
+
+ /* loop thru all contexts, and verify the exten structure compares to the
+ hashtab structure */
+ for(c2=contexts;c2;c2=c2->next) {
+ c1 = find_context_locked(c2->name);
+ if (c1)
+ {
+
+ ast_unlock_contexts();
+
+ /* is every entry in the root list also in the root_table? */
+ for(e1 = c1->root; e1; e1=e1->next)
+ {
+ char dummy_name[1024];
+ ex.exten = dummy_name;
+ ex.matchcid = e1->matchcid;
+ ex.cidmatch = e1->cidmatch;
+ ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
+ e2 = ast_hashtab_lookup(c1->root_table, &ex);
+ if (!e2) {
+ if (e1->matchcid) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
+ } else {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
+ }
+ check_contexts_trouble();
+ }
+ }
+
+ /* is every entry in the root_table also in the root list? */
+ if (!c2->root_table) {
+ if (c2->root) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
+ usleep(500000);
+ }
+ } else {
+ t1 = ast_hashtab_start_traversal(c2->root_table);
+ while( (e2 = ast_hashtab_next(t1)) ) {
+ for(e1=c2->root;e1;e1=e1->next) {
+ if (!strcmp(e1->exten, e2->exten)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
+ check_contexts_trouble();
+ }
+
+ }
+ ast_hashtab_end_traversal(t1);
+ }
+ }
+ /* is every priority reflected in the peer_table at the head of the list? */
+
+ /* is every entry in the root list also in the root_table? */
+ /* are the per-extension peer_tables in the right place? */
+
+ for(e1 = c2->root; e1; e1 = e1->next) {
+
+ for(e2=e1;e2;e2=e2->peer) {
+ ex.priority = e2->priority;
+ if (e2 != e1 && e2->peer_table) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+
+ if (e2 != e1 && e2->peer_label_table) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+
+ if (e2 == e1 && !e2->peer_table){
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+
+ if (e2 == e1 && !e2->peer_label_table) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+
+
+ e3 = ast_hashtab_lookup(e1->peer_table, &ex);
+ if (!e3) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+ }
+
+ if (!e1->peer_table){
+ ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
+ usleep(500000);
+ }
+
+ /* is every entry in the peer_table also in the peer list? */
+ t1 = ast_hashtab_start_traversal(e1->peer_table);
+ while( (e2 = ast_hashtab_next(t1)) ) {
+ for(e3=e1;e3;e3=e3->peer) {
+ if (e3->priority == e2->priority) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
+ check_contexts_trouble();
+ }
+ }
+ ast_hashtab_end_traversal(t1);
+ }
+ }
+ return 0;
+}
+#endif
+
/*
\note This function is special. It saves the stack so that no matter
how many times it is called, it returns to the same place */
@@ -1044,7 +1228,7 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p); \
if (!p->deleted) { \
if (action == E_FINDLABEL) { \
- if (ast_hashtab_lookup(score->exten->peer_label_tree, &pattern)) { \
+ if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
ast_debug(4, "Found label in preferred extension\n"); \
return; \
} \
@@ -1392,11 +1576,11 @@ static void create_match_char_tree(struct ast_context *con)
int biggest_bucket, resizes, numobjs, numbucks;
ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
- ast_hashtab_get_stats(con->root_tree, &biggest_bucket, &resizes, &numobjs, &numbucks);
+ ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
numobjs, numbucks, biggest_bucket, resizes);
#endif
- t1 = ast_hashtab_start_traversal(con->root_tree);
+ t1 = ast_hashtab_start_traversal(con->root_table);
while( (e1 = ast_hashtab_next(t1)) ) {
if (e1->exten)
add_exten_to_pattern_tree(con, e1, 0);
@@ -1787,12 +1971,13 @@ struct fake_context /* this struct is purely for matching in the hashtab */
{
ast_rwlock_t lock;
struct ast_exten *root;
- struct ast_hashtab *root_tree;
+ struct ast_hashtab *root_table;
struct match_char *pattern_tree;
struct ast_context *next;
struct ast_include *includes;
struct ast_ignorepat *ignorepats;
- const char *registrar;
+ const char *registrar;
+ int refcount;
AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
ast_mutex_t macrolock;
char name[256];
@@ -1804,8 +1989,8 @@ struct ast_context *ast_context_find(const char *name)
struct fake_context item;
strncpy(item.name,name,256);
ast_rdlock_contexts();
- if( contexts_tree ) {
- tmp = ast_hashtab_lookup(contexts_tree,&item);
+ if( contexts_table ) {
+ tmp = ast_hashtab_lookup(contexts_table,&item);
} else {
while ( (tmp = ast_walk_contexts(tmp)) ) {
if (!name || !strcasecmp(name, tmp->name))
@@ -1874,7 +2059,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
else { /* look in contexts */
struct fake_context item;
strncpy(item.name,context,256);
- tmp = ast_hashtab_lookup(contexts_tree,&item);
+ tmp = ast_hashtab_lookup(contexts_table,&item);
#ifdef NOTNOW
tmp = NULL;
while ((tmp = ast_walk_contexts(tmp)) ) {
@@ -1896,7 +2081,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
score.total_specificity = 0;
score.exten = 0;
score.total_length = 0;
- if (!tmp->pattern_tree && tmp->root_tree)
+ if (!tmp->pattern_tree && tmp->root_table)
{
create_match_char_tree(tmp);
#ifdef NEED_DEBUG
@@ -1966,9 +2151,9 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
if (action == E_FINDLABEL && label ) {
if (q->status < STATUS_NO_LABEL)
q->status = STATUS_NO_LABEL;
- e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+ e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
} else {
- e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+ e = ast_hashtab_lookup(eroot->peer_table, &pattern);
}
if (e) { /* found a valid match */
q->status = STATUS_SUCCESS;
@@ -2002,9 +2187,9 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
if (action == E_FINDLABEL && label ) {
if (q->status < STATUS_NO_LABEL)
q->status = STATUS_NO_LABEL;
- e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+ e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
} else {
- e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+ e = ast_hashtab_lookup(eroot->peer_table, &pattern);
}
#ifdef NOTNOW
while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
@@ -2686,7 +2871,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
vare++;
}
if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
+ ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
len = vare - vars - 1;
/* Skip totally over variable string */
@@ -2773,7 +2958,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
vare++;
}
if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
+ ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
len = vare - vars - 1;
/* Skip totally over expression */
@@ -3689,14 +3874,14 @@ static int increase_call_count(const struct ast_channel *c)
ast_mutex_lock(&maxcalllock);
if (option_maxcalls) {
if (countcalls >= option_maxcalls) {
- ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
+ ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
failed = -1;
}
}
if (option_maxload) {
getloadavg(&curloadavg, 1);
if (curloadavg >= option_maxload) {
- ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
+ ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
failed = -1;
}
}
@@ -3737,10 +3922,10 @@ static void destroy_exten(struct ast_exten *e)
if (e->priority == PRIORITY_HINT)
ast_remove_hint(e);
- if (e->peer_tree)
- ast_hashtab_destroy(e->peer_tree,0);
- if (e->peer_label_tree)
- ast_hashtab_destroy(e->peer_label_tree, 0);
+ if (e->peer_table)
+ ast_hashtab_destroy(e->peer_table,0);
+ if (e->peer_label_table)
+ ast_hashtab_destroy(e->peer_label_table, 0);
if (e->datad)
e->datad(e->data);
ast_free(e);
@@ -3837,8 +4022,7 @@ static struct ast_context *find_context_locked(const char *context)
ast_copy_string(item.name, context, sizeof(item.name));
ast_rdlock_contexts();
-
- c = ast_hashtab_lookup(contexts_tree,&item);
+ c = ast_hashtab_lookup(contexts_table,&item);
#ifdef NOTNOW
@@ -4017,18 +4201,20 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
#ifdef NEED_DEBUG
ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcid ? "/" : "", matchcid ? callerid : "", registrar);
#endif
+#ifdef CONTEXT_DEBUG
+ check_contexts(__FILE__, __LINE__);
+#endif
/* find this particular extension */
ex.exten = dummy_name;
- ex.matchcid = matchcid;
+ ex.matchcid = matchcid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
ex.cidmatch = callerid;
ast_copy_string(dummy_name, extension, sizeof(dummy_name));
- exten = ast_hashtab_lookup(con->root_tree, &ex);
+ exten = ast_hashtab_lookup(con->root_table, &ex);
if (exten) {
- if (priority == 0)
- {
- exten2 = ast_hashtab_remove_this_object(con->root_tree, exten);
+ if (priority == 0) {
+ exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
if (!exten2)
- ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_tree\n", extension, con->name);
+ ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
@@ -4042,24 +4228,28 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
}
} else {
ex.priority = priority;
- exten2 = ast_hashtab_lookup(exten->peer_tree, &ex);
+ exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
if (exten2) {
if (exten2->label) { /* if this exten has a label, remove that, too */
- exten3 = ast_hashtab_remove_this_object(exten->peer_label_tree,exten2);
+ exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_tree of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
+ ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
}
- exten3 = ast_hashtab_remove_this_object(exten->peer_tree, exten2);
+ exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_tree of context %s, extension %s!\n", priority, con->name, exten2->exten);
- if (ast_hashtab_size(exten->peer_tree) == 0) {
+ ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
+ if (exten2 == exten && exten2->peer) {
+ exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
+ ast_hashtab_insert_immediate(con->root_table, exten2->peer);
+ }
+ if (ast_hashtab_size(exten->peer_table) == 0) {
/* well, if the last priority of an exten is to be removed,
then, the extension is removed, too! */
- exten3 = ast_hashtab_remove_this_object(con->root_tree, exten);
+ exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_tree (%s) (priority %d)\n", exten->exten, con->name, priority);
+ ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
@@ -4075,7 +4265,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
}
} else {
/* hmmm? this exten is not in this pattern tree? */
- ast_log(LOG_WARNING,"Cannot find extension %s in root_tree in context %s\n",
+ ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
extension, con->name);
}
#ifdef NEED_DEBUG
@@ -4088,7 +4278,8 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
/* scan the extension list to find first matching extension-registrar */
for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
if (!strcmp(exten->exten, extension) &&
- (!registrar || !strcmp(exten->registrar, registrar)))
+ (!registrar || !strcmp(exten->registrar, registrar)) &&
+ (!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
break;
}
if (!exten) {
@@ -4100,7 +4291,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
/* scan the priority list to remove extension with exten->priority == priority */
for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
- peer && !strcmp(peer->exten, extension);
+ peer && !strcmp(peer->exten, extension) && (!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
if ((priority == 0 || peer->priority == priority) &&
(!callerid || !matchcid || (matchcid && !strcmp(peer->cidmatch, callerid))) &&
@@ -4114,7 +4305,14 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
* The next node is either the next priority or the next extension
*/
struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
-
+ if (peer->peer) {
+ /* move the peer_table and peer_label_table down to the next peer, if
+ it is there */
+ peer->peer->peer_table = peer->peer_table;
+ peer->peer->peer_label_table = peer->peer_label_table;
+ peer->peer_table = NULL;
+ peer->peer_label_table = NULL;
+ }
if (!prev_exten) { /* change the root... */
con->root = next_node;
} else {
@@ -4133,6 +4331,9 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
previous_peer = peer;
}
}
+#ifdef CONTEXT_DEBUG
+ check_contexts(__FILE__, __LINE__);
+#endif
if (!already_locked)
ast_unlock_context(con);
return found ? 0 : -1;
@@ -4153,7 +4354,7 @@ int ast_context_lockmacro(const char *context)
ast_rdlock_contexts();
strncpy(item.name,context,256);
- c = ast_hashtab_lookup(contexts_tree,&item);
+ c = ast_hashtab_lookup(contexts_table,&item);
if (c)
ret = 0;
@@ -4191,7 +4392,7 @@ int ast_context_unlockmacro(const char *context)
ast_rdlock_contexts();
strncpy(item.name, context, 256);
- c = ast_hashtab_lookup(contexts_tree,&item);
+ c = ast_hashtab_lookup(contexts_table,&item);
if (c)
ret = 0;
#ifdef NOTNOW
@@ -4785,7 +4986,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
if (exten) {
/* Check all includes for the requested extension */
if (includecount >= AST_PBX_MAX_STACK) {
- ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
+ ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
} else {
int dupe = 0;
int x;
@@ -5334,42 +5535,37 @@ int ast_unregister_application(const char *app)
return tmp ? 0 : -1;
}
-static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
{
struct ast_context *tmp, **local_contexts;
struct fake_context search;
int length = sizeof(struct ast_context) + strlen(name) + 1;
- if (!contexts_tree) {
- contexts_tree = ast_hashtab_create(17,
- hashtab_compare_contexts,
+ if (!contexts_table) {
+ contexts_table = ast_hashtab_create(17,
+ ast_hashtab_compare_contexts,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
- hashtab_hash_contexts,
+ ast_hashtab_hash_contexts,
0);
}
+ strncpy(search.name,name,sizeof(search.name));
if (!extcontexts) {
ast_rdlock_contexts();
local_contexts = &contexts;
- strncpy(search.name,name,sizeof(search.name));
- tmp = ast_hashtab_lookup(contexts_tree, &search);
- if (!existsokay && tmp) {
- ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
- }
+ tmp = ast_hashtab_lookup(contexts_table, &search);
ast_unlock_contexts();
- if (tmp)
+ if (tmp) {
+ tmp->refcount++;
return tmp;
+ }
} else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
local_contexts = extcontexts;
- for (tmp = *local_contexts; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, name)) {
- if (!existsokay) {
- ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
- tmp = NULL;
- }
- return tmp;
- }
+ tmp = ast_hashtab_lookup(exttable, &search);
+ if (tmp) {
+ tmp->refcount++;
+ return tmp;
}
}
@@ -5378,19 +5574,26 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
ast_mutex_init(&tmp->macrolock);
strcpy(tmp->name, name);
tmp->root = NULL;
- tmp->root_tree = NULL;
- tmp->registrar = registrar;
+ tmp->root_table = NULL;
+ tmp->registrar = ast_strdup(registrar);
tmp->includes = NULL;
tmp->ignorepats = NULL;
+ tmp->refcount = 1;
+ } else {
+ ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
+ return NULL;
}
+
if (!extcontexts) {
ast_wrlock_contexts();
tmp->next = *local_contexts;
*local_contexts = tmp;
- ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
+ ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
ast_unlock_contexts();
} else {
tmp->next = *local_contexts;
+ if (exttable)
+ ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
*local_contexts = tmp;
}
ast_debug(1, "Registered context '%s'\n", tmp->name);
@@ -5398,16 +5601,7 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
return tmp;
}
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
- return __ast_context_create(extcontexts, name, registrar, 0);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
- return __ast_context_create(extcontexts, name, registrar, 1);
-}
-void __ast_context_destroy(struct ast_context *con, const char *registrar);
+void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
struct store_hint {
char *context;
@@ -5420,17 +5614,125 @@ struct store_hint {
AST_LIST_HEAD(store_hints, store_hint);
+static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
+{
+ struct ast_include *i;
+ struct ast_ignorepat *ip;
+ struct ast_sw *sw;
+
+ /* copy in the includes, switches, and ignorepats */
+ /* walk through includes */
+ for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
+ if (strcmp(ast_get_include_registrar(i), registrar) == 0)
+ continue; /* not mine */
+ ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
+ }
+
+ /* walk through switches */
+ for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
+ if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
+ continue; /* not mine */
+ ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
+ }
+
+ /* walk thru ignorepats ... */
+ for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
+ if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
+ continue; /* not mine */
+ ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
+ }
+}
+
+
+/* the purpose of this routine is to duplicate a context, with all its substructure,
+ except for any extens that have a matching registrar */
+static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
+{
+ struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
+ struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
+ struct ast_hashtab_iter *exten_iter;
+ struct ast_hashtab_iter *prio_iter;
+ int insert_count = 0;
+
+ /* We'll traverse all the extensions/prios, and see which are not registrar'd with
+ the current registrar, and copy them to the new context. If the new context does not
+ exist, we'll create it "on demand". If no items are in this context to copy, then we'll
+ only create the empty matching context if the old one meets the criteria */
+ if (context->root_table) {
+ exten_iter = ast_hashtab_start_traversal(context->root_table);
+ while ((exten_item=ast_hashtab_next(exten_iter))) {
+ if (new) {
+ new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
+ } else {
+ new_exten_item = NULL;
+ }
+ prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+ while ((prio_item=ast_hashtab_next(prio_iter))) {
+ int res1;
+
+ if (new_exten_item) {
+ new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
+ } else {
+ new_prio_item = NULL;
+ }
+ if (strcmp(prio_item->registrar,registrar) == 0) {
+ continue;
+ }
+ /* make sure the new context exists, so we have somewhere to stick this exten/prio */
+ if (!new) {
+ new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
+
+ /* copy in the includes, switches, and ignorepats */
+ context_merge_incls_swits_igps_other_registrars(new, context, registrar);
+ }
+ if (!new) {
+ ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
+ return; /* no sense continuing. */
+ }
+ /* we will not replace existing entries in the new context with stuff from the old context.
+ but, if this is because of some sort of registrar conflict, we ought to say something... */
+ res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
+ prio_item->cidmatch, prio_item->app, prio_item->data, prio_item->datad, prio_item->registrar);
+ if (!res1 && new_exten_item && new_prio_item){
+ ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
+ context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
+ } else {
+ prio_item->data = NULL; /* we pass the priority data from the old to the new */
+ insert_count++;
+ }
+ }
+ ast_hashtab_end_traversal(prio_iter);
+ }
+ ast_hashtab_end_traversal(exten_iter);
+ }
+
+ if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
+ (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
+
+ /* we could have given it the registrar of the other module who incremented the refcount,
+ but that's not available, so we give it the registrar we know about */
+ new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
+
+ /* copy in the includes, switches, and ignorepats */
+ context_merge_incls_swits_igps_other_registrars(new, context, registrar);
+ }
+}
+
+
/* XXX this does not check that multiple contexts are merged */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
{
- struct ast_context *tmp, *lasttmp = NULL;
+ double ft;
+ struct ast_context *tmp, *oldcontextslist;
+ struct ast_hashtab *oldtable;
struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
struct store_hint *this;
struct ast_hint *hint;
struct ast_exten *exten;
int length;
struct ast_state_cb *thiscb, *prevcb;
-
+ struct ast_hashtab_iter *iter;
+
/* it is very important that this function hold the hint list lock _and_ the conlock
during its operation; not only do we need to ensure that the list of contexts
and extensions does not change, but also that no hint callbacks (watchers) are
@@ -5439,8 +5741,29 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
in addition, the locks _must_ be taken in this order, because there are already
other code paths that use this order
*/
+
+ struct timeval begintime, writelocktime, endlocktime, enddeltime;
+ int wrlock_ver;
+
+ begintime = ast_tvnow();
+ ast_rdlock_contexts();
+ iter = ast_hashtab_start_traversal(contexts_table);
+ while ((tmp=ast_hashtab_next(iter))) {
+ context_merge(extcontexts, exttable, tmp, registrar);
+ }
+ ast_hashtab_end_traversal(iter);
+ wrlock_ver = ast_wrlock_contexts_version();
+
+ ast_unlock_contexts(); /* this feels real retarded, but you must do
+ what you must do If this isn't done, the following
+ wrlock is a guraranteed deadlock */
ast_wrlock_contexts();
+ if (ast_wrlock_contexts_version() > wrlock_ver+1) {
+ ast_log(LOG_WARNING,"Something changed the contexts in the middle of merging contexts!\n");
+ }
+
AST_RWLIST_WRLOCK(&hints);
+ writelocktime = ast_tvnow();
/* preserve all watchers for hints associated with this registrar */
AST_RWLIST_TRAVERSE(&hints, hint, list) {
@@ -5459,36 +5782,14 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
}
}
- tmp = *extcontexts;
- if (registrar) {
- /* XXX remove previous contexts from same registrar */
- ast_debug(1, "must remove any reg %s\n", registrar);
- __ast_context_destroy(NULL,registrar);
- while (tmp) {
- lasttmp = tmp;
- tmp = tmp->next;
- }
- } else {
- /* XXX remove contexts with the same name */
- while (tmp) {
- ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
- __ast_context_destroy(tmp,tmp->registrar);
- lasttmp = tmp;
- tmp = tmp->next;
- }
- }
- tmp = *extcontexts;
- while (tmp) {
- ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
- tmp = tmp->next;
- }
- if (lasttmp) {
- lasttmp->next = contexts;
- contexts = *extcontexts;
- *extcontexts = NULL;
- } else
- ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
+ /* save the old table and list */
+ oldtable = contexts_table;
+ oldcontextslist = contexts;
+ /* move in the new table and list */
+ contexts_table = exttable;
+ contexts = *extcontexts;
+
/* restore the watchers for hints that can be found; notify those that
cannot be restored
*/
@@ -5523,7 +5824,36 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
AST_RWLIST_UNLOCK(&hints);
ast_unlock_contexts();
+ endlocktime = ast_tvnow();
+
+ /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
+ is now freely using the new stuff instead */
+
+ ast_hashtab_destroy(oldtable, NULL);
+
+ for (tmp = oldcontextslist; tmp; ) {
+ struct ast_context *next; /* next starting point */
+ next = tmp->next;
+ __ast_internal_context_destroy(tmp);
+ tmp = next;
+ }
+ enddeltime = ast_tvnow();
+
+ ft = ast_tvdiff_us(writelocktime, begintime);
+ ft /= 1000000.0;
+ ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
+
+ ft = ast_tvdiff_us(endlocktime, writelocktime);
+ ft /= 1000000.0;
+ ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
+
+ ft = ast_tvdiff_us(enddeltime, endlocktime);
+ ft /= 1000000.0;
+ ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
+ ft = ast_tvdiff_us(enddeltime, begintime);
+ ft /= 1000000.0;
+ ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
return;
}
@@ -6054,6 +6384,7 @@ int ast_add_extension(const char *context, int replace, const char *extension,
application, data, datad, registrar);
ast_unlock_contexts();
}
+
return ret;
}
@@ -6180,9 +6511,11 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
break;
}
if (!e) { /* go at the end, and ep is surely set because the list is not empty */
- ast_hashtab_insert_safe(eh->peer_tree, tmp);
- if (tmp->label)
- ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
+ ast_hashtab_insert_safe(eh->peer_table, tmp);
+
+ if (tmp->label) {
+ ast_hashtab_insert_safe(eh->peer_label_table, tmp);
+ }
ep->peer = tmp;
return 0; /* success */
}
@@ -6202,25 +6535,33 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
tmp->next = e->next; /* not meaningful if we are not first in the peer list */
tmp->peer = e->peer; /* always meaningful */
if (ep) { /* We're in the peer list, just insert ourselves */
- ast_hashtab_remove_object_via_lookup(eh->peer_tree,e);
- if (e->label)
- ast_hashtab_remove_object_via_lookup(eh->peer_label_tree,e);
- ast_hashtab_insert_safe(eh->peer_tree,tmp);
- if (tmp->label)
- ast_hashtab_insert_safe(eh->peer_label_tree,tmp);
+ ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
+
+ if (e->label) {
+ ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
+ }
+
+ ast_hashtab_insert_safe(eh->peer_table,tmp);
+ if (tmp->label) {
+ ast_hashtab_insert_safe(eh->peer_label_table,tmp);
+ }
+
ep->peer = tmp;
} else if (el) { /* We're the first extension. Take over e's functions */
struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
- tmp->peer_tree = e->peer_tree;
- tmp->peer_label_tree = e->peer_label_tree;
- ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
- ast_hashtab_insert_safe(tmp->peer_tree,tmp);
- if (e->label)
- ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
- if (tmp->label)
- ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
- ast_hashtab_remove_object_via_lookup(con->root_tree, e);
- ast_hashtab_insert_safe(con->root_tree, tmp);
+ tmp->peer_table = e->peer_table;
+ tmp->peer_label_table = e->peer_label_table;
+ ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
+ ast_hashtab_insert_safe(tmp->peer_table,tmp);
+ if (e->label) {
+ ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
+ }
+ if (tmp->label) {
+ ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+ }
+
+ ast_hashtab_remove_object_via_lookup(con->root_table, e);
+ ast_hashtab_insert_safe(con->root_table, tmp);
el->next = tmp;
/* The pattern trie points to this exten; replace the pointer,
and all will be well */
@@ -6233,18 +6574,21 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
}
} else { /* We're the very first extension. */
struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
- ast_hashtab_remove_object_via_lookup(con->root_tree,e);
- ast_hashtab_insert_safe(con->root_tree,tmp);
- tmp->peer_tree = e->peer_tree;
- tmp->peer_label_tree = e->peer_label_tree;
- ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
- ast_hashtab_insert_safe(tmp->peer_tree,tmp);
- if (e->label)
- ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
- if (tmp->label)
- ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
- ast_hashtab_remove_object_via_lookup(con->root_tree, e);
- ast_hashtab_insert_safe(con->root_tree, tmp);
+ ast_hashtab_remove_object_via_lookup(con->root_table, e);
+ ast_hashtab_insert_safe(con->root_table, tmp);
+ tmp->peer_table = e->peer_table;
+ tmp->peer_label_table = e->peer_label_table;
+ ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
+ ast_hashtab_insert_safe(tmp->peer_table, tmp);
+ if (e->label) {
+ ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
+ }
+ if (tmp->label) {
+ ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+ }
+
+ ast_hashtab_remove_object_via_lookup(con->root_table, e);
+ ast_hashtab_insert_safe(con->root_table, tmp);
con->root = tmp;
/* The pattern trie points to this exten; replace the pointer,
and all will be well */
@@ -6266,21 +6610,22 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
tmp->peer = e;
tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
if (ep) { /* Easy enough, we're just in the peer list */
- if (tmp->label)
- ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
- ast_hashtab_insert_safe(eh->peer_tree, tmp);
+ if (tmp->label) {
+ ast_hashtab_insert_safe(eh->peer_label_table, tmp);
+ }
+ ast_hashtab_insert_safe(eh->peer_table, tmp);
ep->peer = tmp;
} else { /* we are the first in some peer list, so link in the ext list */
- tmp->peer_tree = e->peer_tree;
- tmp->peer_label_tree = e ->peer_label_tree;
- e->peer_tree = 0;
- e->peer_label_tree = 0;
- ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+ tmp->peer_table = e->peer_table;
+ tmp->peer_label_table = e->peer_label_table;
+ e->peer_table = 0;
+ e->peer_label_table = 0;
+ ast_hashtab_insert_safe(tmp->peer_table, tmp);
if (tmp->label) {
- ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+ ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
}
- ast_hashtab_remove_object_via_lookup(con->root_tree,e);
- ast_hashtab_insert_safe(con->root_tree,tmp);
+ ast_hashtab_remove_object_via_lookup(con->root_table, e);
+ ast_hashtab_insert_safe(con->root_table, tmp);
if (el)
el->next = tmp; /* in the middle... */
else
@@ -6362,6 +6707,9 @@ int ast_add_extension2(struct ast_context *con,
if (!(tmp = ast_calloc(1, length)))
return -1;
+ if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
+ label = 0;
+
/* use p as dst in assignments, as the fields are const char * */
p = tmp->stuff;
if (label) {
@@ -6373,7 +6721,7 @@ int ast_add_extension2(struct ast_context *con,
p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
tmp->priority = priority;
tmp->cidmatch = p; /* but use p for assignments below */
- if (callerid) {
+ if (!ast_strlen_zero(callerid)) {
p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
tmp->matchcid = 1;
} else {
@@ -6395,11 +6743,11 @@ int ast_add_extension2(struct ast_context *con,
dummy_exten.exten = dummy_name;
dummy_exten.matchcid = 0;
dummy_exten.cidmatch = 0;
- tmp2 = ast_hashtab_lookup(con->root_tree,&dummy_exten);
+ tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
if (!tmp2) {
/* hmmm, not in the trie; */
add_exten_to_pattern_tree(con, tmp, 0);
- ast_hashtab_insert_safe(con->root_tree, tmp); /* for the sake of completeness */
+ ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
}
}
res = 0; /* some compilers will think it is uninitialized otherwise */
@@ -6433,48 +6781,50 @@ int ast_add_extension2(struct ast_context *con,
tmp->next = e;
if (el) { /* there is another exten already in this context */
el->next = tmp;
- tmp->peer_tree = ast_hashtab_create(13,
+ tmp->peer_table = ast_hashtab_create(13,
hashtab_compare_exten_numbers,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_priority,
0);
- tmp->peer_label_tree = ast_hashtab_create(7,
+ tmp->peer_label_table = ast_hashtab_create(7,
hashtab_compare_exten_labels,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_labels,
0);
- if (label)
- ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
- ast_hashtab_insert_safe(tmp->peer_tree, tmp);
-
+ if (label) {
+ ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+ }
+ ast_hashtab_insert_safe(tmp->peer_table, tmp);
} else { /* this is the first exten in this context */
- if (!con->root_tree)
- con->root_tree = ast_hashtab_create(27,
+ if (!con->root_table)
+ con->root_table = ast_hashtab_create(27,
hashtab_compare_extens,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_extens,
0);
con->root = tmp;
- con->root->peer_tree = ast_hashtab_create(13,
+ con->root->peer_table = ast_hashtab_create(13,
hashtab_compare_exten_numbers,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_priority,
0);
- con->root->peer_label_tree = ast_hashtab_create(7,
+ con->root->peer_label_table = ast_hashtab_create(7,
hashtab_compare_exten_labels,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_labels,
0);
- if (label)
- ast_hashtab_insert_safe(con->root->peer_label_tree,tmp);
- ast_hashtab_insert_safe(con->root->peer_tree, tmp);
+ if (label) {
+ ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
+ }
+ ast_hashtab_insert_safe(con->root->peer_table, tmp);
+
}
- ast_hashtab_insert_safe(con->root_tree, tmp);
+ ast_hashtab_insert_safe(con->root_table, tmp);
ast_unlock_context(con);
if (tmp->priority == PRIORITY_HINT)
ast_add_hint(tmp);
@@ -6490,7 +6840,7 @@ int ast_add_extension2(struct ast_context *con,
}
if (tmp->matchcid) {
- ast_verb(3, "Added extension '%s' priority %d (CID match '%s')to %s\n",
+ ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
tmp->exten, tmp->priority, tmp->cidmatch, con->name);
} else {
ast_verb(3, "Added extension '%s' priority %d to %s\n",
@@ -6882,68 +7232,191 @@ outgoing_app_cleanup:
return res;
}
-void __ast_context_destroy(struct ast_context *con, const char *registrar)
+/* this is the guts of destroying a context --
+ freeing up the structure, traversing and destroying the
+ extensions, switches, ignorepats, includes, etc. etc. */
+
+static void __ast_internal_context_destroy( struct ast_context *con)
{
- struct ast_context *tmp, *tmpl=NULL;
struct ast_include *tmpi;
struct ast_sw *sw;
struct ast_exten *e, *el, *en;
struct ast_ignorepat *ipi;
+ struct ast_context *tmp = con;
- for (tmp = contexts; tmp; ) {
- struct ast_context *next; /* next starting point */
- for (; tmp; tmpl = tmp, tmp = tmp->next) {
- ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
- if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
- (!con || !strcasecmp(tmp->name, con->name)) )
- break; /* found it */
+ for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
+ struct ast_include *tmpil = tmpi;
+ tmpi = tmpi->next;
+ ast_free(tmpil);
+ }
+ for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
+ struct ast_ignorepat *ipl = ipi;
+ ipi = ipi->next;
+ ast_free(ipl);
+ }
+ if (tmp->registrar)
+ ast_free(tmp->registrar);
+
+ /* destroy the hash tabs */
+ if (tmp->root_table) {
+ ast_hashtab_destroy(tmp->root_table, 0);
+ }
+ /* and destroy the pattern tree */
+ if (tmp->pattern_tree)
+ destroy_pattern_tree(tmp->pattern_tree);
+
+ while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
+ ast_free(sw);
+ for (e = tmp->root; e;) {
+ for (en = e->peer; en;) {
+ el = en;
+ en = en->peer;
+ destroy_exten(el);
}
+ el = e;
+ e = e->next;
+ destroy_exten(el);
+ }
+ tmp->root = NULL;
+ ast_rwlock_destroy(&tmp->lock);
+ ast_free(tmp);
+}
+
+
+void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
+{
+ struct ast_context *tmp, *tmpl=NULL;
+ struct ast_exten *exten_item, *prio_item;
+
+ for (tmp = list; tmp; ) {
+ struct ast_context *next = NULL; /* next starting point */
+ /* The following code used to skip forward to the next
+ context with matching registrar, but this didn't
+ make sense; individual priorities registrar'd to
+ the matching registrar could occur in any context! */
+ ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
+ if (con) {
+ for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
+ ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
+ if ( !strcasecmp(tmp->name, con->name) ) {
+ break; /* found it */
+ }
+ }
+ }
+
if (!tmp) /* not found, we are done */
break;
ast_wrlock_context(tmp);
- ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
- ast_hashtab_remove_this_object(contexts_tree,tmp);
-
- next = tmp->next;
- if (tmpl)
- tmpl->next = next;
- else
- contexts = next;
- /* Okay, now we're safe to let it go -- in a sense, we were
- ready to let it go as soon as we locked it. */
- ast_unlock_context(tmp);
- for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
- struct ast_include *tmpil = tmpi;
- tmpi = tmpi->next;
- ast_free(tmpil);
- }
- for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
- struct ast_ignorepat *ipl = ipi;
- ipi = ipi->next;
- ast_free(ipl);
- }
- /* destroy the hash tabs */
- if (tmp->root_tree) {
- ast_hashtab_destroy(tmp->root_tree, 0);
- }
- /* and destroy the pattern tree */
- if (tmp->pattern_tree)
- destroy_pattern_tree(tmp->pattern_tree);
-
- while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
- ast_free(sw);
- for (e = tmp->root; e;) {
- for (en = e->peer; en;) {
- el = en;
- en = en->peer;
- destroy_exten(el);
+
+ if (registrar) {
+ /* then search thru and remove any extens that match registrar. */
+ struct ast_hashtab_iter *exten_iter;
+ struct ast_hashtab_iter *prio_iter;
+ struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
+ struct ast_include *i, *pi = NULL, *ni = NULL;
+ struct ast_sw *sw = NULL;
+
+ /* remove any ignorepats whose registrar matches */
+ for (ip = tmp->ignorepats; ip; ip = ipn) {
+ ipn = ip->next;
+ if (!strcmp(ip->registrar, registrar)) {
+ if (ipl) {
+ ipl->next = ip->next;
+ ast_free(ip);
+ continue; /* don't change ipl */
+ } else {
+ tmp->ignorepats = ip->next;
+ ast_free(ip);
+ continue; /* don't change ipl */
+ }
+ }
+ ipl = ip;
+ }
+ /* remove any includes whose registrar matches */
+ for (i = tmp->includes; i; i = ni) {
+ ni = i->next;
+ if (strcmp(i->registrar, registrar) == 0) {
+ /* remove from list */
+ if (pi) {
+ pi->next = i->next;
+ /* free include */
+ ast_free(i);
+ continue; /* don't change pi */
+ } else {
+ tmp->includes = i->next;
+ /* free include */
+ ast_free(i);
+ continue; /* don't change pi */
+ }
+ }
+ pi = i;
+ }
+ /* remove any switches whose registrar matches */
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
+ if (strcmp(sw->registrar,registrar) == 0) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(sw);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+
+ if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
+ exten_iter = ast_hashtab_start_traversal(tmp->root_table);
+ while ((exten_item=ast_hashtab_next(exten_iter))) {
+ prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+ while ((prio_item=ast_hashtab_next(prio_iter))) {
+ if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
+ continue;
+ }
+ ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
+ tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
+ /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
+ ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
+ }
+ ast_hashtab_end_traversal(prio_iter);
+ }
+ ast_hashtab_end_traversal(exten_iter);
}
- el = e;
- e = e->next;
- destroy_exten(el);
+
+ /* delete the context if it's registrar matches, is empty, has refcount of 1, */
+ /* it's not empty, if it has includes, ignorepats, or switches that are registered from
+ another registrar. It's not empty if there are any extensions */
+ if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
+ ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+ ast_hashtab_remove_this_object(contexttab, tmp);
+
+ next = tmp->next;
+ if (tmpl)
+ tmpl->next = next;
+ else
+ contexts = next;
+ /* Okay, now we're safe to let it go -- in a sense, we were
+ ready to let it go as soon as we locked it. */
+ ast_unlock_context(tmp);
+ __ast_internal_context_destroy(tmp);
+ } else {
+ ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
+ tmp->refcount, tmp->root);
+ ast_unlock_context(tmp);
+ next = tmp->next;
+ tmpl = tmp;
+ }
+ } else if (con) {
+ ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
+ ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+ ast_hashtab_remove_this_object(contexttab, tmp);
+
+ next = tmp->next;
+ if (tmpl)
+ tmpl->next = next;
+ else
+ contexts = next;
+ /* Okay, now we're safe to let it go -- in a sense, we were
+ ready to let it go as soon as we locked it. */
+ ast_unlock_context(tmp);
+ __ast_internal_context_destroy(tmp);
}
- ast_rwlock_destroy(&tmp->lock);
- ast_free(tmp);
+
/* if we have a specific match, we are done, otherwise continue */
tmp = con ? NULL : next;
}
@@ -6952,7 +7425,7 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
void ast_context_destroy(struct ast_context *con, const char *registrar)
{
ast_wrlock_contexts();
- __ast_context_destroy(con,registrar);
+ __ast_context_destroy(contexts, contexts_table, con,registrar);
ast_unlock_contexts();
}
@@ -7106,7 +7579,7 @@ static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
return -1;
}
- ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
+ ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
}
if (!chan->hangupcause) {
@@ -7786,13 +8259,22 @@ int load_pbx(void)
return 0;
}
+static int conlock_wrlock_version = 0;
+
+int ast_wrlock_contexts_version(void)
+{
+ return conlock_wrlock_version;
+}
/*
* Lock context list functions ...
*/
int ast_wrlock_contexts()
{
- return ast_rwlock_wrlock(&conlock);
+ int res = ast_rwlock_wrlock(&conlock);
+ if (!res)
+ ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
+ return res;
}
int ast_rdlock_contexts()
@@ -7914,6 +8396,11 @@ const char *ast_get_switch_data(struct ast_sw *sw)
return sw ? sw->data : NULL;
}
+int ast_get_switch_eval(struct ast_sw *sw)
+{
+ return sw->eval;
+}
+
const char *ast_get_switch_registrar(struct ast_sw *sw)
{
return sw ? sw->registrar : NULL;
diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c
index 6226ca4a1..22ec24105 100644
--- a/pbx/pbx_ael.c
+++ b/pbx/pbx_ael.c
@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
+#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
#include "asterisk/pval.h"
#ifdef AAL_ARGCHECK
@@ -87,7 +88,7 @@ struct ael_extension *new_exten(void);
void destroy_extensions(struct ael_extension *exten);
void set_priorities(struct ael_extension *exten);
void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
void destroy_pval(pval *item);
void destroy_pval_item(pval *item);
int is_float(char *arg );
@@ -107,6 +108,8 @@ static int pbx_load_module(void)
int errs=0, sem_err=0, sem_warn=0, sem_note=0;
char *rfilename;
struct ast_context *local_contexts=NULL, *con;
+ struct ast_hashtab *local_table=NULL;
+
struct pval *parse_tree;
ast_log(LOG_NOTICE, "Starting AEL load process.\n");
@@ -126,10 +129,13 @@ static int pbx_load_module(void)
ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
if (errs == 0 && sem_err == 0) {
ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
- ast_compile_ael2(&local_contexts, parse_tree);
+ local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
+ ast_compile_ael2(&local_contexts, local_table, parse_tree);
ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
- ast_merge_contexts_and_delete(&local_contexts, registrar);
+ ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
+ local_table = NULL; /* it's the dialplan global now */
+ local_contexts = NULL;
ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
ast_context_verify_includes(con);
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index a4d8c38cb..cbed1e020 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -51,7 +51,7 @@ static int extenpatternmatchnew_config = 0;
AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
static struct ast_context *local_contexts = NULL;
-
+static struct ast_hashtab *local_table = NULL;
/*
* Prototypes for our completion functions
*/
@@ -1402,7 +1402,6 @@ static int pbx_load_config(const char *config_file)
const char *aft;
const char *newpm;
struct ast_flags config_flags = { 0 };
-
cfg = ast_config_load(config_file, config_flags);
if (!cfg)
return 0;
@@ -1430,7 +1429,7 @@ static int pbx_load_config(const char *config_file)
/* All categories but "general" or "globals" are considered contexts */
if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
continue;
- con=ast_context_find_or_create(&local_contexts,cxt, registrar);
+ con=ast_context_find_or_create(&local_contexts, local_table, cxt, registrar);
if (con == NULL)
continue;
@@ -1642,7 +1641,7 @@ static void pbx_load_users(void)
/* Only create a context here when it is really needed. Otherwise default empty context
created by pbx_config may conflict with the one explicitly created by pbx_ael */
if (!con)
- con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
+ con = ast_context_find_or_create(&local_contexts, local_table, userscontext, registrar);
if (!con) {
ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
@@ -1667,12 +1666,17 @@ static int pbx_load_module(void)
{
struct ast_context *con;
- if(!pbx_load_config(config))
+ if (!local_table)
+ local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
+
+ if (!pbx_load_config(config))
return AST_MODULE_LOAD_DECLINE;
pbx_load_users();
- ast_merge_contexts_and_delete(&local_contexts, registrar);
+ ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
+ local_table = NULL; /* the local table has been moved into the global one. */
+ local_contexts = NULL;
for (con = NULL; (con = ast_walk_contexts(con));)
ast_context_verify_includes(con);
diff --git a/res/ael/ael.flex b/res/ael/ael.flex
index 35ca126aa..0e92db91e 100644
--- a/res/ael/ael.flex
+++ b/res/ael/ael.flex
@@ -60,6 +60,7 @@
%option bison-locations
%{
+#include <asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
@@ -70,9 +71,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define GLOB_ABORTED GLOB_ABEND
#endif
# include <glob.h>
-
#include "asterisk/logger.h"
#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "ael/ael.tab.h"
#include "asterisk/ael_structs.h"
diff --git a/res/ael/ael.tab.c b/res/ael/ael.tab.c
index aa1ec0fad..16c62ba71 100644
--- a/res/ael/ael.tab.c
+++ b/res/ael/ael.tab.c
@@ -188,6 +188,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include "asterisk/logger.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
pval * linku1(pval *head, pval *tail);
@@ -227,14 +229,14 @@ static char *ael_token_subst(const char *mess);
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-#line 54 "ael.y"
+#line 56 "ael.y"
{
int intval; /* integer value, typically flags */
char *str; /* strings */
struct pval *pval; /* full objects */
}
/* Line 198 of yacc.c. */
-#line 238 "ael.tab.c"
+#line 240 "ael.tab.c"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
@@ -256,7 +258,7 @@ typedef struct YYLTYPE
/* Copy the second part of user declarations. */
-#line 60 "ael.y"
+#line 62 "ael.y"
/* declaring these AFTER the union makes things a lot simpler! */
void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s);
@@ -279,7 +281,7 @@ static pval *update_last(pval *, YYLTYPE *);
/* Line 221 of yacc.c. */
-#line 283 "ael.tab.c"
+#line 285 "ael.tab.c"
#ifdef short
# undef short
@@ -625,21 +627,21 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 186, 186, 189, 190, 191, 194, 195, 196, 197,
- 200, 201, 204, 213, 214, 215, 216, 217, 220, 226,
- 232, 233, 234, 237, 237, 243, 243, 250, 251, 252,
- 253, 256, 257, 258, 261, 262, 263, 264, 265, 266,
- 267, 268, 269, 272, 277, 281, 289, 294, 299, 308,
- 309, 310, 316, 321, 325, 333, 333, 337, 340, 343,
- 354, 355, 362, 363, 367, 371, 377, 378, 383, 391,
- 392, 396, 402, 411, 414, 415, 416, 419, 422, 425,
- 426, 427, 425, 433, 437, 438, 439, 440, 443, 443,
- 476, 477, 478, 479, 483, 486, 487, 490, 491, 494,
- 497, 501, 505, 509, 515, 516, 520, 523, 529, 529,
- 534, 542, 542, 553, 560, 563, 564, 567, 568, 571,
- 574, 575, 578, 582, 586, 592, 593, 596, 597, 598,
- 604, 609, 614, 615, 616, 618, 621, 622, 629, 630,
- 631, 634, 637
+ 0, 188, 188, 191, 192, 193, 196, 197, 198, 199,
+ 202, 203, 206, 215, 216, 217, 218, 219, 222, 228,
+ 234, 235, 236, 239, 239, 245, 245, 252, 253, 254,
+ 255, 258, 259, 260, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 274, 279, 283, 291, 296, 301, 310,
+ 311, 312, 318, 323, 327, 335, 335, 339, 342, 345,
+ 356, 357, 364, 365, 369, 373, 379, 380, 385, 393,
+ 394, 398, 404, 413, 416, 417, 418, 421, 424, 427,
+ 428, 429, 427, 435, 439, 440, 441, 442, 445, 445,
+ 478, 479, 480, 481, 485, 488, 489, 492, 493, 496,
+ 499, 503, 507, 511, 517, 518, 522, 525, 531, 531,
+ 536, 544, 544, 555, 562, 565, 566, 569, 570, 573,
+ 576, 577, 580, 584, 588, 594, 595, 598, 599, 600,
+ 606, 611, 616, 617, 618, 620, 623, 624, 631, 632,
+ 633, 636, 639
};
#endif
@@ -1450,329 +1452,329 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, parseio)
switch (yytype)
{
case 43: /* "word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1456 "ael.tab.c"
+#line 1458 "ael.tab.c"
break;
case 46: /* "objects" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1464 "ael.tab.c"
+#line 1466 "ael.tab.c"
break;
case 47: /* "object" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1472 "ael.tab.c"
+#line 1474 "ael.tab.c"
break;
case 48: /* "context_name" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1477 "ael.tab.c"
+#line 1479 "ael.tab.c"
break;
case 49: /* "context" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1485 "ael.tab.c"
+#line 1487 "ael.tab.c"
break;
case 51: /* "macro" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1493 "ael.tab.c"
+#line 1495 "ael.tab.c"
break;
case 52: /* "globals" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1501 "ael.tab.c"
+#line 1503 "ael.tab.c"
break;
case 53: /* "global_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1509 "ael.tab.c"
+#line 1511 "ael.tab.c"
break;
case 54: /* "assignment" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1517 "ael.tab.c"
+#line 1519 "ael.tab.c"
break;
case 56: /* "local_assignment" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1525 "ael.tab.c"
+#line 1527 "ael.tab.c"
break;
case 58: /* "arglist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1533 "ael.tab.c"
+#line 1535 "ael.tab.c"
break;
case 59: /* "elements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1541 "ael.tab.c"
+#line 1543 "ael.tab.c"
break;
case 60: /* "element" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1549 "ael.tab.c"
+#line 1551 "ael.tab.c"
break;
case 61: /* "ignorepat" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1557 "ael.tab.c"
+#line 1559 "ael.tab.c"
break;
case 62: /* "extension" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1565 "ael.tab.c"
+#line 1567 "ael.tab.c"
break;
case 63: /* "statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1573 "ael.tab.c"
+#line 1575 "ael.tab.c"
break;
case 64: /* "timerange" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1578 "ael.tab.c"
+#line 1580 "ael.tab.c"
break;
case 65: /* "timespec" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1586 "ael.tab.c"
+#line 1588 "ael.tab.c"
break;
case 66: /* "test_expr" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1591 "ael.tab.c"
+#line 1593 "ael.tab.c"
break;
case 68: /* "if_like_head" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1599 "ael.tab.c"
+#line 1601 "ael.tab.c"
break;
case 69: /* "word_list" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1604 "ael.tab.c"
+#line 1606 "ael.tab.c"
break;
case 71: /* "word3_list" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1609 "ael.tab.c"
+#line 1611 "ael.tab.c"
break;
case 72: /* "goto_word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1614 "ael.tab.c"
+#line 1616 "ael.tab.c"
break;
case 73: /* "switch_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1622 "ael.tab.c"
+#line 1624 "ael.tab.c"
break;
case 74: /* "statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1630 "ael.tab.c"
+#line 1632 "ael.tab.c"
break;
case 79: /* "opt_else" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1638 "ael.tab.c"
+#line 1640 "ael.tab.c"
break;
case 80: /* "target" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1646 "ael.tab.c"
+#line 1648 "ael.tab.c"
break;
case 81: /* "opt_pri" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1651 "ael.tab.c"
+#line 1653 "ael.tab.c"
break;
case 82: /* "jumptarget" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1659 "ael.tab.c"
+#line 1661 "ael.tab.c"
break;
case 83: /* "macro_call" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1667 "ael.tab.c"
+#line 1669 "ael.tab.c"
break;
case 85: /* "application_call_head" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1675 "ael.tab.c"
+#line 1677 "ael.tab.c"
break;
case 87: /* "application_call" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1683 "ael.tab.c"
+#line 1685 "ael.tab.c"
break;
case 88: /* "opt_word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
{ free((yyvaluep->str));};
-#line 1688 "ael.tab.c"
+#line 1690 "ael.tab.c"
break;
case 89: /* "eval_arglist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1696 "ael.tab.c"
+#line 1698 "ael.tab.c"
break;
case 90: /* "case_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1704 "ael.tab.c"
+#line 1706 "ael.tab.c"
break;
case 91: /* "case_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1712 "ael.tab.c"
+#line 1714 "ael.tab.c"
break;
case 92: /* "macro_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1720 "ael.tab.c"
+#line 1722 "ael.tab.c"
break;
case 93: /* "macro_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1728 "ael.tab.c"
+#line 1730 "ael.tab.c"
break;
case 94: /* "switches" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1736 "ael.tab.c"
+#line 1738 "ael.tab.c"
break;
case 95: /* "eswitches" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1744 "ael.tab.c"
+#line 1746 "ael.tab.c"
break;
case 96: /* "switchlist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1752 "ael.tab.c"
+#line 1754 "ael.tab.c"
break;
case 97: /* "included_entry" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1760 "ael.tab.c"
+#line 1762 "ael.tab.c"
break;
case 98: /* "includeslist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1768 "ael.tab.c"
+#line 1770 "ael.tab.c"
break;
case 99: /* "includes" */
-#line 165 "ael.y"
+#line 167 "ael.y"
{
destroy_pval((yyvaluep->pval));
prev_word=0;
};
-#line 1776 "ael.tab.c"
+#line 1778 "ael.tab.c"
break;
default:
@@ -2095,57 +2097,57 @@ yyreduce:
switch (yyn)
{
case 2:
-#line 186 "ael.y"
+#line 188 "ael.y"
{ (yyval.pval) = parseio->pval = (yyvsp[(1) - (1)].pval); ;}
break;
case 3:
-#line 189 "ael.y"
+#line 191 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 4:
-#line 190 "ael.y"
+#line 192 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 5:
-#line 191 "ael.y"
+#line 193 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
break;
case 6:
-#line 194 "ael.y"
+#line 196 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 7:
-#line 195 "ael.y"
+#line 197 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 8:
-#line 196 "ael.y"
+#line 198 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 9:
-#line 197 "ael.y"
+#line 199 "ael.y"
{(yyval.pval)=0;/* allow older docs to be read */;}
break;
case 10:
-#line 200 "ael.y"
+#line 202 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str); ;}
break;
case 11:
-#line 201 "ael.y"
+#line 203 "ael.y"
{ (yyval.str) = strdup("default"); ;}
break;
case 12:
-#line 204 "ael.y"
+#line 206 "ael.y"
{
(yyval.pval) = npval2(PV_CONTEXT, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)]));
(yyval.pval)->u1.str = (yyvsp[(3) - (6)].str);
@@ -2155,32 +2157,32 @@ yyreduce:
break;
case 13:
-#line 213 "ael.y"
+#line 215 "ael.y"
{ (yyval.intval) = 1; ;}
break;
case 14:
-#line 214 "ael.y"
+#line 216 "ael.y"
{ (yyval.intval) = 0; ;}
break;
case 15:
-#line 215 "ael.y"
+#line 217 "ael.y"
{ (yyval.intval) = 2; ;}
break;
case 16:
-#line 216 "ael.y"
+#line 218 "ael.y"
{ (yyval.intval)=3; ;}
break;
case 17:
-#line 217 "ael.y"
+#line 219 "ael.y"
{ (yyval.intval)=3; ;}
break;
case 18:
-#line 220 "ael.y"
+#line 222 "ael.y"
{
(yyval.pval) = npval2(PV_MACRO, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (8)].str); (yyval.pval)->u2.arglist = (yyvsp[(4) - (8)].pval); (yyval.pval)->u3.macro_statements = (yyvsp[(7) - (8)].pval);
@@ -2188,7 +2190,7 @@ yyreduce:
break;
case 19:
-#line 226 "ael.y"
+#line 228 "ael.y"
{
(yyval.pval) = npval2(PV_GLOBALS, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
(yyval.pval)->u1.statements = (yyvsp[(3) - (4)].pval);
@@ -2196,27 +2198,27 @@ yyreduce:
break;
case 20:
-#line 232 "ael.y"
+#line 234 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 21:
-#line 233 "ael.y"
+#line 235 "ael.y"
{(yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 22:
-#line 234 "ael.y"
+#line 236 "ael.y"
{(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
break;
case 23:
-#line 237 "ael.y"
+#line 239 "ael.y"
{ reset_semicount(parseio->scanner); ;}
break;
case 24:
-#line 237 "ael.y"
+#line 239 "ael.y"
{
(yyval.pval) = npval2(PV_VARDEC, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
(yyval.pval)->u1.str = (yyvsp[(1) - (5)].str);
@@ -2224,12 +2226,12 @@ yyreduce:
break;
case 25:
-#line 243 "ael.y"
+#line 245 "ael.y"
{ reset_semicount(parseio->scanner); ;}
break;
case 26:
-#line 243 "ael.y"
+#line 245 "ael.y"
{
(yyval.pval) = npval2(PV_LOCALVARDEC, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (6)].str);
@@ -2237,94 +2239,94 @@ yyreduce:
break;
case 27:
-#line 250 "ael.y"
+#line 252 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 28:
-#line 251 "ael.y"
+#line 253 "ael.y"
{ (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
break;
case 29:
-#line 252 "ael.y"
+#line 254 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;}
break;
case 30:
-#line 253 "ael.y"
+#line 255 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
break;
case 31:
-#line 256 "ael.y"
+#line 258 "ael.y"
{(yyval.pval)=0;;}
break;
case 32:
-#line 257 "ael.y"
+#line 259 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 33:
-#line 258 "ael.y"
+#line 260 "ael.y"
{ (yyval.pval)=(yyvsp[(2) - (2)].pval);;}
break;
case 34:
-#line 261 "ael.y"
+#line 263 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 35:
-#line 262 "ael.y"
+#line 264 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 36:
-#line 263 "ael.y"
+#line 265 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 37:
-#line 264 "ael.y"
+#line 266 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 38:
-#line 265 "ael.y"
+#line 267 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 39:
-#line 266 "ael.y"
+#line 268 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 40:
-#line 267 "ael.y"
+#line 269 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 41:
-#line 268 "ael.y"
+#line 270 "ael.y"
{free((yyvsp[(1) - (2)].str)); (yyval.pval)=0;;}
break;
case 42:
-#line 269 "ael.y"
+#line 271 "ael.y"
{(yyval.pval)=0;/* allow older docs to be read */;}
break;
case 43:
-#line 272 "ael.y"
+#line 274 "ael.y"
{
(yyval.pval) = npval2(PV_IGNOREPAT, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
(yyval.pval)->u1.str = (yyvsp[(3) - (4)].str);;}
break;
case 44:
-#line 277 "ael.y"
+#line 279 "ael.y"
{
(yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.str = (yyvsp[(1) - (3)].str);
@@ -2332,7 +2334,7 @@ yyreduce:
break;
case 45:
-#line 281 "ael.y"
+#line 283 "ael.y"
{
(yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (5)]), &(yylsp[(3) - (5)]));
(yyval.pval)->u1.str = malloc(strlen((yyvsp[(1) - (5)].str))+strlen((yyvsp[(3) - (5)].str))+2);
@@ -2344,7 +2346,7 @@ yyreduce:
break;
case 46:
-#line 289 "ael.y"
+#line 291 "ael.y"
{
(yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2353,7 +2355,7 @@ yyreduce:
break;
case 47:
-#line 294 "ael.y"
+#line 296 "ael.y"
{
(yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (7)]), &(yylsp[(7) - (7)]));
(yyval.pval)->u1.str = (yyvsp[(5) - (7)].str);
@@ -2362,7 +2364,7 @@ yyreduce:
break;
case 48:
-#line 299 "ael.y"
+#line 301 "ael.y"
{
(yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)]));
(yyval.pval)->u1.str = (yyvsp[(6) - (8)].str);
@@ -2372,22 +2374,22 @@ yyreduce:
break;
case 49:
-#line 308 "ael.y"
+#line 310 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 50:
-#line 309 "ael.y"
+#line 311 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 51:
-#line 310 "ael.y"
+#line 312 "ael.y"
{(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
break;
case 52:
-#line 316 "ael.y"
+#line 318 "ael.y"
{
asprintf(&(yyval.str), "%s:%s:%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str));
free((yyvsp[(1) - (5)].str));
@@ -2396,12 +2398,12 @@ yyreduce:
break;
case 53:
-#line 321 "ael.y"
+#line 323 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str); ;}
break;
case 54:
-#line 325 "ael.y"
+#line 327 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (7)].str), &(yylsp[(1) - (7)]));
(yyval.pval)->next = nword((yyvsp[(3) - (7)].str), &(yylsp[(3) - (7)]));
@@ -2410,31 +2412,31 @@ yyreduce:
break;
case 55:
-#line 333 "ael.y"
+#line 335 "ael.y"
{ reset_parencount(parseio->scanner); ;}
break;
case 56:
-#line 333 "ael.y"
+#line 335 "ael.y"
{ (yyval.str) = (yyvsp[(3) - (4)].str); ;}
break;
case 57:
-#line 337 "ael.y"
+#line 339 "ael.y"
{
(yyval.pval)= npval2(PV_IF, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (2)].str); ;}
break;
case 58:
-#line 340 "ael.y"
+#line 342 "ael.y"
{
(yyval.pval) = npval2(PV_RANDOM, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
(yyval.pval)->u1.str=(yyvsp[(2) - (2)].str);;}
break;
case 59:
-#line 343 "ael.y"
+#line 345 "ael.y"
{
(yyval.pval) = npval2(PV_IFTIME, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
(yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval);
@@ -2442,12 +2444,12 @@ yyreduce:
break;
case 60:
-#line 354 "ael.y"
+#line 356 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str);;}
break;
case 61:
-#line 355 "ael.y"
+#line 357 "ael.y"
{
asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
free((yyvsp[(1) - (2)].str));
@@ -2456,12 +2458,12 @@ yyreduce:
break;
case 62:
-#line 362 "ael.y"
+#line 364 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str); ;}
break;
case 63:
-#line 363 "ael.y"
+#line 365 "ael.y"
{
asprintf(&((yyval.str)), "%s %s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
free((yyvsp[(1) - (2)].str));
@@ -2469,7 +2471,7 @@ yyreduce:
break;
case 64:
-#line 367 "ael.y"
+#line 369 "ael.y"
{
asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
free((yyvsp[(1) - (3)].str));
@@ -2477,7 +2479,7 @@ yyreduce:
break;
case 65:
-#line 371 "ael.y"
+#line 373 "ael.y"
{ /* there are often '&' in hints */
asprintf(&((yyval.str)), "%s&%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
free((yyvsp[(1) - (3)].str));
@@ -2485,12 +2487,12 @@ yyreduce:
break;
case 66:
-#line 377 "ael.y"
+#line 379 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str);;}
break;
case 67:
-#line 378 "ael.y"
+#line 380 "ael.y"
{
asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
free((yyvsp[(1) - (2)].str));
@@ -2499,7 +2501,7 @@ yyreduce:
break;
case 68:
-#line 383 "ael.y"
+#line 385 "ael.y"
{
asprintf(&((yyval.str)), "%s%s%s", (yyvsp[(1) - (3)].str), (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str));
free((yyvsp[(1) - (3)].str));
@@ -2509,12 +2511,12 @@ yyreduce:
break;
case 69:
-#line 391 "ael.y"
+#line 393 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str);;}
break;
case 70:
-#line 392 "ael.y"
+#line 394 "ael.y"
{
asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
free((yyvsp[(1) - (2)].str));
@@ -2522,7 +2524,7 @@ yyreduce:
break;
case 71:
-#line 396 "ael.y"
+#line 398 "ael.y"
{
asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
free((yyvsp[(1) - (3)].str));
@@ -2530,7 +2532,7 @@ yyreduce:
break;
case 72:
-#line 402 "ael.y"
+#line 404 "ael.y"
{
(yyval.pval) = npval2(PV_SWITCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (5)].str);
@@ -2538,60 +2540,60 @@ yyreduce:
break;
case 73:
-#line 411 "ael.y"
+#line 413 "ael.y"
{
(yyval.pval) = npval2(PV_STATEMENTBLOCK, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval));;}
break;
case 74:
-#line 414 "ael.y"
+#line 416 "ael.y"
{ (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
break;
case 75:
-#line 415 "ael.y"
+#line 417 "ael.y"
{ (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
break;
case 76:
-#line 416 "ael.y"
+#line 418 "ael.y"
{
(yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;}
break;
case 77:
-#line 419 "ael.y"
+#line 421 "ael.y"
{
(yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;}
break;
case 78:
-#line 422 "ael.y"
+#line 424 "ael.y"
{
(yyval.pval) = npval2(PV_LABEL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
(yyval.pval)->u1.str = (yyvsp[(1) - (2)].str); ;}
break;
case 79:
-#line 425 "ael.y"
+#line 427 "ael.y"
{reset_semicount(parseio->scanner);;}
break;
case 80:
-#line 426 "ael.y"
+#line 428 "ael.y"
{reset_semicount(parseio->scanner);;}
break;
case 81:
-#line 427 "ael.y"
+#line 429 "ael.y"
{reset_parencount(parseio->scanner);;}
break;
case 82:
-#line 427 "ael.y"
+#line 429 "ael.y"
{ /* XXX word_list maybe ? */
(yyval.pval) = npval2(PV_FOR, &(yylsp[(1) - (12)]), &(yylsp[(12) - (12)]));
(yyval.pval)->u1.for_init = (yyvsp[(4) - (12)].str);
@@ -2601,7 +2603,7 @@ yyreduce:
break;
case 83:
-#line 433 "ael.y"
+#line 435 "ael.y"
{
(yyval.pval) = npval2(PV_WHILE, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (3)].str);
@@ -2609,34 +2611,34 @@ yyreduce:
break;
case 84:
-#line 437 "ael.y"
+#line 439 "ael.y"
{ (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
break;
case 85:
-#line 438 "ael.y"
+#line 440 "ael.y"
{ (yyval.pval) = update_last((yyvsp[(2) - (3)].pval), &(yylsp[(2) - (3)])); ;}
break;
case 86:
-#line 439 "ael.y"
+#line 441 "ael.y"
{ (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;}
break;
case 87:
-#line 440 "ael.y"
+#line 442 "ael.y"
{
(yyval.pval)= npval2(PV_APPLICATION_CALL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
(yyval.pval)->u1.str = (yyvsp[(1) - (2)].str);;}
break;
case 88:
-#line 443 "ael.y"
+#line 445 "ael.y"
{reset_semicount(parseio->scanner);;}
break;
case 89:
-#line 443 "ael.y"
+#line 445 "ael.y"
{
char *bufx;
int tot=0;
@@ -2673,22 +2675,22 @@ yyreduce:
break;
case 90:
-#line 476 "ael.y"
+#line 478 "ael.y"
{ (yyval.pval) = npval2(PV_BREAK, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
break;
case 91:
-#line 477 "ael.y"
+#line 479 "ael.y"
{ (yyval.pval) = npval2(PV_RETURN, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
break;
case 92:
-#line 478 "ael.y"
+#line 480 "ael.y"
{ (yyval.pval) = npval2(PV_CONTINUE, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
break;
case 93:
-#line 479 "ael.y"
+#line 481 "ael.y"
{
(yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(2) - (3)]));
(yyval.pval)->u2.statements = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval));
@@ -2696,41 +2698,41 @@ yyreduce:
break;
case 94:
-#line 483 "ael.y"
+#line 485 "ael.y"
{ (yyval.pval)=0; ;}
break;
case 95:
-#line 486 "ael.y"
+#line 488 "ael.y"
{ (yyval.pval) = (yyvsp[(2) - (2)].pval); ;}
break;
case 96:
-#line 487 "ael.y"
+#line 489 "ael.y"
{ (yyval.pval) = NULL ; ;}
break;
case 97:
-#line 490 "ael.y"
+#line 492 "ael.y"
{ (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
break;
case 98:
-#line 491 "ael.y"
+#line 493 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
(yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;}
break;
case 99:
-#line 494 "ael.y"
+#line 496 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
(yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;}
break;
case 100:
-#line 497 "ael.y"
+#line 499 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)]));
(yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2738,7 +2740,7 @@ yyreduce:
break;
case 101:
-#line 501 "ael.y"
+#line 503 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)]));
(yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2746,7 +2748,7 @@ yyreduce:
break;
case 102:
-#line 505 "ael.y"
+#line 507 "ael.y"
{
(yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)]));
(yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2754,7 +2756,7 @@ yyreduce:
break;
case 103:
-#line 509 "ael.y"
+#line 511 "ael.y"
{
(yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)]));
(yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2762,24 +2764,24 @@ yyreduce:
break;
case 104:
-#line 515 "ael.y"
+#line 517 "ael.y"
{ (yyval.str) = strdup("1"); ;}
break;
case 105:
-#line 516 "ael.y"
+#line 518 "ael.y"
{ (yyval.str) = (yyvsp[(2) - (2)].str); ;}
break;
case 106:
-#line 520 "ael.y"
+#line 522 "ael.y"
{ /* ext[, pri] default 1 */
(yyval.pval) = nword((yyvsp[(1) - (2)].str), &(yylsp[(1) - (2)]));
(yyval.pval)->next = nword((yyvsp[(2) - (2)].str), &(yylsp[(2) - (2)])); ;}
break;
case 107:
-#line 523 "ael.y"
+#line 525 "ael.y"
{ /* context, ext, pri */
(yyval.pval) = nword((yyvsp[(4) - (4)].str), &(yylsp[(4) - (4)]));
(yyval.pval)->next = nword((yyvsp[(1) - (4)].str), &(yylsp[(1) - (4)]));
@@ -2787,12 +2789,12 @@ yyreduce:
break;
case 108:
-#line 529 "ael.y"
+#line 531 "ael.y"
{reset_argcount(parseio->scanner);;}
break;
case 109:
-#line 529 "ael.y"
+#line 531 "ael.y"
{
/* XXX original code had @2 but i think we need @5 */
(yyval.pval) = npval2(PV_MACRO_CALL, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
@@ -2801,19 +2803,19 @@ yyreduce:
break;
case 110:
-#line 534 "ael.y"
+#line 536 "ael.y"
{
(yyval.pval)= npval2(PV_MACRO_CALL, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.str = (yyvsp[(1) - (3)].str); ;}
break;
case 111:
-#line 542 "ael.y"
+#line 544 "ael.y"
{reset_argcount(parseio->scanner);;}
break;
case 112:
-#line 542 "ael.y"
+#line 544 "ael.y"
{
if (strcasecmp((yyvsp[(1) - (3)].str),"goto") == 0) {
(yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(2) - (3)]));
@@ -2826,7 +2828,7 @@ yyreduce:
break;
case 113:
-#line 553 "ael.y"
+#line 555 "ael.y"
{
(yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(3) - (3)]));
if( (yyval.pval)->type == PV_GOTO )
@@ -2837,49 +2839,49 @@ yyreduce:
break;
case 114:
-#line 560 "ael.y"
+#line 562 "ael.y"
{ (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;}
break;
case 115:
-#line 563 "ael.y"
+#line 565 "ael.y"
{ (yyval.str) = (yyvsp[(1) - (1)].str) ;}
break;
case 116:
-#line 564 "ael.y"
+#line 566 "ael.y"
{ (yyval.str) = strdup(""); ;}
break;
case 117:
-#line 567 "ael.y"
+#line 569 "ael.y"
{ (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
break;
case 118:
-#line 568 "ael.y"
+#line 570 "ael.y"
{
(yyval.pval)= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/);
(yyval.pval)->u1.str = strdup(""); ;}
break;
case 119:
-#line 571 "ael.y"
+#line 573 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;}
break;
case 120:
-#line 574 "ael.y"
+#line 576 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 121:
-#line 575 "ael.y"
+#line 577 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 122:
-#line 578 "ael.y"
+#line 580 "ael.y"
{
(yyval.pval) = npval2(PV_CASE, &(yylsp[(1) - (4)]), &(yylsp[(3) - (4)])); /* XXX 3 or 4 ? */
(yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2887,7 +2889,7 @@ yyreduce:
break;
case 123:
-#line 582 "ael.y"
+#line 584 "ael.y"
{
(yyval.pval) = npval2(PV_DEFAULT, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
(yyval.pval)->u1.str = NULL;
@@ -2895,7 +2897,7 @@ yyreduce:
break;
case 124:
-#line 586 "ael.y"
+#line 588 "ael.y"
{
(yyval.pval) = npval2(PV_PATTERN, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); /* XXX@3 or @4 ? */
(yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2903,27 +2905,27 @@ yyreduce:
break;
case 125:
-#line 592 "ael.y"
+#line 594 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 126:
-#line 593 "ael.y"
+#line 595 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
break;
case 127:
-#line 596 "ael.y"
+#line 598 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 128:
-#line 597 "ael.y"
+#line 599 "ael.y"
{ (yyval.pval)=(yyvsp[(1) - (1)].pval);;}
break;
case 129:
-#line 598 "ael.y"
+#line 600 "ael.y"
{
(yyval.pval) = npval2(PV_CATCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
(yyval.pval)->u1.str = (yyvsp[(2) - (5)].str);
@@ -2931,47 +2933,47 @@ yyreduce:
break;
case 130:
-#line 604 "ael.y"
+#line 606 "ael.y"
{
(yyval.pval) = npval2(PV_SWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)]));
(yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
break;
case 131:
-#line 609 "ael.y"
+#line 611 "ael.y"
{
(yyval.pval) = npval2(PV_ESWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)]));
(yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
break;
case 132:
-#line 614 "ael.y"
+#line 616 "ael.y"
{ (yyval.pval) = NULL; ;}
break;
case 133:
-#line 615 "ael.y"
+#line 617 "ael.y"
{ (yyval.pval) = linku1(nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])), (yyvsp[(3) - (3)].pval)); ;}
break;
case 134:
-#line 616 "ael.y"
+#line 618 "ael.y"
{ char *x; asprintf(&x,"%s@%s", (yyvsp[(1) - (5)].str),(yyvsp[(3) - (5)].str)); free((yyvsp[(1) - (5)].str)); free((yyvsp[(3) - (5)].str));
(yyval.pval) = linku1(nword(x, &(yylsp[(1) - (5)])), (yyvsp[(5) - (5)].pval));;}
break;
case 135:
-#line 618 "ael.y"
+#line 620 "ael.y"
{(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
break;
case 136:
-#line 621 "ael.y"
+#line 623 "ael.y"
{ (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
break;
case 137:
-#line 622 "ael.y"
+#line 624 "ael.y"
{
(yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
(yyval.pval)->u2.arglist = (yyvsp[(3) - (3)].pval);
@@ -2979,36 +2981,36 @@ yyreduce:
break;
case 138:
-#line 629 "ael.y"
+#line 631 "ael.y"
{ (yyval.pval) = (yyvsp[(1) - (2)].pval); ;}
break;
case 139:
-#line 630 "ael.y"
+#line 632 "ael.y"
{ (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval)); ;}
break;
case 140:
-#line 631 "ael.y"
+#line 633 "ael.y"
{(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
break;
case 141:
-#line 634 "ael.y"
+#line 636 "ael.y"
{
(yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
(yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval);set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
break;
case 142:
-#line 637 "ael.y"
+#line 639 "ael.y"
{
(yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));;}
break;
/* Line 1270 of yacc.c. */
-#line 3012 "ael.tab.c"
+#line 3014 "ael.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3227,7 +3229,7 @@ yyreturn:
}
-#line 642 "ael.y"
+#line 644 "ael.y"
static char *token_equivs1[] =
diff --git a/res/ael/ael.tab.h b/res/ael/ael.tab.h
index 95b011852..02c09dbb9 100644
--- a/res/ael/ael.tab.h
+++ b/res/ael/ael.tab.h
@@ -120,7 +120,7 @@
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-#line 54 "ael.y"
+#line 56 "ael.y"
{
int intval; /* integer value, typically flags */
char *str; /* strings */
diff --git a/res/ael/ael.y b/res/ael/ael.y
index a8df1cb51..97558eca4 100644
--- a/res/ael/ael.y
+++ b/res/ael/ael.y
@@ -31,6 +31,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include "asterisk/logger.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
pval * linku1(pval *head, pval *tail);
diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c
index 1f96e3377..b96cda20f 100644
--- a/res/ael/ael_lex.c
+++ b/res/ael/ael_lex.c
@@ -804,9 +804,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define GLOB_ABORTED GLOB_ABEND
#endif
# include <glob.h>
-
#include "asterisk/logger.h"
#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "ael/ael.tab.h"
#include "asterisk/ael_structs.h"
@@ -907,7 +908,7 @@ static void pbcwhere(const char *text, int *line, int *col )
#define STORE_POS
#define STORE_LOC
#endif
-#line 909 "ael_lex.c"
+#line 911 "ael_lex.c"
#define INITIAL 0
#define paren 1
@@ -1146,10 +1147,10 @@ YY_DECL
register int yy_act;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-#line 187 "ael.flex"
+#line 189 "ael.flex"
-#line 1151 "ael_lex.c"
+#line 1153 "ael_lex.c"
yylval = yylval_param;
@@ -1240,260 +1241,260 @@ do_action: /* This label is used only to access EOF actions. */
case 1:
YY_RULE_SETUP
-#line 189 "ael.flex"
+#line 191 "ael.flex"
{ STORE_POS; return LC;}
YY_BREAK
case 2:
YY_RULE_SETUP
-#line 190 "ael.flex"
+#line 192 "ael.flex"
{ STORE_POS; return RC;}
YY_BREAK
case 3:
YY_RULE_SETUP
-#line 191 "ael.flex"
+#line 193 "ael.flex"
{ STORE_POS; return LP;}
YY_BREAK
case 4:
YY_RULE_SETUP
-#line 192 "ael.flex"
+#line 194 "ael.flex"
{ STORE_POS; return RP;}
YY_BREAK
case 5:
YY_RULE_SETUP
-#line 193 "ael.flex"
+#line 195 "ael.flex"
{ STORE_POS; return SEMI;}
YY_BREAK
case 6:
YY_RULE_SETUP
-#line 194 "ael.flex"
+#line 196 "ael.flex"
{ STORE_POS; return EQ;}
YY_BREAK
case 7:
YY_RULE_SETUP
-#line 195 "ael.flex"
+#line 197 "ael.flex"
{ STORE_POS; return COMMA;}
YY_BREAK
case 8:
YY_RULE_SETUP
-#line 196 "ael.flex"
+#line 198 "ael.flex"
{ STORE_POS; return COLON;}
YY_BREAK
case 9:
YY_RULE_SETUP
-#line 197 "ael.flex"
+#line 199 "ael.flex"
{ STORE_POS; return AMPER;}
YY_BREAK
case 10:
YY_RULE_SETUP
-#line 198 "ael.flex"
+#line 200 "ael.flex"
{ STORE_POS; return BAR;}
YY_BREAK
case 11:
YY_RULE_SETUP
-#line 199 "ael.flex"
+#line 201 "ael.flex"
{ STORE_POS; return EXTENMARK;}
YY_BREAK
case 12:
YY_RULE_SETUP
-#line 200 "ael.flex"
+#line 202 "ael.flex"
{ STORE_POS; return AT;}
YY_BREAK
case 13:
YY_RULE_SETUP
-#line 201 "ael.flex"
+#line 203 "ael.flex"
{/*comment*/}
YY_BREAK
case 14:
YY_RULE_SETUP
-#line 202 "ael.flex"
+#line 204 "ael.flex"
{ STORE_POS; return KW_CONTEXT;}
YY_BREAK
case 15:
YY_RULE_SETUP
-#line 203 "ael.flex"
+#line 205 "ael.flex"
{ STORE_POS; return KW_ABSTRACT;}
YY_BREAK
case 16:
YY_RULE_SETUP
-#line 204 "ael.flex"
+#line 206 "ael.flex"
{ STORE_POS; return KW_EXTEND;}
YY_BREAK
case 17:
YY_RULE_SETUP
-#line 205 "ael.flex"
+#line 207 "ael.flex"
{ STORE_POS; return KW_MACRO;};
YY_BREAK
case 18:
YY_RULE_SETUP
-#line 206 "ael.flex"
+#line 208 "ael.flex"
{ STORE_POS; return KW_GLOBALS;}
YY_BREAK
case 19:
YY_RULE_SETUP
-#line 207 "ael.flex"
+#line 209 "ael.flex"
{ STORE_POS; return KW_LOCAL;}
YY_BREAK
case 20:
YY_RULE_SETUP
-#line 208 "ael.flex"
+#line 210 "ael.flex"
{ STORE_POS; return KW_IGNOREPAT;}
YY_BREAK
case 21:
YY_RULE_SETUP
-#line 209 "ael.flex"
+#line 211 "ael.flex"
{ STORE_POS; return KW_SWITCH;}
YY_BREAK
case 22:
YY_RULE_SETUP
-#line 210 "ael.flex"
+#line 212 "ael.flex"
{ STORE_POS; return KW_IF;}
YY_BREAK
case 23:
YY_RULE_SETUP
-#line 211 "ael.flex"
+#line 213 "ael.flex"
{ STORE_POS; return KW_IFTIME;}
YY_BREAK
case 24:
YY_RULE_SETUP
-#line 212 "ael.flex"
+#line 214 "ael.flex"
{ STORE_POS; return KW_RANDOM;}
YY_BREAK
case 25:
YY_RULE_SETUP
-#line 213 "ael.flex"
+#line 215 "ael.flex"
{ STORE_POS; return KW_REGEXTEN;}
YY_BREAK
case 26:
YY_RULE_SETUP
-#line 214 "ael.flex"
+#line 216 "ael.flex"
{ STORE_POS; return KW_HINT;}
YY_BREAK
case 27:
YY_RULE_SETUP
-#line 215 "ael.flex"
+#line 217 "ael.flex"
{ STORE_POS; return KW_ELSE;}
YY_BREAK
case 28:
YY_RULE_SETUP
-#line 216 "ael.flex"
+#line 218 "ael.flex"
{ STORE_POS; return KW_GOTO;}
YY_BREAK
case 29:
YY_RULE_SETUP
-#line 217 "ael.flex"
+#line 219 "ael.flex"
{ STORE_POS; return KW_JUMP;}
YY_BREAK
case 30:
YY_RULE_SETUP
-#line 218 "ael.flex"
+#line 220 "ael.flex"
{ STORE_POS; return KW_RETURN;}
YY_BREAK
case 31:
YY_RULE_SETUP
-#line 219 "ael.flex"
+#line 221 "ael.flex"
{ STORE_POS; return KW_BREAK;}
YY_BREAK
case 32:
YY_RULE_SETUP
-#line 220 "ael.flex"
+#line 222 "ael.flex"
{ STORE_POS; return KW_CONTINUE;}
YY_BREAK
case 33:
YY_RULE_SETUP
-#line 221 "ael.flex"
+#line 223 "ael.flex"
{ STORE_POS; return KW_FOR;}
YY_BREAK
case 34:
YY_RULE_SETUP
-#line 222 "ael.flex"
+#line 224 "ael.flex"
{ STORE_POS; return KW_WHILE;}
YY_BREAK
case 35:
YY_RULE_SETUP
-#line 223 "ael.flex"
+#line 225 "ael.flex"
{ STORE_POS; return KW_CASE;}
YY_BREAK
case 36:
YY_RULE_SETUP
-#line 224 "ael.flex"
+#line 226 "ael.flex"
{ STORE_POS; return KW_DEFAULT;}
YY_BREAK
case 37:
YY_RULE_SETUP
-#line 225 "ael.flex"
+#line 227 "ael.flex"
{ STORE_POS; return KW_PATTERN;}
YY_BREAK
case 38:
YY_RULE_SETUP
-#line 226 "ael.flex"
+#line 228 "ael.flex"
{ STORE_POS; return KW_CATCH;}
YY_BREAK
case 39:
YY_RULE_SETUP
-#line 227 "ael.flex"
+#line 229 "ael.flex"
{ STORE_POS; return KW_SWITCHES;}
YY_BREAK
case 40:
YY_RULE_SETUP
-#line 228 "ael.flex"
+#line 230 "ael.flex"
{ STORE_POS; return KW_ESWITCHES;}
YY_BREAK
case 41:
YY_RULE_SETUP
-#line 229 "ael.flex"
+#line 231 "ael.flex"
{ STORE_POS; return KW_INCLUDES;}
YY_BREAK
case 42:
YY_RULE_SETUP
-#line 230 "ael.flex"
+#line 232 "ael.flex"
{ BEGIN(comment); my_col += 2; }
YY_BREAK
case 43:
YY_RULE_SETUP
-#line 232 "ael.flex"
+#line 234 "ael.flex"
{ my_col += yyleng; }
YY_BREAK
case 44:
/* rule 44 can match eol */
YY_RULE_SETUP
-#line 233 "ael.flex"
+#line 235 "ael.flex"
{ ++my_lineno; my_col=1;}
YY_BREAK
case 45:
YY_RULE_SETUP
-#line 234 "ael.flex"
+#line 236 "ael.flex"
{ my_col += yyleng; }
YY_BREAK
case 46:
/* rule 46 can match eol */
YY_RULE_SETUP
-#line 235 "ael.flex"
+#line 237 "ael.flex"
{ ++my_lineno; my_col=1;}
YY_BREAK
case 47:
YY_RULE_SETUP
-#line 236 "ael.flex"
+#line 238 "ael.flex"
{ my_col += 2; BEGIN(INITIAL); }
YY_BREAK
case 48:
/* rule 48 can match eol */
YY_RULE_SETUP
-#line 238 "ael.flex"
+#line 240 "ael.flex"
{ my_lineno++; my_col = 1; }
YY_BREAK
case 49:
YY_RULE_SETUP
-#line 239 "ael.flex"
+#line 241 "ael.flex"
{ my_col += yyleng; }
YY_BREAK
case 50:
YY_RULE_SETUP
-#line 240 "ael.flex"
+#line 242 "ael.flex"
{ my_col += (yyleng*8)-(my_col%8); }
YY_BREAK
case 51:
YY_RULE_SETUP
-#line 242 "ael.flex"
+#line 244 "ael.flex"
{
STORE_POS;
yylval->str = strdup(yytext);
@@ -1511,7 +1512,7 @@ YY_RULE_SETUP
case 52:
/* rule 52 can match eol */
YY_RULE_SETUP
-#line 258 "ael.flex"
+#line 260 "ael.flex"
{
if ( pbcpop(')') ) { /* error */
STORE_LOC;
@@ -1537,7 +1538,7 @@ YY_RULE_SETUP
case 53:
/* rule 53 can match eol */
YY_RULE_SETUP
-#line 280 "ael.flex"
+#line 282 "ael.flex"
{
char c = yytext[yyleng-1];
if (c == '(')
@@ -1549,7 +1550,7 @@ YY_RULE_SETUP
case 54:
/* rule 54 can match eol */
YY_RULE_SETUP
-#line 288 "ael.flex"
+#line 290 "ael.flex"
{
char c = yytext[yyleng-1];
if ( pbcpop(c)) { /* error */
@@ -1574,7 +1575,7 @@ YY_RULE_SETUP
case 55:
/* rule 55 can match eol */
YY_RULE_SETUP
-#line 310 "ael.flex"
+#line 312 "ael.flex"
{
char c = yytext[yyleng-1];
if (c == '(')
@@ -1586,7 +1587,7 @@ YY_RULE_SETUP
case 56:
/* rule 56 can match eol */
YY_RULE_SETUP
-#line 318 "ael.flex"
+#line 320 "ael.flex"
{
if ( pbcpop(')') ) { /* error */
STORE_LOC;
@@ -1614,7 +1615,7 @@ YY_RULE_SETUP
case 57:
/* rule 57 can match eol */
YY_RULE_SETUP
-#line 342 "ael.flex"
+#line 344 "ael.flex"
{
if( parencount != 0) { /* printf("Folding in a comma!\n"); */
yymore();
@@ -1632,7 +1633,7 @@ YY_RULE_SETUP
case 58:
/* rule 58 can match eol */
YY_RULE_SETUP
-#line 356 "ael.flex"
+#line 358 "ael.flex"
{
char c = yytext[yyleng-1];
if ( pbcpop(c) ) { /* error */
@@ -1653,7 +1654,7 @@ YY_RULE_SETUP
case 59:
/* rule 59 can match eol */
YY_RULE_SETUP
-#line 373 "ael.flex"
+#line 375 "ael.flex"
{
char c = yytext[yyleng-1];
yymore();
@@ -1663,7 +1664,7 @@ YY_RULE_SETUP
case 60:
/* rule 60 can match eol */
YY_RULE_SETUP
-#line 379 "ael.flex"
+#line 381 "ael.flex"
{
char c = yytext[yyleng-1];
if ( pbcpop(c) ) { /* error */
@@ -1679,7 +1680,7 @@ YY_RULE_SETUP
case 61:
/* rule 61 can match eol */
YY_RULE_SETUP
-#line 391 "ael.flex"
+#line 393 "ael.flex"
{
STORE_LOC;
yylval->str = strdup(yytext);
@@ -1692,7 +1693,7 @@ YY_RULE_SETUP
case 62:
/* rule 62 can match eol */
YY_RULE_SETUP
-#line 400 "ael.flex"
+#line 402 "ael.flex"
{
char fnamebuf[1024],*p1,*p2;
int glob_ret;
@@ -1742,7 +1743,7 @@ case YY_STATE_EOF(paren):
case YY_STATE_EOF(semic):
case YY_STATE_EOF(argg):
case YY_STATE_EOF(comment):
-#line 445 "ael.flex"
+#line 447 "ael.flex"
{
char fnamebuf[2048];
if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) {
@@ -1777,10 +1778,10 @@ case YY_STATE_EOF(comment):
YY_BREAK
case 63:
YY_RULE_SETUP
-#line 479 "ael.flex"
+#line 481 "ael.flex"
ECHO;
YY_BREAK
-#line 1784 "ael_lex.c"
+#line 1786 "ael_lex.c"
case YY_END_OF_BUFFER:
{
@@ -2905,7 +2906,7 @@ void *ael_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
#define YYTABLES_NAME "yytables"
-#line 479 "ael.flex"
+#line 481 "ael.flex"
diff --git a/res/ael/pval.c b/res/ael/pval.c
index 44bc0a12d..fa9625a3d 100644
--- a/res/ael/pval.c
+++ b/res/ael/pval.c
@@ -4006,7 +4006,7 @@ static void fix_gotos_in_extensions(struct ael_extension *exten)
}
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
{
pval *p,*p2;
struct ast_context *context;
@@ -4037,7 +4037,7 @@ void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
switch (p->type) {
case PV_MACRO:
- context = ast_context_create(local_contexts, p->u1.str, registrar);
+ context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
exten = new_exten();
exten->context = context;
@@ -4075,7 +4075,7 @@ void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
break;
case PV_CONTEXT:
- context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
+ context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
/* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
for (p2=p->u2.statements; p2; p2=p2->next) {
diff --git a/utils/Makefile b/utils/Makefile
index fe4a2dbfe..87b79302c 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -130,7 +130,7 @@ aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c
aelparse.o: ASTCFLAGS+=-I$(ASTTOPDIR)/res -DSTANDALONE_AEL -Wno-unused
-aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
+aelparse: aelparse.o aelbison.o pbx_ael.o hashtab.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
astobj2.c: $(ASTTOPDIR)/main/astobj2.c
@cp $< $@
@@ -154,7 +154,7 @@ hashtest.o: ASTCFLAGS+=-O0
extconf.o: extconf.c
-conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o
+conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o hashtab.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o
testexpr2s: $(ASTTOPDIR)/main/ast_expr2f.c $(ASTTOPDIR)/main/ast_expr2.c $(ASTTOPDIR)/main/ast_expr2.h
$(CC) -g -c -I$(ASTTOPDIR)/include -DSTANDALONE_AEL $(ASTTOPDIR)/main/ast_expr2f.c -o ast_expr2f.o
diff --git a/utils/ael_main.c b/utils/ael_main.c
index 7174cf942..ae5dbd10b 100644
--- a/utils/ael_main.c
+++ b/utils/ael_main.c
@@ -19,6 +19,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ast_expr.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
#include "asterisk/extconf.h"
@@ -557,3 +559,33 @@ int main(int argc, char **argv)
return 0;
}
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+{
+ return 0;
+}
+
+unsigned int ast_hashtab_hash_contexts(const void *obj);
+
+unsigned int ast_hashtab_hash_contexts(const void *obj)
+{
+ return 0;
+}
+
+#ifdef DEBUG_THREADS
+
+void ast_mark_lock_acquired(void *lock_addr)
+{
+}
+
+void ast_remove_lock_info(void *lock_addr)
+{
+}
+
+void ast_store_lock_info(enum ast_lock_type type, const char *filename,
+ int line_num, const char *func, const char *lock_name, void *lock_addr)
+{
+}
+
+#endif
diff --git a/utils/conf2ael.c b/utils/conf2ael.c
index 02d28af0d..7ece70e23 100644
--- a/utils/conf2ael.c
+++ b/utils/conf2ael.c
@@ -47,6 +47,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/callerid.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
@@ -607,14 +609,7 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
return localized_context_add_include2(con, value,registrar);
}
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
- printf("Creating context %s, registrar=%s\n", name, registrar);
-
- return localized_context_create(extcontexts, name, registrar);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
{
printf("find/Creating context %s, registrar=%s\n", name, registrar);
@@ -661,9 +656,9 @@ int ast_context_verify_includes(struct ast_context *con)
return localized_context_verify_includes(con);
}
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
{
localized_merge_contexts_and_delete(extcontexts, registrar);
}
@@ -691,3 +686,33 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
}
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+{
+ return 0;
+}
+
+unsigned int ast_hashtab_hash_contexts(const void *obj);
+
+unsigned int ast_hashtab_hash_contexts(const void *obj)
+{
+ return 0;
+}
+
+#ifdef DEBUG_THREADS
+
+void ast_mark_lock_acquired(void *lock_addr)
+{
+}
+
+void ast_remove_lock_info(void *lock_addr)
+{
+}
+
+void ast_store_lock_info(enum ast_lock_type type, const char *filename,
+ int line_num, const char *func, const char *lock_name, void *lock_addr)
+{
+}
+
+#endif
diff --git a/utils/extconf.c b/utils/extconf.c
index 0afcc0222..d388586e0 100644
--- a/utils/extconf.c
+++ b/utils/extconf.c
@@ -23,6 +23,7 @@
* for operations outside of asterisk. A huge, awful hack.
*
*/
+#undef DEBUG_THREADS
#include "asterisk/compat.h"
#include "asterisk/paths.h" /* we use AST_CONFIG_DIR */
@@ -65,10 +66,9 @@ struct ast_channel
#include "asterisk/inline_api.h"
#include "asterisk/endian.h"
#include "asterisk/ast_expr.h"
-#include "asterisk/ael_structs.h"
-#include "asterisk/pval.h"
/* logger.h */
+
#define EVENTLOG "event_log"
#define QUEUELOG "queue_log"
@@ -147,6 +147,746 @@ void ast_console_toggle_mute(int fd);
#define __LOG_DTMF 6
#define LOG_DTMF __LOG_DTMF, _A_
+/* lock.h */
+
+#ifndef HAVE_MTX_PROFILE
+#define __MTX_PROF(a) return pthread_mutex_lock((a))
+#else
+#define __MTX_PROF(a) do { \
+ int i; \
+ /* profile only non-blocking events */ \
+ ast_mark(mtx_prof, 1); \
+ i = pthread_mutex_trylock((a)); \
+ ast_mark(mtx_prof, 0); \
+ if (!i) \
+ return i; \
+ else \
+ return pthread_mutex_lock((a)); \
+ } while (0)
+#endif /* HAVE_MTX_PROFILE */
+
+#define AST_PTHREADT_NULL (pthread_t) -1
+#define AST_PTHREADT_STOP (pthread_t) -2
+
+#if defined(SOLARIS) || defined(BSD)
+#define AST_MUTEX_INIT_W_CONSTRUCTORS
+#endif /* SOLARIS || BSD */
+
+/* Asterisk REQUIRES recursive (not error checking) mutexes
+ and will not run without them. */
+#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
+#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
+#else
+#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
+#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
+#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
+
+#ifdef DEBUG_THREADS
+
+#define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
+
+#ifdef THREAD_CRASH
+#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
+#else
+#define DO_THREAD_CRASH do { } while (0)
+#endif
+
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
+
+#define AST_MAX_REENTRANCY 10
+
+struct ast_mutex_info {
+ pthread_mutex_t mutex;
+ /*! Track which thread holds this lock */
+ unsigned int track:1;
+ const char *file[AST_MAX_REENTRANCY];
+ int lineno[AST_MAX_REENTRANCY];
+ int reentrancy;
+ const char *func[AST_MAX_REENTRANCY];
+ pthread_t thread[AST_MAX_REENTRANCY];
+};
+
+typedef struct ast_mutex_info ast_mutex_t;
+
+typedef pthread_cond_t ast_cond_t;
+
+static pthread_mutex_t empty_mutex;
+
+static void __attribute__((constructor)) init_empty_mutex(void)
+{
+ memset(&empty_mutex, 0, sizeof(empty_mutex));
+}
+
+static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
+ const char *mutex_name, ast_mutex_t *t,
+ pthread_mutexattr_t *attr)
+{
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+ int canlog = strcmp(filename, "logger.c");
+
+ if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ if ((t->mutex) != (empty_mutex)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
+ filename, lineno, func, mutex_name);
+ __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
+ t->file[0], t->lineno[0], t->func[0], mutex_name);
+ DO_THREAD_CRASH;
+ return 0;
+ }
+ }
+#endif
+
+ t->file[0] = filename;
+ t->lineno[0] = lineno;
+ t->func[0] = func;
+ t->thread[0] = 0;
+ t->reentrancy = 0;
+
+ return pthread_mutex_init(&t->mutex, attr);
+}
+
+static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
+ const char *mutex_name, ast_mutex_t *t)
+{
+ static pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+
+ return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
+}
+#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
+
+static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
+ const char *mutex_name, ast_mutex_t *t)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ }
+#endif
+
+ res = pthread_mutex_trylock(&t->mutex);
+ switch (res) {
+ case 0:
+ pthread_mutex_unlock(&t->mutex);
+ break;
+ case EINVAL:
+ __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
+ filename, lineno, func, mutex_name);
+ break;
+ case EBUSY:
+ __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
+ filename, lineno, func, mutex_name);
+ __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+ break;
+ }
+
+ if ((res = pthread_mutex_destroy(&t->mutex)))
+ __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
+ filename, lineno, func, strerror(res));
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+ else
+ t->mutex = PTHREAD_MUTEX_INIT_VALUE;
+#endif
+ t->file[0] = filename;
+ t->lineno[0] = lineno;
+ t->func[0] = func;
+
+ return res;
+}
+
+static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
+ const char* mutex_name, ast_mutex_t *t)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ ast_mutex_init(t);
+ }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+#ifdef DETECT_DEADLOCKS
+ {
+ time_t seconds = time(NULL);
+ time_t current;
+ do {
+#ifdef HAVE_MTX_PROFILE
+ ast_mark(mtx_prof, 1);
+#endif
+ res = pthread_mutex_trylock(&t->mutex);
+#ifdef HAVE_MTX_PROFILE
+ ast_mark(mtx_prof, 0);
+#endif
+ if (res == EBUSY) {
+ current = time(NULL);
+ if ((current - seconds) && (!((current - seconds) % 5))) {
+ __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
+ filename, lineno, func, (int)(current - seconds), mutex_name);
+ __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
+ t->func[t->reentrancy-1], mutex_name);
+ }
+ usleep(200);
+ }
+ } while (res == EBUSY);
+ }
+#else
+#ifdef HAVE_MTX_PROFILE
+ ast_mark(mtx_prof, 1);
+ res = pthread_mutex_trylock(&t->mutex);
+ ast_mark(mtx_prof, 0);
+ if (res)
+#endif
+ res = pthread_mutex_lock(&t->mutex);
+#endif /* DETECT_DEADLOCKS */
+
+ if (!res) {
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = filename;
+ t->lineno[t->reentrancy] = lineno;
+ t->func[t->reentrancy] = func;
+ t->thread[t->reentrancy] = pthread_self();
+ t->reentrancy++;
+ } else {
+ __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+ filename, lineno, func, mutex_name);
+ }
+ } else {
+ __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
+ filename, lineno, func, strerror(errno));
+ DO_THREAD_CRASH;
+ }
+
+ return res;
+}
+
+static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
+ const char* mutex_name, ast_mutex_t *t)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ ast_mutex_init(t);
+ }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+ if (!(res = pthread_mutex_trylock(&t->mutex))) {
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = filename;
+ t->lineno[t->reentrancy] = lineno;
+ t->func[t->reentrancy] = func;
+ t->thread[t->reentrancy] = pthread_self();
+ t->reentrancy++;
+ } else {
+ __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+ filename, lineno, func, mutex_name);
+ }
+ } else {
+ __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+ }
+
+ return res;
+}
+
+static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
+ const char *mutex_name, ast_mutex_t *t)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ }
+#endif
+
+ if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+ __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+ filename, lineno, func, mutex_name);
+ __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+ DO_THREAD_CRASH;
+ }
+
+ if (--t->reentrancy < 0) {
+ __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+ filename, lineno, func, mutex_name);
+ t->reentrancy = 0;
+ }
+
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = NULL;
+ t->lineno[t->reentrancy] = 0;
+ t->func[t->reentrancy] = NULL;
+ t->thread[t->reentrancy] = 0;
+ }
+
+ if ((res = pthread_mutex_unlock(&t->mutex))) {
+ __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
+ filename, lineno, func, strerror(res));
+ DO_THREAD_CRASH;
+ }
+
+ return res;
+}
+
+static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
+ const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
+{
+ return pthread_cond_init(cond, cond_attr);
+}
+
+static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
+ const char *cond_name, ast_cond_t *cond)
+{
+ return pthread_cond_signal(cond);
+}
+
+static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
+ const char *cond_name, ast_cond_t *cond)
+{
+ return pthread_cond_broadcast(cond);
+}
+
+static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
+ const char *cond_name, ast_cond_t *cond)
+{
+ return pthread_cond_destroy(cond);
+}
+
+static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
+ const char *cond_name, const char *mutex_name,
+ ast_cond_t *cond, ast_mutex_t *t)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ }
+#endif
+
+ if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+ __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+ filename, lineno, func, mutex_name);
+ __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+ DO_THREAD_CRASH;
+ }
+
+ if (--t->reentrancy < 0) {
+ __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+ filename, lineno, func, mutex_name);
+ t->reentrancy = 0;
+ }
+
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = NULL;
+ t->lineno[t->reentrancy] = 0;
+ t->func[t->reentrancy] = NULL;
+ t->thread[t->reentrancy] = 0;
+ }
+
+ if ((res = pthread_cond_wait(cond, &t->mutex))) {
+ __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
+ filename, lineno, func, strerror(res));
+ DO_THREAD_CRASH;
+ } else {
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = filename;
+ t->lineno[t->reentrancy] = lineno;
+ t->func[t->reentrancy] = func;
+ t->thread[t->reentrancy] = pthread_self();
+ t->reentrancy++;
+ } else {
+ __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+ filename, lineno, func, mutex_name);
+ }
+ }
+
+ return res;
+}
+
+static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
+ const char *cond_name, const char *mutex_name, ast_cond_t *cond,
+ ast_mutex_t *t, const struct timespec *abstime)
+{
+ int res;
+ int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+ if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+ __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+ filename, lineno, func, mutex_name);
+ }
+#endif
+
+ if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+ __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+ filename, lineno, func, mutex_name);
+ __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+ t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+ DO_THREAD_CRASH;
+ }
+
+ if (--t->reentrancy < 0) {
+ __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+ filename, lineno, func, mutex_name);
+ t->reentrancy = 0;
+ }
+
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = NULL;
+ t->lineno[t->reentrancy] = 0;
+ t->func[t->reentrancy] = NULL;
+ t->thread[t->reentrancy] = 0;
+ }
+
+ if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
+ __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
+ filename, lineno, func, strerror(res));
+ DO_THREAD_CRASH;
+ } else {
+ if (t->reentrancy < AST_MAX_REENTRANCY) {
+ t->file[t->reentrancy] = filename;
+ t->lineno[t->reentrancy] = lineno;
+ t->func[t->reentrancy] = func;
+ t->thread[t->reentrancy] = pthread_self();
+ t->reentrancy++;
+ } else {
+ __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+ filename, lineno, func, mutex_name);
+ }
+ }
+
+ return res;
+}
+
+#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
+#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
+#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
+
+#else /* !DEBUG_THREADS */
+
+
+typedef pthread_mutex_t ast_mutex_t;
+
+#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
+
+static inline int ast_mutex_init(ast_mutex_t *pmutex)
+{
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+
+ return pthread_mutex_init(pmutex, &attr);
+}
+
+#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
+
+static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
+{
+ return pthread_mutex_unlock(pmutex);
+}
+
+static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
+{
+ return pthread_mutex_destroy(pmutex);
+}
+
+static inline int ast_mutex_lock(ast_mutex_t *pmutex)
+{
+ __MTX_PROF(pmutex);
+}
+
+static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
+{
+ return pthread_mutex_trylock(pmutex);
+}
+
+typedef pthread_cond_t ast_cond_t;
+
+static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
+{
+ return pthread_cond_init(cond, cond_attr);
+}
+
+static inline int ast_cond_signal(ast_cond_t *cond)
+{
+ return pthread_cond_signal(cond);
+}
+
+static inline int ast_cond_broadcast(ast_cond_t *cond)
+{
+ return pthread_cond_broadcast(cond);
+}
+
+static inline int ast_cond_destroy(ast_cond_t *cond)
+{
+ return pthread_cond_destroy(cond);
+}
+
+static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
+{
+ return pthread_cond_wait(cond, t);
+}
+
+static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
+{
+ return pthread_cond_timedwait(cond, t, abstime);
+}
+
+#endif /* !DEBUG_THREADS */
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
+ constructors/destructors to create/destroy mutexes. */
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+ scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
+static void __attribute__ ((constructor)) init_##mutex(void) \
+{ \
+ ast_mutex_init(&mutex); \
+} \
+static void __attribute__ ((destructor)) fini_##mutex(void) \
+{ \
+ ast_mutex_destroy(&mutex); \
+}
+#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
+/* By default, use static initialization of mutexes. */
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+ scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
+#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
+#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
+#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
+#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
+#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
+#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
+#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
+#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
+#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
+#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
+#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
+#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
+
+#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
+
+#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
+
+#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
+
+#ifndef __linux__
+#define pthread_create __use_ast_pthread_create_instead__
+#endif
+
+typedef pthread_rwlock_t ast_rwlock_t;
+
+static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+{
+ pthread_rwlockattr_t attr;
+
+ pthread_rwlockattr_init(&attr);
+
+#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
+ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
+#endif
+
+ return pthread_rwlock_init(prwlock, &attr);
+}
+
+static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_destroy(prwlock);
+}
+
+static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_unlock(prwlock);
+}
+
+static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_rdlock(prwlock);
+}
+
+static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_tryrdlock(prwlock);
+}
+
+static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_wrlock(prwlock);
+}
+
+static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
+{
+ return pthread_rwlock_trywrlock(prwlock);
+}
+
+/* Statically declared read/write locks */
+
+#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+ scope ast_rwlock_t rwlock; \
+static void __attribute__ ((constructor)) init_##rwlock(void) \
+{ \
+ ast_rwlock_init(&rwlock); \
+} \
+static void __attribute__ ((destructor)) fini_##rwlock(void) \
+{ \
+ ast_rwlock_destroy(&rwlock); \
+}
+#else
+#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+ scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
+#endif
+
+#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
+
+/*
+ * Initial support for atomic instructions.
+ * For platforms that have it, use the native cpu instruction to
+ * implement them. For other platforms, resort to a 'slow' version
+ * (defined in utils.c) that protects the atomic instruction with
+ * a single lock.
+ * The slow versions is always available, for testing purposes,
+ * as ast_atomic_fetchadd_int_slow()
+ */
+
+#if defined(HAVE_OSX_ATOMICS)
+#include "libkern/OSAtomic.h"
+#endif
+
+/*! \brief Atomically add v to *p and return * the previous value of *p.
+ * This can be used to handle reference counts, and the return value
+ * can be used to generate unique identifiers.
+ */
+
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ return __sync_fetch_and_add(p, v);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ return OSAtomicAdd32(v, (int32_t *) p);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ return OSAtomicAdd64(v, (int64_t *) p);
+#elif defined (__i386__) || defined(__x86_64__)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ __asm __volatile (
+ " lock xaddl %0, %1 ; "
+ : "+r" (v), /* 0 (result) */
+ "=m" (*p) /* 1 */
+ : "m" (*p)); /* 2 */
+ return (v);
+})
+#else
+static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
+{
+ int ret;
+ ret = *p;
+ *p += v;
+ return ret;
+}
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ return ast_atomic_fetchadd_int_slow(p, v);
+})
+#endif
+
+/*! \brief decrement *p by 1 and return true if the variable has reached 0.
+ * Useful e.g. to check if a refcount has reached 0.
+ */
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+ return __sync_sub_and_fetch(p, 1) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+ return OSAtomicAdd32( -1, (int32_t *) p) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+ return OSAtomicAdd64( -1, (int64_t *) p) == 0;
+#else
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+ int a = ast_atomic_fetchadd_int(p, -1);
+ return a == 1; /* true if the value is 0 now (so it was 1 previously) */
+})
+#endif
+
+#ifndef DEBUG_CHANNEL_LOCKS
+/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
+ in the Makefile, print relevant output for debugging */
+#define ast_channel_lock(x) ast_mutex_lock(&x->lock)
+/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
+ in the Makefile, print relevant output for debugging */
+#define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
+/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
+ in the Makefile, print relevant output for debugging */
+#define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
+#else
+
+/*! \brief Lock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_lock(struct ast_channel *chan);
+
+/*! \brief Unlock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function
+*/
+int ast_channel_unlock(struct ast_channel *chan);
+
+/*! \brief Lock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_trylock(struct ast_channel *chan);
+#endif
+
+
+#include "asterisk/hashtab.h"
+#include "asterisk/ael_structs.h"
+#include "asterisk/pval.h"
+
/* from utils.h */
static unsigned int __unsigned_int_flags_dummy;
@@ -1121,742 +1861,6 @@ extern int ast_language_is_prefix;
-/* lock.h */
-
-#ifndef HAVE_MTX_PROFILE
-#define __MTX_PROF(a) return pthread_mutex_lock((a))
-#else
-#define __MTX_PROF(a) do { \
- int i; \
- /* profile only non-blocking events */ \
- ast_mark(mtx_prof, 1); \
- i = pthread_mutex_trylock((a)); \
- ast_mark(mtx_prof, 0); \
- if (!i) \
- return i; \
- else \
- return pthread_mutex_lock((a)); \
- } while (0)
-#endif /* HAVE_MTX_PROFILE */
-
-#define AST_PTHREADT_NULL (pthread_t) -1
-#define AST_PTHREADT_STOP (pthread_t) -2
-
-#if defined(SOLARIS) || defined(BSD)
-#define AST_MUTEX_INIT_W_CONSTRUCTORS
-#endif /* SOLARIS || BSD */
-
-/* Asterisk REQUIRES recursive (not error checking) mutexes
- and will not run without them. */
-#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
-#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
-#else
-#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
-#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
-#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
-
-#ifdef DEBUG_THREADS
-
-#define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
-
-#ifdef THREAD_CRASH
-#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
-#else
-#define DO_THREAD_CRASH do { } while (0)
-#endif
-
-#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
-
-#define AST_MAX_REENTRANCY 10
-
-struct ast_mutex_info {
- pthread_mutex_t mutex;
- /*! Track which thread holds this lock */
- unsigned int track:1;
- const char *file[AST_MAX_REENTRANCY];
- int lineno[AST_MAX_REENTRANCY];
- int reentrancy;
- const char *func[AST_MAX_REENTRANCY];
- pthread_t thread[AST_MAX_REENTRANCY];
-};
-
-typedef struct ast_mutex_info ast_mutex_t;
-
-typedef pthread_cond_t ast_cond_t;
-
-static pthread_mutex_t empty_mutex;
-
-static void __attribute__((constructor)) init_empty_mutex(void)
-{
- memset(&empty_mutex, 0, sizeof(empty_mutex));
-}
-
-static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
- const char *mutex_name, ast_mutex_t *t,
- pthread_mutexattr_t *attr)
-{
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
- int canlog = strcmp(filename, "logger.c");
-
- if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- if ((t->mutex) != (empty_mutex)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
- filename, lineno, func, mutex_name);
- __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
- t->file[0], t->lineno[0], t->func[0], mutex_name);
- DO_THREAD_CRASH;
- return 0;
- }
- }
-#endif
-
- t->file[0] = filename;
- t->lineno[0] = lineno;
- t->func[0] = func;
- t->thread[0] = 0;
- t->reentrancy = 0;
-
- return pthread_mutex_init(&t->mutex, attr);
-}
-
-static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
- const char *mutex_name, ast_mutex_t *t)
-{
- static pthread_mutexattr_t attr;
-
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
-
- return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
-}
-#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
-
-static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
- const char *mutex_name, ast_mutex_t *t)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- }
-#endif
-
- res = pthread_mutex_trylock(&t->mutex);
- switch (res) {
- case 0:
- pthread_mutex_unlock(&t->mutex);
- break;
- case EINVAL:
- __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
- filename, lineno, func, mutex_name);
- break;
- case EBUSY:
- __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
- filename, lineno, func, mutex_name);
- __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
- break;
- }
-
- if ((res = pthread_mutex_destroy(&t->mutex)))
- __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
- filename, lineno, func, strerror(res));
-#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
- else
- t->mutex = PTHREAD_MUTEX_INIT_VALUE;
-#endif
- t->file[0] = filename;
- t->lineno[0] = lineno;
- t->func[0] = func;
-
- return res;
-}
-
-static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
- const char* mutex_name, ast_mutex_t *t)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- ast_mutex_init(t);
- }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-#ifdef DETECT_DEADLOCKS
- {
- time_t seconds = time(NULL);
- time_t current;
- do {
-#ifdef HAVE_MTX_PROFILE
- ast_mark(mtx_prof, 1);
-#endif
- res = pthread_mutex_trylock(&t->mutex);
-#ifdef HAVE_MTX_PROFILE
- ast_mark(mtx_prof, 0);
-#endif
- if (res == EBUSY) {
- current = time(NULL);
- if ((current - seconds) && (!((current - seconds) % 5))) {
- __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
- filename, lineno, func, (int)(current - seconds), mutex_name);
- __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
- t->func[t->reentrancy-1], mutex_name);
- }
- usleep(200);
- }
- } while (res == EBUSY);
- }
-#else
-#ifdef HAVE_MTX_PROFILE
- ast_mark(mtx_prof, 1);
- res = pthread_mutex_trylock(&t->mutex);
- ast_mark(mtx_prof, 0);
- if (res)
-#endif
- res = pthread_mutex_lock(&t->mutex);
-#endif /* DETECT_DEADLOCKS */
-
- if (!res) {
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = filename;
- t->lineno[t->reentrancy] = lineno;
- t->func[t->reentrancy] = func;
- t->thread[t->reentrancy] = pthread_self();
- t->reentrancy++;
- } else {
- __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
- filename, lineno, func, mutex_name);
- }
- } else {
- __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
- filename, lineno, func, strerror(errno));
- DO_THREAD_CRASH;
- }
-
- return res;
-}
-
-static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
- const char* mutex_name, ast_mutex_t *t)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- ast_mutex_init(t);
- }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
- if (!(res = pthread_mutex_trylock(&t->mutex))) {
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = filename;
- t->lineno[t->reentrancy] = lineno;
- t->func[t->reentrancy] = func;
- t->thread[t->reentrancy] = pthread_self();
- t->reentrancy++;
- } else {
- __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
- filename, lineno, func, mutex_name);
- }
- } else {
- __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
- }
-
- return res;
-}
-
-static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
- const char *mutex_name, ast_mutex_t *t)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- }
-#endif
-
- if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
- __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
- filename, lineno, func, mutex_name);
- __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
- DO_THREAD_CRASH;
- }
-
- if (--t->reentrancy < 0) {
- __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
- filename, lineno, func, mutex_name);
- t->reentrancy = 0;
- }
-
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = NULL;
- t->lineno[t->reentrancy] = 0;
- t->func[t->reentrancy] = NULL;
- t->thread[t->reentrancy] = 0;
- }
-
- if ((res = pthread_mutex_unlock(&t->mutex))) {
- __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
- filename, lineno, func, strerror(res));
- DO_THREAD_CRASH;
- }
-
- return res;
-}
-
-static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
- const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
- return pthread_cond_init(cond, cond_attr);
-}
-
-static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
- const char *cond_name, ast_cond_t *cond)
-{
- return pthread_cond_signal(cond);
-}
-
-static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
- const char *cond_name, ast_cond_t *cond)
-{
- return pthread_cond_broadcast(cond);
-}
-
-static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
- const char *cond_name, ast_cond_t *cond)
-{
- return pthread_cond_destroy(cond);
-}
-
-static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
- const char *cond_name, const char *mutex_name,
- ast_cond_t *cond, ast_mutex_t *t)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- }
-#endif
-
- if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
- __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
- filename, lineno, func, mutex_name);
- __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
- DO_THREAD_CRASH;
- }
-
- if (--t->reentrancy < 0) {
- __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
- filename, lineno, func, mutex_name);
- t->reentrancy = 0;
- }
-
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = NULL;
- t->lineno[t->reentrancy] = 0;
- t->func[t->reentrancy] = NULL;
- t->thread[t->reentrancy] = 0;
- }
-
- if ((res = pthread_cond_wait(cond, &t->mutex))) {
- __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
- filename, lineno, func, strerror(res));
- DO_THREAD_CRASH;
- } else {
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = filename;
- t->lineno[t->reentrancy] = lineno;
- t->func[t->reentrancy] = func;
- t->thread[t->reentrancy] = pthread_self();
- t->reentrancy++;
- } else {
- __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
- filename, lineno, func, mutex_name);
- }
- }
-
- return res;
-}
-
-static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
- const char *cond_name, const char *mutex_name, ast_cond_t *cond,
- ast_mutex_t *t, const struct timespec *abstime)
-{
- int res;
- int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
- if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
- __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
- filename, lineno, func, mutex_name);
- }
-#endif
-
- if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
- __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
- filename, lineno, func, mutex_name);
- __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
- t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
- DO_THREAD_CRASH;
- }
-
- if (--t->reentrancy < 0) {
- __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
- filename, lineno, func, mutex_name);
- t->reentrancy = 0;
- }
-
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = NULL;
- t->lineno[t->reentrancy] = 0;
- t->func[t->reentrancy] = NULL;
- t->thread[t->reentrancy] = 0;
- }
-
- if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
- __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
- filename, lineno, func, strerror(res));
- DO_THREAD_CRASH;
- } else {
- if (t->reentrancy < AST_MAX_REENTRANCY) {
- t->file[t->reentrancy] = filename;
- t->lineno[t->reentrancy] = lineno;
- t->func[t->reentrancy] = func;
- t->thread[t->reentrancy] = pthread_self();
- t->reentrancy++;
- } else {
- __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
- filename, lineno, func, mutex_name);
- }
- }
-
- return res;
-}
-
-#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
-#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
-#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
-
-#else /* !DEBUG_THREADS */
-
-
-typedef pthread_mutex_t ast_mutex_t;
-
-#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
-
-static inline int ast_mutex_init(ast_mutex_t *pmutex)
-{
- pthread_mutexattr_t attr;
-
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
-
- return pthread_mutex_init(pmutex, &attr);
-}
-
-#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
-
-static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
-{
- return pthread_mutex_unlock(pmutex);
-}
-
-static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
-{
- return pthread_mutex_destroy(pmutex);
-}
-
-static inline int ast_mutex_lock(ast_mutex_t *pmutex)
-{
- __MTX_PROF(pmutex);
-}
-
-static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
-{
- return pthread_mutex_trylock(pmutex);
-}
-
-typedef pthread_cond_t ast_cond_t;
-
-static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
- return pthread_cond_init(cond, cond_attr);
-}
-
-static inline int ast_cond_signal(ast_cond_t *cond)
-{
- return pthread_cond_signal(cond);
-}
-
-static inline int ast_cond_broadcast(ast_cond_t *cond)
-{
- return pthread_cond_broadcast(cond);
-}
-
-static inline int ast_cond_destroy(ast_cond_t *cond)
-{
- return pthread_cond_destroy(cond);
-}
-
-static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
-{
- return pthread_cond_wait(cond, t);
-}
-
-static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
-{
- return pthread_cond_timedwait(cond, t, abstime);
-}
-
-#endif /* !DEBUG_THREADS */
-
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
- constructors/destructors to create/destroy mutexes. */
-#define __AST_MUTEX_DEFINE(scope, mutex) \
- scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
-static void __attribute__ ((constructor)) init_##mutex(void) \
-{ \
- ast_mutex_init(&mutex); \
-} \
-static void __attribute__ ((destructor)) fini_##mutex(void) \
-{ \
- ast_mutex_destroy(&mutex); \
-}
-#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
-/* By default, use static initialization of mutexes. */
-#define __AST_MUTEX_DEFINE(scope, mutex) \
- scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
-#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
-#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
-#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
-#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
-#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
-#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
-#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
-#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
-#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
-#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
-#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
-#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
-
-#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
-
-#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
-
-#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
-
-#ifndef __linux__
-#define pthread_create __use_ast_pthread_create_instead__
-#endif
-
-typedef pthread_rwlock_t ast_rwlock_t;
-
-static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
-{
- pthread_rwlockattr_t attr;
-
- pthread_rwlockattr_init(&attr);
-
-#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
- pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
-#endif
-
- return pthread_rwlock_init(prwlock, &attr);
-}
-
-static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_destroy(prwlock);
-}
-
-static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_unlock(prwlock);
-}
-
-static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_rdlock(prwlock);
-}
-
-static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_tryrdlock(prwlock);
-}
-
-static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_wrlock(prwlock);
-}
-
-static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
-{
- return pthread_rwlock_trywrlock(prwlock);
-}
-
-/* Statically declared read/write locks */
-
-#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
- scope ast_rwlock_t rwlock; \
-static void __attribute__ ((constructor)) init_##rwlock(void) \
-{ \
- ast_rwlock_init(&rwlock); \
-} \
-static void __attribute__ ((destructor)) fini_##rwlock(void) \
-{ \
- ast_rwlock_destroy(&rwlock); \
-}
-#else
-#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
- scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
-#endif
-
-#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
-
-/*
- * Initial support for atomic instructions.
- * For platforms that have it, use the native cpu instruction to
- * implement them. For other platforms, resort to a 'slow' version
- * (defined in utils.c) that protects the atomic instruction with
- * a single lock.
- * The slow versions is always available, for testing purposes,
- * as ast_atomic_fetchadd_int_slow()
- */
-
-#if defined(HAVE_OSX_ATOMICS)
-#include "libkern/OSAtomic.h"
-#endif
-
-/*! \brief Atomically add v to *p and return * the previous value of *p.
- * This can be used to handle reference counts, and the return value
- * can be used to generate unique identifiers.
- */
-
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
- return __sync_fetch_and_add(p, v);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
- return OSAtomicAdd32(v, (int32_t *) p);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
- return OSAtomicAdd64(v, (int64_t *) p);
-#elif defined (__i386__) || defined(__x86_64__)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
- __asm __volatile (
- " lock xaddl %0, %1 ; "
- : "+r" (v), /* 0 (result) */
- "=m" (*p) /* 1 */
- : "m" (*p)); /* 2 */
- return (v);
-})
-#else
-static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
-{
- int ret;
- ret = *p;
- *p += v;
- return ret;
-}
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
- return ast_atomic_fetchadd_int_slow(p, v);
-})
-#endif
-
-/*! \brief decrement *p by 1 and return true if the variable has reached 0.
- * Useful e.g. to check if a refcount has reached 0.
- */
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
- return __sync_sub_and_fetch(p, 1) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
- return OSAtomicAdd32( -1, (int32_t *) p) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
- return OSAtomicAdd64( -1, (int64_t *) p) == 0;
-#else
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
- int a = ast_atomic_fetchadd_int(p, -1);
- return a == 1; /* true if the value is 0 now (so it was 1 previously) */
-})
-#endif
-
-#ifndef DEBUG_CHANNEL_LOCKS
-/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
- in the Makefile, print relevant output for debugging */
-#define ast_channel_lock(x) ast_mutex_lock(&x->lock)
-/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
- in the Makefile, print relevant output for debugging */
-#define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
-/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
- in the Makefile, print relevant output for debugging */
-#define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
-#else
-
-/*! \brief Lock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_lock(struct ast_channel *chan);
-
-/*! \brief Unlock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function
-*/
-int ast_channel_unlock(struct ast_channel *chan);
-
-/*! \brief Lock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_trylock(struct ast_channel *chan);
-#endif
-
-
/* linkedlists.h */
#define AST_LIST_LOCK(head) \