]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Convert the contexts lock to a read/write lock to resolve a deadlock. This
authorRussell Bryant <russell@russellbryant.com>
Fri, 21 Dec 2007 16:37:47 +0000 (16:37 +0000)
committerRussell Bryant <russell@russellbryant.com>
Fri, 21 Dec 2007 16:37:47 +0000 (16:37 +0000)
has a nice side benefit of improving performance.  :)

(closes issue #11609)
(closes issue #11080)

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@94466 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/pbx.h
main/pbx.c

index 1e8bf56d699919ea202e934c5a9e0f16eb89d3dd..41c04ce9c7e5902deed41161e14691f2e714ed4b 100644 (file)
@@ -652,7 +652,9 @@ int ast_ignore_pattern(const char *context, const char *pattern);
  * \retval 0 on success 
  * \retval -1 on error
  */
-int ast_lock_contexts(void);
+int ast_lock_contexts(void); /* equivalent to wrlock */
+int ast_rdlock_contexts(void);
+int ast_wrlock_contexts(void);
 
 /*! 
  * \brief Unlocks contexts
index 001a23e6781e0f8da36718d656efca1a5a5d7786..ef851706d589217890f6b1bf3670ccb498d2099e 100644 (file)
@@ -488,7 +488,7 @@ static struct pbx_builtin {
 };
 
 static struct ast_context *contexts;
-AST_MUTEX_DEFINE_STATIC(conlock);              /*!< Lock for the ast_context list */
+AST_RWLOCK_DEFINE_STATIC(conlock);             /*!< Lock for the ast_context list */
 
 static AST_LIST_HEAD_STATIC(apps, ast_app);
 
@@ -890,12 +890,16 @@ int ast_extension_close(const char *pattern, const char *data, int needmore)
 struct ast_context *ast_context_find(const char *name)
 {
        struct ast_context *tmp = NULL;
-       ast_mutex_lock(&conlock);
+
+       ast_rdlock_contexts();
+
        while ( (tmp = ast_walk_contexts(tmp)) ) {
                if (!name || !strcasecmp(name, tmp->name))
                        break;
        }
-       ast_mutex_unlock(&conlock);
+
+       ast_unlock_contexts();
+
        return tmp;
 }
 
@@ -1800,19 +1804,19 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
 
        int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
 
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
        if (e) {
                if (matching_action) {
-                       ast_mutex_unlock(&conlock);
+                       ast_unlock_contexts();
                        return -1;      /* success, we found it */
                } else if (action == E_FINDLABEL) { /* map the label to a priority */
                        res = e->priority;
-                       ast_mutex_unlock(&conlock);
+                       ast_unlock_contexts();
                        return res;     /* the priority we were looking for */
                } else {        /* spawn */
                        app = pbx_findapp(e->app);
-                       ast_mutex_unlock(&conlock);
+                       ast_unlock_contexts();
                        if (!app) {
                                ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
                                return -1;
@@ -1847,7 +1851,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        return pbx_exec(c, app, passdata);      /* 0 on success, -1 on failure */
                }
        } else if (q.swo) {     /* not found here, but in another switch */
-               ast_mutex_unlock(&conlock);
+               ast_unlock_contexts();
                if (matching_action) {
                        return -1;
                } else {
@@ -1858,7 +1862,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
                }
        } else {        /* not found anywhere, see what happened */
-               ast_mutex_unlock(&conlock);
+               ast_unlock_contexts();
                switch (q.status) {
                case STATUS_NO_CONTEXT:
                        if (!matching_action)
@@ -1891,9 +1895,9 @@ static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *c
        struct ast_exten *e;
        struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
 
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
 
        return e;
 }
@@ -2011,7 +2015,7 @@ void ast_hint_state_changed(const char *device)
 {
        struct ast_hint *hint;
 
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        AST_LIST_LOCK(&hints);
 
        AST_LIST_TRAVERSE(&hints, hint, list) {
@@ -2049,7 +2053,7 @@ void ast_hint_state_changed(const char *device)
        }
 
        AST_LIST_UNLOCK(&hints);
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
 }
 
 /*! \brief  ast_extension_state_add: Add watcher for extension states */
@@ -2684,7 +2688,7 @@ static struct ast_context *find_context_locked(const char *context)
 {
        struct ast_context *c = NULL;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
        while ( (c = ast_walk_contexts(c)) ) {
                if (!strcmp(ast_get_context_name(c), context))
                        return c;
@@ -2907,7 +2911,7 @@ int ast_context_lockmacro(const char *context)
        struct ast_context *c = NULL;
        int ret = -1;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        while ((c = ast_walk_contexts(c))) {
                if (!strcmp(ast_get_context_name(c), context)) {
@@ -2935,7 +2939,7 @@ int ast_context_unlockmacro(const char *context)
        struct ast_context *c = NULL;
        int ret = -1;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        while ((c = ast_walk_contexts(c))) {
                if (!strcmp(ast_get_context_name(c), context)) {
@@ -3463,7 +3467,7 @@ static char *complete_show_dialplan_context(const char *line, const char *word,
        if (pos != 2)
                return NULL;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        wordlen = strlen(word);
 
@@ -3508,7 +3512,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
        struct ast_context *c = NULL;
        int res = 0, old_total_exten = dpc->total_exten;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        /* walk all contexts ... */
        while ( (c = ast_walk_contexts(c)) ) {
@@ -3861,7 +3865,7 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
        int length = sizeof(struct ast_context) + strlen(name) + 1;
 
        if (!extcontexts) {
-               ast_mutex_lock(&conlock);
+               ast_rdlock_contexts();
                local_contexts = &contexts;
        } else
                local_contexts = extcontexts;
@@ -3873,28 +3877,31 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
                                tmp = NULL;
                        }
                        if (!extcontexts)
-                               ast_mutex_unlock(&conlock);
+                               ast_unlock_contexts();
                        return tmp;
                }
        }
+       
+       if (!extcontexts)
+               ast_unlock_contexts();
+
        if ((tmp = ast_calloc(1, length))) {
                ast_mutex_init(&tmp->lock);
                ast_mutex_init(&tmp->macrolock);
                strcpy(tmp->name, name);
-               tmp->root = NULL;
                tmp->registrar = registrar;
+               if (!extcontexts)
+                       ast_wrlock_contexts();
                tmp->next = *local_contexts;
-               tmp->includes = NULL;
-               tmp->ignorepats = NULL;
                *local_contexts = tmp;
+               if (!extcontexts)
+                       ast_unlock_contexts();
                if (option_debug)
                        ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
                if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
        }
 
-       if (!extcontexts)
-               ast_mutex_unlock(&conlock);
        return tmp;
 }
 
@@ -3939,7 +3946,7 @@ 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
        */
-       ast_mutex_lock(&conlock);
+       ast_wrlock_contexts();
        AST_LIST_LOCK(&hints);
 
        /* preserve all watchers for hints associated with this registrar */
@@ -4017,7 +4024,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
        }
 
        AST_LIST_UNLOCK(&hints);
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
 
        return;
 }
@@ -5289,7 +5296,6 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
        struct ast_exten *e, *el, *en;
        struct ast_ignorepat *ipi;
 
-       ast_mutex_lock(&conlock);
        for (tmp = contexts; tmp; ) {
                struct ast_context *next;       /* next starting point */
                for (; tmp; tmpl = tmp, tmp = tmp->next) {
@@ -5339,12 +5345,13 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
                /* if we have a specific match, we are done, otherwise continue */
                tmp = con ? NULL : next;
        }
-       ast_mutex_unlock(&conlock);
 }
 
 void ast_context_destroy(struct ast_context *con, const char *registrar)
 {
+       ast_wrlock_contexts();
        __ast_context_destroy(con,registrar);
+       ast_unlock_contexts();
 }
 
 static void wait_for_hangup(struct ast_channel *chan, void *data)
@@ -6112,12 +6119,22 @@ int load_pbx(void)
  */
 int ast_lock_contexts()
 {
-       return ast_mutex_lock(&conlock);
+       return ast_rwlock_wrlock(&conlock);
+}
+
+int ast_rdlock_contexts(void)
+{
+       return ast_rwlock_rdlock(&conlock);
+}
+
+int ast_wrlock_contexts(void)
+{
+       return ast_rwlock_wrlock(&conlock);
 }
 
 int ast_unlock_contexts()
 {
-       return ast_mutex_unlock(&conlock);
+       return ast_rwlock_unlock(&conlock);
 }
 
 /*