[asterisk-commits] russell: branch 1.4 r116038 - /branches/1.4/channels/chan_local.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 13 16:17:23 CDT 2008


Author: russell
Date: Tue May 13 16:17:23 2008
New Revision: 116038

URL: http://svn.digium.com/view/asterisk?view=rev&rev=116038
Log:
Fix a deadlock involving channel autoservice and chan_local that was debugged
and fixed by mmichelson and me.

We observed a system that had a bunch of threads stuck in ast_autoservice_stop().
The reason these threads were waiting around is because this function waits to
ensure that the channel list in the autoservice thread gets rebuilt before the
stop() function returns.  However, the autoservice thread was also locked, so
the autoservice channel list was never getting rebuilt.

The autoservice thread was stuck waiting for the channel lock on a local channel.
However, the local channel was locked by a thread that was stuck in the autoservice
stop function.

It turned out that the issue came down to the local_queue_frame() function in
chan_local.  This function assumed that one of the channels passed in as an
argument was locked when called.  However, that was not always the case.  There
were multiple cases in which this channel was not locked when the function was
called.  We fixed up chan_local to indicate to this function whether this channel
was locked or not.  The previous assumption had caused local_queue_frame() to
improperly return with the channel locked, where it would then never get unlocked.

(closes issue #12584)
(related to issue #12603)

Modified:
    branches/1.4/channels/chan_local.c

Modified: branches/1.4/channels/chan_local.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/channels/chan_local.c?view=diff&rev=116038&r1=116037&r2=116038
==============================================================================
--- branches/1.4/channels/chan_local.c (original)
+++ branches/1.4/channels/chan_local.c Tue May 13 16:17:23 2008
@@ -160,7 +160,8 @@
 	return NULL;
 }
 
-static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
+static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, 
+	struct ast_channel *us, int us_locked)
 {
 	struct ast_channel *other = NULL;
 
@@ -184,11 +185,13 @@
 	/* Ensure that we have both channels locked */
 	while (other && ast_channel_trylock(other)) {
 		ast_mutex_unlock(&p->lock);
-		if (us)
+		if (us && us_locked) {
 			ast_channel_unlock(us);
+		}
 		usleep(1);
-		if (us)
+		if (us && us_locked) {
 			ast_channel_lock(us);
+		}
 		ast_mutex_lock(&p->lock);
 		other = isoutbound ? p->owner : p->chan;
 	}
@@ -217,7 +220,7 @@
 	if (isoutbound) {
 		/* Pass along answer since somebody answered us */
 		struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
-		res = local_queue_frame(p, isoutbound, &answer, ast);
+		res = local_queue_frame(p, isoutbound, &answer, ast, 1);
 	} else
 		ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
 	if (!res)
@@ -306,7 +309,7 @@
 	if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
 		check_bridge(p, isoutbound);
 	if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
-		res = local_queue_frame(p, isoutbound, f, ast);
+		res = local_queue_frame(p, isoutbound, f, ast, 1);
 	else {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
@@ -361,7 +364,7 @@
 		f.subclass = condition;
 		f.data = (void*)data;
 		f.datalen = datalen;
-		if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
+		if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
 			ast_mutex_unlock(&p->lock);
 	}
 
@@ -381,7 +384,7 @@
 	ast_mutex_lock(&p->lock);
 	isoutbound = IS_OUTBOUND(ast, p);
 	f.subclass = digit;
-	if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
+	if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
 		ast_mutex_unlock(&p->lock);
 
 	return res;
@@ -401,7 +404,7 @@
 	isoutbound = IS_OUTBOUND(ast, p);
 	f.subclass = digit;
 	f.len = duration;
-	if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
+	if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
 		ast_mutex_unlock(&p->lock);
 
 	return res;
@@ -421,7 +424,7 @@
 	isoutbound = IS_OUTBOUND(ast, p);
 	f.data = (char *) text;
 	f.datalen = strlen(text) + 1;
-	if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
+	if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
 		ast_mutex_unlock(&p->lock);
 	return res;
 }
@@ -441,7 +444,7 @@
 	f.subclass = subclass;
 	f.data = (char *)data;
 	f.datalen = datalen;
-	if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
+	if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
 		ast_mutex_unlock(&p->lock);
 	return res;
 }
@@ -564,7 +567,7 @@
 		/* Need to actually hangup since there is no PBX */
 		ochan = p->chan;
 	else
-		res = local_queue_frame(p, isoutbound, &f, NULL);
+		res = local_queue_frame(p, isoutbound, &f, NULL, 1);
 	if (!res)
 		ast_mutex_unlock(&p->lock);
 	if (ochan)




More information about the asterisk-commits mailing list