[asterisk-commits] russell: branch 1.4 r105409 - /branches/1.4/main/autoservice.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Feb 29 17:34:32 CST 2008


Author: russell
Date: Fri Feb 29 17:34:32 2008
New Revision: 105409

URL: http://svn.digium.com/view/asterisk?view=rev&rev=105409
Log:
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
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)

Modified:
    branches/1.4/main/autoservice.c

Modified: branches/1.4/main/autoservice.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/main/autoservice.c?view=diff&rev=105409&r1=105408&r2=105409
==============================================================================
--- branches/1.4/main/autoservice.c (original)
+++ branches/1.4/main/autoservice.c Fri Feb 29 17:34:32 2008
@@ -67,6 +67,8 @@
 
 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 @@
 		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 @@
 	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 @@
 		ast_frfree(f);
 	}
 
+	while (chan_list_state == as_chan_list_state)
+		usleep(1000);
+
 	return res;
 }




More information about the asterisk-commits mailing list