diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-02-29 23:34:32 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-02-29 23:34:32 +0000 |
commit | e877f3be1961d705c370c5ffbb148852afd63888 (patch) | |
tree | e4b4f6f347874e88ddb140e7058d40c2d9583389 | |
parent | e546d5f67d70b2f37a9b7015a3d97130e5cd5905 (diff) |
Fix a major bug in autoservice. There was a race condition in the handling of
the list of channels in autoservice. The problem was that it was possible for
a channel to get removed from autoservice and destroyed, while the autoservice
thread was still messing with the channel. This led to memory corruption, and
caused crashes. This explains multiple backtraces I have seen that have
references to autoservice, but do to the nature of the issue (memory corruption),
could cause crashes in a number of areas.
(fixes the crash in BE-386)
(closes issue #11694)
(closes issue #11940)
The following issues could be related. If you are the reporter of one of these,
please update to include this fix and try again.
(potentially fixes issue #11189)
(potentially fixes issue #12107)
(potentially fixes issue #11573)
(potentially fixes issue #12008)
(potentially fixes issue #11189)
(potentially fixes issue #11993)
(potentially fixes issue #11791)
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@105409 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | main/autoservice.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/main/autoservice.c b/main/autoservice.c index 140103dba..0a641e97c 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -67,6 +67,8 @@ static AST_LIST_HEAD_STATIC(aslist, asent); static pthread_t asthread = AST_PTHREADT_NULL; +static int as_chan_list_state; + static void defer_frame(struct ast_channel *chan, struct ast_frame *f) { struct ast_frame *dup_f; @@ -91,6 +93,11 @@ static void *autoservice_run(void *ign) int x = 0, ms = 500; AST_LIST_LOCK(&aslist); + + /* At this point, we know that no channels that have been removed are going + * to get used again. */ + as_chan_list_state++; + AST_LIST_TRAVERSE(&aslist, as, list) { if (!as->chan->_softhangup) { if (x < MAX_AUTOMONS) @@ -215,10 +222,18 @@ int ast_autoservice_stop(struct ast_channel *chan) struct ast_frame *f; int removed = 0; int orig_end_dtmf_flag = 0; + int chan_list_state; AST_LIST_HEAD_INIT_NOLOCK(&dtmf_frames); AST_LIST_LOCK(&aslist); + + /* Save the autoservice channel list state. We _must_ verify that the channel + * list has been rebuilt before we return. Because, after we return, the channel + * could get destroyed and we don't want our poor autoservice thread to step on + * it after its gone! */ + chan_list_state = as_chan_list_state; + AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) { if (as->chan == chan) { as->use_count--; @@ -256,5 +271,8 @@ int ast_autoservice_stop(struct ast_channel *chan) ast_frfree(f); } + while (chan_list_state == as_chan_list_state) + usleep(1000); + return res; } |