From ed61d214191f5ecc7a00ae01a89cb8d9cd501872 Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Thu, 5 Sep 2013 17:10:28 +0000
Subject: [PATCH] chan_iax2: Fix bridgecallno deadlock avoidance.

* Fix bridgecallno deadlock avoidance.  When doing deadlock avoidance, you
need to retest the status of values for each loop to see if you still need
the lock for bridgecallno.

* As a safety check, after acquiring the bridgecallno lock you should
check if iaxs[bridgecallno] is NULL just like the current callno checks.

* Move setting thread->iostate to IAX_IOSTATE_IDLE to after processing any
deferred frames to ensure that the iostate is IDLE when it is placed back
into the idle list.  defer_full_frame() tries to ensure
iax2_process_thread() wakes up to process the frame.
........

Merged revisions 398379 from http://svn.asterisk.org/svn/asterisk/branches/1.8


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@398380 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_iax2.c | 55 +++++++++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 26 deletions(-)

diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 21bd1fc2e7..05e88b9b64 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -810,7 +810,7 @@ struct chan_iax2_pvt {
 	/*! Status of knowledge of peer ADSI capability */
 	int peeradsicpe;
 
-	/*! Who we are bridged to */
+	/*! Callno of native bridge peer. (Valid if nonzero) */
 	unsigned short bridgecallno;
 
 	int pingid;			/*!< Transmit PING request */
@@ -11510,13 +11510,13 @@ immediatedial:
 				}
 				break;
 			case IAX_COMMAND_TXREJ:
-				if (iaxs[fr->callno]->bridgecallno) {
-					while (ast_mutex_trylock(&iaxsl[iaxs[fr->callno]->bridgecallno])) {
-						DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
-					}
-					if (!iaxs[fr->callno]) {
-						break;
-					}
+				while (iaxs[fr->callno]
+					&& iaxs[fr->callno]->bridgecallno
+					&& ast_mutex_trylock(&iaxsl[iaxs[fr->callno]->bridgecallno])) {
+					DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
+				}
+				if (!iaxs[fr->callno]) {
+					break;
 				}
 
 				iaxs[fr->callno]->transferring = TRANSFER_NONE;
@@ -11527,20 +11527,21 @@ immediatedial:
 					break;
 				}
 
-				if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
+				if (iaxs[iaxs[fr->callno]->bridgecallno]
+					&& iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
 					iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE;
 					send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
 				}
 				ast_mutex_unlock(&iaxsl[iaxs[fr->callno]->bridgecallno]);
 				break;
 			case IAX_COMMAND_TXREADY:
-				if (iaxs[fr->callno]->bridgecallno) {
-					while (ast_mutex_trylock(&iaxsl[iaxs[fr->callno]->bridgecallno])) {
-						DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
-					}
-					if (!iaxs[fr->callno]) {
-						break;
-					}
+				while (iaxs[fr->callno]
+					&& iaxs[fr->callno]->bridgecallno
+					&& ast_mutex_trylock(&iaxsl[iaxs[fr->callno]->bridgecallno])) {
+					DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
+				}
+				if (!iaxs[fr->callno]) {
+					break;
 				}
 
 				if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) {
@@ -11559,8 +11560,9 @@ immediatedial:
 					break;
 				}
 
-				if (!(iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_READY) &&
-				    !(iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_MREADY)) {
+				if (!iaxs[iaxs[fr->callno]->bridgecallno]
+					|| (iaxs[iaxs[fr->callno]->bridgecallno]->transferring != TRANSFER_READY
+						&& iaxs[iaxs[fr->callno]->bridgecallno]->transferring != TRANSFER_MREADY)) {
 					ast_mutex_unlock(&iaxsl[iaxs[fr->callno]->bridgecallno]);
 					break;
 				}
@@ -11944,11 +11946,10 @@ static void *iax2_process_thread(void *data)
 			break;
 		}
 
-		if (thread->iostate == IAX_IOSTATE_IDLE)
-			continue;
-
 		/* See what we need to do */
 		switch (thread->iostate) {
+		case IAX_IOSTATE_IDLE:
+			continue;
 		case IAX_IOSTATE_READY:
 			thread->actions++;
 			thread->iostate = IAX_IOSTATE_PROCESSING;
@@ -11961,14 +11962,10 @@ static void *iax2_process_thread(void *data)
 #ifdef SCHED_MULTITHREADED
 			thread->schedfunc(thread->scheddata);
 #endif		
+			break;
 		default:
 			break;
 		}
-		time(&thread->checktime);
-		thread->iostate = IAX_IOSTATE_IDLE;
-#ifdef DEBUG_SCHED_MULTITHREAD
-		thread->curfunc[0]='\0';
-#endif		
 
 		/* The network thread added us to the active_thread list when we were given
 		 * frames to process, Now that we are done, we must remove ourselves from
@@ -11979,6 +11976,12 @@ static void *iax2_process_thread(void *data)
 
 		/* Make sure another frame didn't sneak in there after we thought we were done. */
 		handle_deferred_full_frames(thread);
+
+		time(&thread->checktime);
+		thread->iostate = IAX_IOSTATE_IDLE;
+#ifdef DEBUG_SCHED_MULTITHREAD
+		thread->curfunc[0]='\0';
+#endif
 	}
 
 	/*!
-- 
GitLab