diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-11-06 14:08:54 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-11-06 14:08:54 +0000 |
commit | f36c90c199831bf4240be5fffe13ed53df311cb6 (patch) | |
tree | 6a1fd6335a5024feab1f589fdd13c101a07e2833 | |
parent | fe4629867d96d86b48165d964049f60875644c5d (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
-rw-r--r-- | channels/busy.h | 18 | ||||
-rw-r--r-- | channels/ringtone.h | 18 | ||||
-rw-r--r-- | include/asterisk/pbx.h | 25 | ||||
-rw-r--r-- | main/pbx.c | 48 |
4 files changed, 62 insertions, 47 deletions
diff --git a/channels/busy.h b/channels/busy.h index 22d327931..6e5db8e47 100644 --- a/channels/busy.h +++ b/channels/busy.h @@ -1,21 +1,3 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2007, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - /* busy.h: Generated from frequencies 480 and 620 by gentone. 400 samples */ static short busy[400] = { diff --git a/channels/ringtone.h b/channels/ringtone.h index 7750c0e77..559c42a7b 100644 --- a/channels/ringtone.h +++ b/channels/ringtone.h @@ -1,21 +1,3 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2007, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - /* ringtone.h: Generated from frequencies 440 and 480 by gentone. 200 samples */ static short ringtone[200] = { diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 2b6ad75e6..645c8eedd 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -850,14 +850,39 @@ struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip); struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); +/*! + * \note Will lock the channel. + */ int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf); + +/*! + * \note Will lock the channel. + */ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name); + +/*! + * \note Will lock the channel. + */ void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value); + +/*! + * \note Will lock the channel. + */ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value); + +/*! + * \note Will lock the channel. + */ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp); void pbx_builtin_clear_globals(void); + +/*! + * \note Will lock the channel. + */ int pbx_builtin_setvar(struct ast_channel *chan, void *data); + int pbx_builtin_raise_exception(struct ast_channel *chan, void *data); + void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count); void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count); 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); } |