diff options
-rw-r--r-- | apps/app_dial.c | 4 | ||||
-rw-r--r-- | apps/app_meetme.c | 4 | ||||
-rw-r--r-- | apps/app_queue.c | 4 | ||||
-rw-r--r-- | channels/chan_iax2.c | 3 | ||||
-rw-r--r-- | channels/chan_sip.c | 9 | ||||
-rw-r--r-- | channels/chan_skinny.c | 3 | ||||
-rw-r--r-- | include/asterisk/pbx.h | 38 | ||||
-rw-r--r-- | include/asterisk/pval.h | 3 | ||||
-rw-r--r-- | main/features.c | 15 | ||||
-rw-r--r-- | main/pbx.c | 592 | ||||
-rw-r--r-- | pbx/pbx_ael.c | 12 | ||||
-rw-r--r-- | pbx/pbx_config.c | 16 | ||||
-rw-r--r-- | res/ael/ael.flex | 4 | ||||
-rw-r--r-- | res/ael/ael.tab.c | 502 | ||||
-rw-r--r-- | res/ael/ael.tab.h | 2 | ||||
-rw-r--r-- | res/ael/ael.y | 2 | ||||
-rw-r--r-- | res/ael/ael_lex.c | 141 | ||||
-rw-r--r-- | res/ael/pval.c | 6 | ||||
-rw-r--r-- | utils/Makefile | 4 | ||||
-rw-r--r-- | utils/ael_main.c | 33 | ||||
-rw-r--r-- | utils/conf2ael.c | 45 | ||||
-rw-r--r-- | utils/extconf.c | 1480 |
22 files changed, 1582 insertions, 1340 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c index b52a97b2d..dfd6f8306 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -2096,9 +2096,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 471477a55..b7a72aeb7 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -5280,7 +5280,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); @@ -5417,7 +5417,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 5ab932c1c..bd2487d9b 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -6147,9 +6147,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/channels/chan_iax2.c b/channels/chan_iax2.c index 1df3cf3e8..d19adbef0 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -10771,8 +10771,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 40645214a..a4afae1a9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3388,6 +3388,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 @@ -3408,11 +3409,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); + } } } @@ -20297,8 +20299,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 44d88ae1f..4baa5771a 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -5801,8 +5801,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 1ba9b0d70..14e7af4b2 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) @@ -973,8 +965,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 edfd647b3..ea545e4a4 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 d26ac5b91..2a284cb43 100644 --- a/main/features.c +++ b/main/features.c @@ -488,9 +488,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 */ @@ -2228,12 +2226,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; @@ -2822,7 +2817,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 8d9658f36..427c0cca9 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" @@ -140,8 +141,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]; @@ -203,12 +204,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 */ + 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 */ @@ -327,17 +329,18 @@ 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); /* 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; @@ -376,7 +379,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); @@ -684,7 +687,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 */ @@ -1252,11 +1255,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); @@ -1582,12 +1585,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]; @@ -1599,8 +1603,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)) @@ -1668,7 +1672,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)) ) { @@ -1690,7 +1694,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 @@ -1750,9 +1754,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; @@ -1786,9 +1790,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)) ) { @@ -2465,7 +2469,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 */ @@ -2552,7 +2556,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 */ @@ -3479,14 +3483,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; } } @@ -3527,10 +3531,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); @@ -3627,8 +3631,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 @@ -3789,19 +3792,19 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension /* Handle this is in the new world */ #ifdef NEED_DEBUG - ast_log(LOG_NOTICE,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar); + ast_verb(3,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar); #endif /* find this particular extension */ ex.exten = dummy_name; ex.matchcid = 0; 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); + 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); @@ -3815,24 +3818,28 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension } } 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 */ @@ -3848,7 +3855,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension } } 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 @@ -3905,10 +3912,10 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension */ struct ast_exten *next_node = peer->peer ? peer->peer : peer->next; if (next_node && next_node == peer->peer) { - next_node->peer_tree = exten->peer_tree; /* move the priority hash tabs over */ - exten->peer_tree = 0; - next_node->peer_label_tree = exten->peer_label_tree; - exten->peer_label_tree = 0; + next_node->peer_table = exten->peer_table; /* move the priority hash tabs over */ + exten->peer_table = 0; + next_node->peer_label_table = exten->peer_label_table; + exten->peer_label_table = 0; } if (!prev_exten) { /* change the root... */ con->root = next_node; @@ -3946,7 +3953,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; @@ -3984,7 +3991,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 @@ -4578,7 +4585,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; @@ -5127,42 +5134,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; } } @@ -5171,19 +5173,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->root_table = NULL; tmp->registrar = 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); @@ -5191,16 +5200,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; @@ -5213,17 +5213,89 @@ struct store_hint { AST_LIST_HEAD(store_hints, store_hint); +/* 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 */ + } + 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); + } +} + + /* 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 @@ -5232,8 +5304,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) { @@ -5252,36 +5345,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 */ @@ -5316,7 +5387,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; } @@ -5854,6 +5954,7 @@ int ast_add_extension(const char *context, int replace, const char *extension, application, data, datad, registrar); ast_unlock_contexts(); } + return ret; } @@ -5980,9 +6081,9 @@ 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); + ast_hashtab_insert_safe(eh->peer_table, tmp); if (tmp->label) - ast_hashtab_insert_safe(eh->peer_label_tree, tmp); + ast_hashtab_insert_safe(eh->peer_label_table, tmp); ep->peer = tmp; return 0; /* success */ } @@ -6002,25 +6103,25 @@ 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); + ast_hashtab_remove_object_via_lookup(eh->peer_table,e); if (e->label) - ast_hashtab_remove_object_via_lookup(eh->peer_label_tree,e); - ast_hashtab_insert_safe(eh->peer_tree,tmp); + 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_tree,tmp); + 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); + 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_tree,e); + ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, 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_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 */ @@ -6032,18 +6133,18 @@ 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); + 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_tree,e); + ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, 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_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 */ @@ -6064,20 +6165,20 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp, 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); + 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 @@ -6159,6 +6260,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) { @@ -6170,7 +6274,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 { @@ -6192,11 +6296,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 */ @@ -6230,48 +6334,48 @@ 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); + 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); + 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); @@ -6287,7 +6391,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", @@ -6684,68 +6788,125 @@ 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 (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_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 */ 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)) ) + if ( registrar || (con && 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; + + 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 (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); + + ast_context_remove_extension2(tmp, prio_item->exten, prio_item->priority, registrar); + } + 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, */ + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root) { + 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 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; } @@ -6754,7 +6915,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(); } @@ -6899,7 +7060,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) { @@ -7568,12 +7729,21 @@ 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() { + int res = ast_rwlock_wrlock(&conlock); + if (!res) + ast_atomic_fetchadd_int(&conlock_wrlock_version, 1); return ast_rwlock_wrlock(&conlock); } diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c index fa4b7d516..0e40c9496 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 @@ -88,7 +89,7 @@ void linkprio(struct ael_extension *exten, struct ael_priority *prio); 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 ); @@ -108,6 +109,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"); @@ -127,10 +130,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 4a7a3d368..bf707a950 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 */ @@ -1371,7 +1371,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; @@ -1399,7 +1398,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; @@ -1601,7 +1600,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); @@ -1626,12 +1625,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 cf2d36a2c..1ca6427f4 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 26206af5d..8b7436374 100644 --- a/res/ael/ael_lex.c +++ b/res/ael/ael_lex.c @@ -803,9 +803,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" @@ -906,7 +907,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 @@ -1145,10 +1146,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; @@ -1239,260 +1240,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); @@ -1510,7 +1511,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; @@ -1536,7 +1537,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 == '(') @@ -1548,7 +1549,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 */ @@ -1573,7 +1574,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 == '(') @@ -1585,7 +1586,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; @@ -1613,7 +1614,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(); @@ -1631,7 +1632,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 */ @@ -1652,7 +1653,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(); @@ -1662,7 +1663,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 */ @@ -1678,7 +1679,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); @@ -1691,7 +1692,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; @@ -1741,7 +1742,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) { @@ -1778,10 +1779,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: { @@ -2906,7 +2907,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 56794041d..38748ecde 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -3963,7 +3963,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; @@ -3994,7 +3994,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; @@ -4032,7 +4032,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 4c6bb1114..5089ffe63 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -131,7 +131,7 @@ aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c aelparse.o: ASTCFLAGS+=-I$(ASTTOPDIR)/res -DSTANDALONE_AEL -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 $< $@ @@ -155,7 +155,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 7f20365f3..24349b457 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" @@ -582,3 +584,34 @@ 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 fa6a3ccdb..56856efbf 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" @@ -604,14 +606,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); @@ -658,9 +653,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); } @@ -688,3 +683,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 5d4b21eac..9903ff295 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; @@ -1119,742 +1859,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) \ |