diff options
-rw-r--r-- | include/asterisk/pbx.h | 4 | ||||
-rw-r--r-- | main/pbx.c | 79 |
2 files changed, 51 insertions, 32 deletions
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 1e8bf56d6..41c04ce9c 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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 diff --git a/main/pbx.c b/main/pbx.c index 001a23e67..ef851706d 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -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); } /* |