aboutsummaryrefslogtreecommitdiffstats
path: root/main/pbx.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-06 14:08:54 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-06 14:08:54 +0000
commitf36c90c199831bf4240be5fffe13ed53df311cb6 (patch)
tree6a1fd6335a5024feab1f589fdd13c101a07e2833 /main/pbx.c
parentfe4629867d96d86b48165d964049f60875644c5d (diff)
Merged revisions 88805 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r88805 | russell | 2007-11-05 16:07:54 -0600 (Mon, 05 Nov 2007) | 12 lines After seeing crashes related to channel variables, I went looking around at the ways that channel variables are handled. In general, they were not handled in a thread-safe way. The channel _must_ be locked when reading or writing from/to the channel variable list. What I have done to improve this situation is to make pbx_builtin_setvar_helper() and friends lock the channel when doing their thing. Asterisk API calls almost all lock the channel for you as necessary, but this family of functions did not. (closes issue #10923, reported by atis) (closes issue #11159, reported by 850t) ........ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@88934 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/pbx.c')
-rw-r--r--main/pbx.c48
1 files changed, 37 insertions, 11 deletions
diff --git a/main/pbx.c b/main/pbx.c
index 71190ae9a..aa4459d35 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1187,6 +1187,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
if (c) {
+ ast_channel_lock(c);
places[0] = &c->varshead;
}
/*
@@ -1284,6 +1285,9 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
if (need_substring)
*ret = substring(*ret, offset, length, workspace, workspacelen);
}
+
+ if (c)
+ ast_channel_unlock(c);
}
static void exception_store_free(void *data)
@@ -5913,6 +5917,8 @@ int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **b
(*buf)->used = 0;
(*buf)->str[0] = '\0';
+ ast_channel_lock(chan);
+
AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
/* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
@@ -5926,6 +5932,8 @@ int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **b
break;
}
+ ast_channel_unlock(chan);
+
return total;
}
@@ -5938,8 +5946,11 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
if (!name)
return NULL;
- if (chan)
+
+ if (chan) {
+ ast_channel_lock(chan);
places[0] = &chan->varshead;
+ }
for (i = 0; i < 2; i++) {
if (!places[i])
@@ -5958,6 +5969,9 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
break;
}
+ if (chan)
+ ast_channel_unlock(chan);
+
return ret;
}
@@ -5974,18 +5988,25 @@ void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, cons
return;
}
- headp = (chan) ? &chan->varshead : &globals;
+ if (chan) {
+ ast_channel_lock(chan);
+ headp = &chan->varshead;
+ } else {
+ ast_rwlock_wrlock(&globalslock);
+ headp = &globals;
+ }
if (value) {
if (headp == &globals)
ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
newvariable = ast_var_assign(name, value);
- if (headp == &globals)
- ast_rwlock_wrlock(&globalslock);
AST_LIST_INSERT_HEAD(headp, newvariable, entries);
- if (headp == &globals)
- ast_rwlock_unlock(&globalslock);
}
+
+ if (chan)
+ ast_channel_unlock(chan);
+ else
+ ast_rwlock_unlock(&globalslock);
}
void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
@@ -5994,7 +6015,6 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
struct varshead *headp;
const char *nametail = name;
- /* XXX may need locking on the channel ? */
if (name[strlen(name) - 1] == ')') {
char *function = ast_strdupa(name);
@@ -6002,7 +6022,13 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
return;
}
- headp = (chan) ? &chan->varshead : &globals;
+ if (chan) {
+ ast_channel_lock(chan);
+ headp = &chan->varshead;
+ } else {
+ ast_rwlock_wrlock(&globalslock);
+ headp = &globals;
+ }
/* For comparison purposes, we have to strip leading underscores */
if (*nametail == '_') {
@@ -6011,8 +6037,6 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
nametail++;
}
- if (headp == &globals)
- ast_rwlock_wrlock(&globalslock);
AST_LIST_TRAVERSE (headp, newvariable, entries) {
if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
/* there is already such a variable, delete it */
@@ -6036,7 +6060,9 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
chan ? chan->uniqueid : "none");
}
- if (headp == &globals)
+ if (chan)
+ ast_channel_unlock(chan);
+ else
ast_rwlock_unlock(&globalslock);
}