diff options
Diffstat (limited to 'main/pbx.c')
-rw-r--r-- | main/pbx.c | 86 |
1 files changed, 70 insertions, 16 deletions
diff --git a/main/pbx.c b/main/pbx.c index 103d27815..1554beac7 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -339,6 +339,12 @@ 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); +static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp, + struct ast_exten *el, struct ast_exten *e, int replace, int lockhints); +static int ast_add_extension2_lockopt(struct ast_context *con, + int replace, const char *extension, int priority, const char *label, const char *callerid, + const char *application, void *data, void (*datad)(void *), + const char *registrar, int lockconts, int lockhints); /* a func for qsort to use to sort a char array */ static int compare_char(const void *a, const void *b) @@ -3464,20 +3470,18 @@ int ast_extension_state_del(int id, ast_state_cb_type callback) return ret; } -/*! \brief Add hint to hint list, check initial extension state */ -static int ast_add_hint(struct ast_exten *e) + +/*! \brief Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! */ +static int ast_add_hint_nolock(struct ast_exten *e) { struct ast_hint *hint; if (!e) return -1; - AST_RWLIST_WRLOCK(&hints); - /* Search if hint exists, do nothing */ AST_RWLIST_TRAVERSE(&hints, hint, list) { if (hint->exten == e) { - AST_RWLIST_UNLOCK(&hints); ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e)); return -1; } @@ -3486,7 +3490,6 @@ static int ast_add_hint(struct ast_exten *e) ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e)); if (!(hint = ast_calloc(1, sizeof(*hint)))) { - AST_RWLIST_UNLOCK(&hints); return -1; } /* Initialize and insert new item at the top */ @@ -3494,10 +3497,21 @@ static int ast_add_hint(struct ast_exten *e) hint->laststate = ast_extension_state2(e); AST_RWLIST_INSERT_HEAD(&hints, hint, list); - AST_RWLIST_UNLOCK(&hints); return 0; } +/*! \brief Add hint to hint list, check initial extension state */ +static int ast_add_hint(struct ast_exten *e) +{ + int ret; + + AST_RWLIST_WRLOCK(&hints); + ret = ast_add_hint_nolock(e); + AST_RWLIST_UNLOCK(&hints); + + return ret; +} + /*! \brief Change hint for an extension */ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne) { @@ -5788,13 +5802,13 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ } 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_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n"); } AST_RWLIST_WRLOCK(&hints); @@ -6549,6 +6563,17 @@ static int ext_strncpy(char *dst, const char *src, int len) static int add_pri(struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace) { + return add_pri_lockopt(con, tmp, el, e, replace, 1); +} + +/*! + * \brief add the extension in the priority chain. + * \retval 0 on success. + * \retval -1 on failure. +*/ +static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp, + struct ast_exten *el, struct ast_exten *e, int replace, int lockhints) +{ struct ast_exten *ep; struct ast_exten *eh=e; @@ -6683,8 +6708,13 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp, e->next = NULL; /* e is no more at the head, so e->next must be reset */ } /* And immediately return success. */ - if (tmp->priority == PRIORITY_HINT) - ast_add_hint(tmp); + if (tmp->priority == PRIORITY_HINT) { + if (lockhints) { + ast_add_hint(tmp); + } else { + ast_add_hint_nolock(tmp); + } + } } return 0; } @@ -6719,6 +6749,19 @@ int ast_add_extension2(struct ast_context *con, const char *application, void *data, void (*datad)(void *), const char *registrar) { + return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1); +} + +/*! \brief + * Does all the work of ast_add_extension2, but adds two args, to determine if + * context and hint locking should be done. In merge_and_delete, we need to do + * this without locking, as the locks are already held. + */ +static int ast_add_extension2_lockopt(struct ast_context *con, + int replace, const char *extension, int priority, const char *label, const char *callerid, + const char *application, void *data, void (*datad)(void *), + const char *registrar, int lockconts, int lockhints) +{ /* * Sort extensions (or patterns) according to the rules indicated above. * These are implemented by the function ext_cmp()). @@ -6790,7 +6833,9 @@ int ast_add_extension2(struct ast_context *con, tmp->datad = datad; tmp->registrar = registrar; - ast_wrlock_context(con); + if (lockconts) { + ast_wrlock_context(con); + } if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding an extension, and the trie exists, then we need to incrementally add this pattern to it. */ @@ -6823,7 +6868,9 @@ int ast_add_extension2(struct ast_context *con, } if (e && res == 0) { /* exact match, insert in the pri chain */ res = add_pri(con, tmp, el, e, replace); - ast_unlock_context(con); + if (lockconts) { + ast_unlock_context(con); + } if (res < 0) { errno = EEXIST; /* XXX do we care ? */ return 0; /* XXX should we return -1 maybe ? */ @@ -6880,9 +6927,16 @@ int ast_add_extension2(struct ast_context *con, } ast_hashtab_insert_safe(con->root_table, tmp); - ast_unlock_context(con); - if (tmp->priority == PRIORITY_HINT) - ast_add_hint(tmp); + if (lockconts) { + ast_unlock_context(con); + } + if (tmp->priority == PRIORITY_HINT) { + if (lockhints) { + ast_add_hint(tmp); + } else { + ast_add_hint_nolock(tmp); + } + } } if (option_debug) { if (tmp->matchcid) { |