diff options
-rw-r--r-- | main/pbx.c | 127 |
1 files changed, 110 insertions, 17 deletions
diff --git a/main/pbx.c b/main/pbx.c index 84e727127..0dcca8fd3 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -967,6 +967,15 @@ 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 ast_add_extension_nolock(const char *context, int replace, const char *extension, + int priority, const char *label, const char *callerid, + const char *application, void *data, void (*datad)(void *), const char *registrar); +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) @@ -1150,6 +1159,7 @@ void check_contexts_trouble(void) } static struct ast_context *find_context_locked(const char *context); +static struct ast_context *find_context(const char *context); int check_contexts(char *, int); int check_contexts(char *file, int line ) @@ -3965,20 +3975,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; } @@ -3987,7 +3995,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 */ @@ -3995,10 +4002,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) { @@ -4563,6 +4581,22 @@ void pbx_set_overrideswitch(const char *newval) /*! * \brief lookup for a context with a given name, + * \retval found context or NULL if not found. +*/ +static struct ast_context *find_context(const char *context) +{ + struct ast_context *c = NULL; + struct fake_context item; + + ast_copy_string(item.name, context, sizeof(item.name)); + + c = ast_hashtab_lookup(contexts_table,&item); + + return c; +} + +/*! + * \brief lookup for a context with a given name, * \retval with conlock held if found. * \retval NULL if not found. */ @@ -6533,13 +6567,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); @@ -6580,7 +6614,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ * individual extension, because the pattern will no longer match first. */ if (exten && exten->exten[0] == '_') { - ast_add_extension(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL, + ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar); /* rwlocks are not recursive locks */ exten = ast_hint_extension_nolock(NULL, this->context, this->exten); @@ -7159,6 +7193,25 @@ int ast_ignore_pattern(const char *context, const char *pattern) } /* + * ast_add_extension_nolock -- use only in situations where the conlock is already held + * ENOENT - no existence of context + * + */ +static int ast_add_extension_nolock(const char *context, 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 ret = -1; + struct ast_context *c = find_context(context); + + if (c) { + ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid, + application, data, datad, registrar, 0, 0); + } + + return ret; +} +/* * EBUSY - can't lock * ENOENT - no existence of context * @@ -7301,6 +7354,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; @@ -7435,8 +7499,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; } @@ -7471,6 +7540,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()). @@ -7543,7 +7625,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. */ @@ -7576,7 +7660,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 ? */ @@ -7633,9 +7719,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) { |