[asterisk-commits] dlee: branch dlee/ASTERISK-194630-startup-deadlock r398668 - in /team/dlee/AS...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Sep 9 15:21:29 CDT 2013


Author: dlee
Date: Mon Sep  9 15:21:25 2013
New Revision: 398668

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=398668
Log:
Merged revisions 398301-398648 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    team/dlee/ASTERISK-194630-startup-deadlock/   (props changed)
    team/dlee/ASTERISK-194630-startup-deadlock/channels/chan_iax2.c
    team/dlee/ASTERISK-194630-startup-deadlock/channels/iax2-parser.c
    team/dlee/ASTERISK-194630-startup-deadlock/include/asterisk/lock.h
    team/dlee/ASTERISK-194630-startup-deadlock/main/lock.c
    team/dlee/ASTERISK-194630-startup-deadlock/main/utils.c
    team/dlee/ASTERISK-194630-startup-deadlock/res/res_jabber.c

Propchange: team/dlee/ASTERISK-194630-startup-deadlock/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Sep  9 15:21:25 2013
@@ -1,1 +1,1 @@
-/branches/1.8:1-398279
+/branches/1.8:1-398664

Modified: team/dlee/ASTERISK-194630-startup-deadlock/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/channels/chan_iax2.c?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/channels/chan_iax2.c (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/channels/chan_iax2.c Mon Sep  9 15:21:25 2013
@@ -806,7 +806,7 @@
 	/*! 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 */
@@ -1460,12 +1460,11 @@
 #ifdef SCHED_MULTITHREADED
 static int __schedule_action(void (*func)(const void *data), const void *data, const char *funcname)
 {
-	struct iax2_thread *thread = NULL;
+	struct iax2_thread *thread;
 	static time_t lasterror;
-	static time_t t;
+	time_t t;
 
 	thread = find_idle_thread();
-
 	if (thread != NULL) {
 		thread->schedfunc = func;
 		thread->scheddata = data;
@@ -1477,9 +1476,10 @@
 		return 0;
 	}
 	time(&t);
-	if (t != lasterror) 
-		ast_debug(1, "Out of idle IAX2 threads for scheduling!\n");
-	lasterror = t;
+	if (t != lasterror) {
+		lasterror = t;
+		ast_debug(1, "Out of idle IAX2 threads for scheduling! (%s)\n", funcname);
+	}
 
 	return -1;
 }
@@ -3489,42 +3489,49 @@
 	struct iax_frame *f = (struct iax_frame *)data;
 	int freeme = 0;
 	int callno = f->callno;
+
 	/* Make sure this call is still active */
 	if (callno) 
 		ast_mutex_lock(&iaxsl[callno]);
 	if (callno && iaxs[callno]) {
-		if ((f->retries < 0) /* Already ACK'd */ ||
-		    (f->retries >= max_retries) /* Too many attempts */) {
-				/* Record an error if we've transmitted too many times */
-				if (f->retries >= max_retries) {
-					if (f->transfer) {
-						/* Transfer timeout */
-						send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
-					} else if (f->final) {
-						iax2_destroy(callno);
-					} else {
-						if (iaxs[callno]->owner)
-							ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass.integer, f->ts, f->oseqno);
-						iaxs[callno]->error = ETIMEDOUT;
-						if (iaxs[callno]->owner) {
-							struct ast_frame fr = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
-							/* Hangup the fd */
-							iax2_queue_frame(callno, &fr); /* XXX */
-							/* Remember, owner could disappear */
-							if (iaxs[callno] && iaxs[callno]->owner)
-								iaxs[callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
-						} else {
-							if (iaxs[callno]->reg) {
-								memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
-								iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
-								iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
-							}
-							iax2_destroy(callno);
-						}
+		if (f->retries < 0) {
+			/* Already ACK'd */
+			freeme = 1;
+		} else if (f->retries >= max_retries) {
+			/* Too many attempts.  Record an error. */
+			if (f->transfer) {
+				/* Transfer timeout */
+				send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
+			} else if (f->final) {
+				iax2_destroy(callno);
+			} else {
+				if (iaxs[callno]->owner) {
+					ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n",
+						ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),
+						iaxs[f->callno]->owner->name,
+						f->af.frametype,
+						f->af.subclass.integer,
+						f->ts,
+						f->oseqno);
+				}
+				iaxs[callno]->error = ETIMEDOUT;
+				if (iaxs[callno]->owner) {
+					struct ast_frame fr = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
+					/* Hangup the fd */
+					iax2_queue_frame(callno, &fr); /* XXX */
+					/* Remember, owner could disappear */
+					if (iaxs[callno] && iaxs[callno]->owner)
+						iaxs[callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
+				} else {
+					if (iaxs[callno]->reg) {
+						memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
+						iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
+						iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
 					}
-
+					iax2_destroy(callno);
 				}
-				freeme = 1;
+			}
+			freeme = 1;
 		} else {
 			/* Update it if it needs it */
 			update_packet(f);
@@ -8661,8 +8668,6 @@
 	return 0;
 }
 
-static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-
 static void reg_source_db(struct iax2_peer *p)
 {
 	char data[80];
@@ -9625,9 +9630,10 @@
 
 	if (!(thread = find_idle_thread())) {
 		time(&t);
-		if (t != last_errtime)
+		if (t != last_errtime) {
+			last_errtime = t;
 			ast_debug(1, "Out of idle IAX2 threads for I/O, pausing!\n");
-		last_errtime = t;
+		}
 		usleep(1);
 		return 1;
 	}
@@ -11369,13 +11375,13 @@
 				}
 				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;
@@ -11386,20 +11392,21 @@
 					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) {
@@ -11418,8 +11425,9 @@
 					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;
 				}
@@ -11545,13 +11553,14 @@
 			}
 
 			/* Don't actually pass these frames along */
-			if ((f.subclass.integer != IAX_COMMAND_ACK) && 
-			  (f.subclass.integer != IAX_COMMAND_TXCNT) && 
-			  (f.subclass.integer != IAX_COMMAND_TXACC) && 
-			  (f.subclass.integer != IAX_COMMAND_INVAL) &&
-			  (f.subclass.integer != IAX_COMMAND_VNAK)) { 
-			  	if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno)
+			if ((f.subclass.integer != IAX_COMMAND_ACK) &&
+				(f.subclass.integer != IAX_COMMAND_TXCNT) &&
+				(f.subclass.integer != IAX_COMMAND_TXACC) &&
+				(f.subclass.integer != IAX_COMMAND_INVAL) &&
+				(f.subclass.integer != IAX_COMMAND_VNAK)) {
+				if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno) {
 					send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
+				}
 			}
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
@@ -11670,8 +11679,9 @@
 		/*iaxs[fr->callno]->last = fr->ts; (do it afterwards cos schedule/forward_delivery needs the last ts too)*/
 		fr->outoforder = 0;
 	} else {
-		if (iaxdebug && iaxs[fr->callno])
+		if (iaxdebug && iaxs[fr->callno]) {
 			ast_debug(1, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass.integer, fr->ts, iaxs[fr->callno]->last);
+		}
 		fr->outoforder = -1;
 	}
 	fr->cacheable = ((f.frametype == AST_FRAME_VOICE) || (f.frametype == AST_FRAME_VIDEO));
@@ -11789,11 +11799,10 @@
 			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;
@@ -11806,14 +11815,10 @@
 #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
@@ -11824,12 +11829,18 @@
 
 		/* 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
 	}
 
 	/*!
-	 * \note For some reason, idle threads are exiting without being removed
-	 * from an idle list, which is causing memory corruption.  Forcibly remove
-	 * it from the list, if it's there.
+	 * \note For some reason, idle threads are exiting without being
+	 * removed from an idle list, which is causing memory
+	 * corruption.  Forcibly remove it from the list, if it's there.
 	 */
 	AST_LIST_LOCK(&idle_list);
 	AST_LIST_REMOVE(&idle_list, thread, list);
@@ -14098,7 +14109,7 @@
 		return res;
 
 	res = AST_DEVICE_UNAVAILABLE;
-	ast_debug(3, "iax2_devicestate: Found peer. What's device state of %s? addr=%d, defaddr=%d maxms=%d, lastms=%d\n",
+	ast_debug(3, "Found peer. What's device state of %s? addr=%d, defaddr=%d maxms=%d, lastms=%d\n",
 		pds.peer, ast_sockaddr_ipv4(&p->addr), p->defaddr.sin_addr.s_addr, p->maxms, p->lastms);
 	
 	if ((ast_sockaddr_ipv4(&p->addr) || p->defaddr.sin_addr.s_addr) &&
@@ -14387,7 +14398,7 @@
 	struct iax2_thread *thread;
 
 	AST_LIST_LOCK(list_head);
-	while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, list))) {
+	while ((thread = AST_LIST_REMOVE_HEAD(list_head, list))) {
 		pthread_t thread_id = thread->threadid;
 
 		thread->stop = 1;
@@ -14429,9 +14440,9 @@
 	}
 
 	/* Call for all threads to halt */
-	cleanup_thread_list(&idle_list);
 	cleanup_thread_list(&active_list);
 	cleanup_thread_list(&dynamic_list);
+	cleanup_thread_list(&idle_list);
 
 	ast_netsock_release(netsock);
 	ast_netsock_release(outsock);

Modified: team/dlee/ASTERISK-194630-startup-deadlock/channels/iax2-parser.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/channels/iax2-parser.c?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/channels/iax2-parser.c (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/channels/iax2-parser.c Mon Sep  9 15:21:25 2013
@@ -239,11 +239,12 @@
 	dump_prov_ies(output, maxlen, value, len);
 }
 
-static struct iax2_ie {
+struct iax2_ie {
 	int ie;
 	char *name;
 	void (*dump)(char *output, int maxlen, void *value, int len);
-} infoelts[] = {
+};
+static struct iax2_ie infoelts[] = {
 	{ IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
 	{ IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
 	{ IAX_IE_CALLING_ANI, "ANI", dump_string },
@@ -392,6 +393,7 @@
 	int found;
 	char interp[1024];
 	char tmp[1024];
+
 	if (len < 2)
 		return;
 	while(len > 2) {
@@ -604,6 +606,14 @@
 		"TXFER  ",
 		"CNLINE ",
 		"REDIR  ",
+		"T38PARM",
+		"CC ERR!",/* This must never go across an IAX link. */
+		"SRCCHG ",
+		"READACT",
+		"AOC    ",
+		"ENDOFQ ",
+		"INCOMPL",
+		"UPDRTPP",
 	};
 	struct ast_iax2_full_hdr *fh;
 	char retries[20];

Modified: team/dlee/ASTERISK-194630-startup-deadlock/include/asterisk/lock.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/include/asterisk/lock.h?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/include/asterisk/lock.h (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/include/asterisk/lock.h Mon Sep  9 15:21:25 2013
@@ -281,12 +281,16 @@
 #else
 void ast_remove_lock_info(void *lock_addr);
 #endif /* HAVE_BKTR */
+void ast_suspend_lock_info(void *lock_addr);
+void ast_restore_lock_info(void *lock_addr);
 #else
 #ifdef HAVE_BKTR
 #define ast_remove_lock_info(ignore,me)
 #else
 #define ast_remove_lock_info(ignore)
 #endif /* HAVE_BKTR */
+#define ast_suspend_lock_info(ignore);
+#define ast_restore_lock_info(ignore);
 #endif /* !defined(LOW_MEMORY) */
 
 /*!

Modified: team/dlee/ASTERISK-194630-startup-deadlock/main/lock.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/main/lock.c?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/main/lock.c (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/main/lock.c Mon Sep  9 15:21:25 2013
@@ -265,12 +265,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
 #else
 		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
@@ -394,12 +402,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
 #else
 		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
@@ -548,10 +564,8 @@
 
 #ifdef DEBUG_THREADS
 	struct ast_lock_track *lt = NULL;
+	struct ast_lock_track lt_orig;
 	int canlog = strcmp(filename, "logger.c") & t->tracking;
-#ifdef HAVE_BKTR
-	struct ast_bt *bt = NULL;
-#endif
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -581,33 +595,20 @@
 			__dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
 			DO_THREAD_CRASH;
-		}
-
-		if (--lt->reentrancy < 0) {
-			__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-				   filename, lineno, func, mutex_name);
-			lt->reentrancy = 0;
-		}
-
-		if (lt->reentrancy < AST_MAX_REENTRANCY) {
-			lt->file[lt->reentrancy] = NULL;
-			lt->lineno[lt->reentrancy] = 0;
-			lt->func[lt->reentrancy] = NULL;
-			lt->thread[lt->reentrancy] = 0;
-		}
-
-#ifdef HAVE_BKTR
-		if (lt->reentrancy) {
-			bt = &lt->backtrace[lt->reentrancy - 1];
-		}
-#endif
-		ast_reentrancy_unlock(lt);
-
-#ifdef HAVE_BKTR
-		ast_remove_lock_info(t, bt);
-#else
-		ast_remove_lock_info(t);
-#endif
+		} else if (lt->reentrancy <= 0) {
+			__ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
+					   filename, lineno, func, mutex_name);
+			DO_THREAD_CRASH;
+		}
+
+		/* Waiting on a condition completely suspends a recursive mutex,
+		 * even if it's been recursively locked multiple times. Make a
+		 * copy of the lock tracking, and reset reentrancy to zero */
+		lt_orig = *lt;
+		lt->reentrancy = 0;
+		ast_reentrancy_unlock(lt);
+
+		ast_suspend_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
 
@@ -619,28 +620,16 @@
 				   filename, lineno, func, strerror(res));
 		DO_THREAD_CRASH;
 	} else if (lt) {
-		ast_reentrancy_lock(lt);
-		if (lt->reentrancy < AST_MAX_REENTRANCY) {
-			lt->file[lt->reentrancy] = filename;
-			lt->lineno[lt->reentrancy] = lineno;
-			lt->func[lt->reentrancy] = func;
-			lt->thread[lt->reentrancy] = pthread_self();
-#ifdef HAVE_BKTR
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
-			bt = &lt->backtrace[lt->reentrancy];
-#endif
-			lt->reentrancy++;
-		} else {
-			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-							   filename, lineno, func, mutex_name);
-		}
-		ast_reentrancy_unlock(lt);
-
-#ifdef HAVE_BKTR
-		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
-#else
-		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
-#endif
+		pthread_mutex_t reentr_mutex_orig;
+		ast_reentrancy_lock(lt);
+		/* Restore lock tracking to what it was prior to the wait */
+		reentr_mutex_orig = lt->reentr_mutex;
+		*lt = lt_orig;
+		/* un-trash the mutex we just copied over */
+		lt->reentr_mutex = reentr_mutex_orig;
+		ast_reentrancy_unlock(lt);
+
+		ast_restore_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
 
@@ -655,10 +644,8 @@
 
 #ifdef DEBUG_THREADS
 	struct ast_lock_track *lt = NULL;
+	struct ast_lock_track lt_orig;
 	int canlog = strcmp(filename, "logger.c") & t->tracking;
-#ifdef HAVE_BKTR
-	struct ast_bt *bt = NULL;
-#endif
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
 	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -688,32 +675,20 @@
 			__dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
 			DO_THREAD_CRASH;
-		}
-
-		if (--lt->reentrancy < 0) {
-			__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+		} else if (lt->reentrancy <= 0) {
+			__ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
 					   filename, lineno, func, mutex_name);
-			lt->reentrancy = 0;
-		}
-
-		if (lt->reentrancy < AST_MAX_REENTRANCY) {
-			lt->file[lt->reentrancy] = NULL;
-			lt->lineno[lt->reentrancy] = 0;
-			lt->func[lt->reentrancy] = NULL;
-			lt->thread[lt->reentrancy] = 0;
-		}
-#ifdef HAVE_BKTR
-		if (lt->reentrancy) {
-			bt = &lt->backtrace[lt->reentrancy - 1];
-		}
-#endif
-		ast_reentrancy_unlock(lt);
-
-#ifdef HAVE_BKTR
-		ast_remove_lock_info(t, bt);
-#else
-		ast_remove_lock_info(t);
-#endif
+			DO_THREAD_CRASH;
+		}
+
+		/* Waiting on a condition completely suspends a recursive mutex,
+		 * even if it's been recursively locked multiple times. Make a
+		 * copy of the lock tracking, and reset reentrancy to zero */
+		lt_orig = *lt;
+		lt->reentrancy = 0;
+		ast_reentrancy_unlock(lt);
+
+		ast_suspend_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
 
@@ -725,28 +700,16 @@
 				   filename, lineno, func, strerror(res));
 		DO_THREAD_CRASH;
 	} else if (lt) {
-		ast_reentrancy_lock(lt);
-		if (lt->reentrancy < AST_MAX_REENTRANCY) {
-			lt->file[lt->reentrancy] = filename;
-			lt->lineno[lt->reentrancy] = lineno;
-			lt->func[lt->reentrancy] = func;
-			lt->thread[lt->reentrancy] = pthread_self();
-#ifdef HAVE_BKTR
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
-			bt = &lt->backtrace[lt->reentrancy];
-#endif
-			lt->reentrancy++;
-		} else {
-			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-							   filename, lineno, func, mutex_name);
-		}
-		ast_reentrancy_unlock(lt);
-
-#ifdef HAVE_BKTR
-		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
-#else
-		ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
-#endif
+		pthread_mutex_t reentr_mutex_orig;
+		ast_reentrancy_lock(lt);
+		/* Restore lock tracking to what it was prior to the wait */
+		reentr_mutex_orig = lt->reentr_mutex;
+		*lt = lt_orig;
+		/* un-trash the mutex we just copied over */
+		lt->reentr_mutex = reentr_mutex_orig;
+		ast_reentrancy_unlock(lt);
+
+		ast_suspend_lock_info(t);
 	}
 #endif /* DEBUG_THREADS */
 
@@ -946,12 +909,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
@@ -1062,12 +1033,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1178,12 +1157,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1278,12 +1265,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1377,12 +1372,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
@@ -1444,12 +1447,20 @@
 
 	if (lt) {
 #ifdef HAVE_BKTR
+		struct ast_bt tmp;
+
+		/* The implementation of backtrace() may have its own locks.
+		 * Capture the backtrace outside of the reentrancy lock to
+		 * avoid deadlocks. See ASTERISK-22455. */
+		ast_bt_get_addresses(&tmp);
+
 		ast_reentrancy_lock(lt);
 		if (lt->reentrancy != AST_MAX_REENTRANCY) {
-			ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+			lt->backtrace[lt->reentrancy] = tmp;
 			bt = &lt->backtrace[lt->reentrancy];
 		}
 		ast_reentrancy_unlock(lt);
+
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
 		ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);

Modified: team/dlee/ASTERISK-194630-startup-deadlock/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/main/utils.c?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/main/utils.c (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/main/utils.c Mon Sep  9 15:21:25 2013
@@ -585,6 +585,8 @@
 		enum ast_lock_type type;
 		/*! This thread is waiting on this lock */
 		int pending:2;
+		/*! A condition has suspended this lock */
+		int suspended:1;
 #ifdef HAVE_BKTR
 		struct ast_bt *backtrace;
 #endif
@@ -771,6 +773,60 @@
 	return 0;
 }
 
+void ast_suspend_lock_info(void *lock_addr)
+{
+	struct thr_lock_info *lock_info;
+	int i = 0;
+
+	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) {
+		return;
+	}
+
+	pthread_mutex_lock(&lock_info->lock);
+
+	for (i = lock_info->num_locks - 1; i >= 0; i--) {
+		if (lock_info->locks[i].lock_addr == lock_addr)
+			break;
+	}
+
+	if (i == -1) {
+		/* Lock not found :( */
+		pthread_mutex_unlock(&lock_info->lock);
+		return;
+	}
+
+	lock_info->locks[i].suspended = 1;
+
+	pthread_mutex_unlock(&lock_info->lock);
+}
+
+void ast_restore_lock_info(void *lock_addr)
+{
+	struct thr_lock_info *lock_info;
+	int i = 0;
+
+	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
+		return;
+
+	pthread_mutex_lock(&lock_info->lock);
+
+	for (i = lock_info->num_locks - 1; i >= 0; i--) {
+		if (lock_info->locks[i].lock_addr == lock_addr)
+			break;
+	}
+
+	if (i == -1) {
+		/* Lock not found :( */
+		pthread_mutex_unlock(&lock_info->lock);
+		return;
+	}
+
+	lock_info->locks[i].suspended = 0;
+
+	pthread_mutex_unlock(&lock_info->lock);
+}
+
+
 #ifdef HAVE_BKTR
 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
 #else
@@ -864,7 +920,7 @@
 	ast_mutex_t *lock;
 	struct ast_lock_track *lt;
 	
-	ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n", 
+	ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d%s)\n", 
 				   lock_info->locks[i].pending > 0 ? "Waiting for " : 
 				   lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
 				   lock_info->locks[i].file, 
@@ -872,7 +928,8 @@
 				   lock_info->locks[i].line_num,
 				   lock_info->locks[i].func, lock_info->locks[i].lock_name,
 				   lock_info->locks[i].lock_addr, 
-				   lock_info->locks[i].times_locked);
+				   lock_info->locks[i].times_locked,
+				   lock_info->locks[i].suspended ? " - suspended" : "");
 #ifdef HAVE_BKTR
 	append_backtrace_information(str, lock_info->locks[i].backtrace);
 #endif
@@ -981,20 +1038,32 @@
 	pthread_mutex_lock(&lock_infos_lock.mutex);
 	AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
 		int i;
-		if (lock_info->num_locks) {
-			ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
-				lock_info->thread_name);
-			pthread_mutex_lock(&lock_info->lock);
-			for (i = 0; str && i < lock_info->num_locks; i++) {
-				append_lock_information(&str, lock_info, i);
+		int header_printed = 0;
+		pthread_mutex_lock(&lock_info->lock);
+		for (i = 0; str && i < lock_info->num_locks; i++) {
+			/* Don't show suspended locks */
+			if (lock_info->locks[i].suspended) {
+				continue;
 			}
-			pthread_mutex_unlock(&lock_info->lock);
-			if (!str)
-				break;
+
+			if (!header_printed) {
+				ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
+					lock_info->thread_name);
+				header_printed = 1;
+			}
+
+			append_lock_information(&str, lock_info, i);
+		}
+		pthread_mutex_unlock(&lock_info->lock);
+		if (!str) {
+			break;
+		}
+		if (header_printed) {
 			ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
-			               "===\n");
-			if (!str)
-				break;
+				"===\n");
+		}
+		if (!str) {
+			break;
 		}
 	}
 	pthread_mutex_unlock(&lock_infos_lock.mutex);

Modified: team/dlee/ASTERISK-194630-startup-deadlock/res/res_jabber.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-194630-startup-deadlock/res/res_jabber.c?view=diff&rev=398668&r1=398667&r2=398668
==============================================================================
--- team/dlee/ASTERISK-194630-startup-deadlock/res/res_jabber.c (original)
+++ team/dlee/ASTERISK-194630-startup-deadlock/res/res_jabber.c Mon Sep  9 15:21:25 2013
@@ -3260,7 +3260,7 @@
  */
 static int aji_handle_pubsub_event(void *data, ikspak *pak)
 {
-	char *item_id, *device_state, *context, *cachable_str;
+	char *item_id, *device_state, *mailbox, *cachable_str;
 	int oldmsgs, newmsgs;
 	iks *item, *item_content;
 	struct ast_eid pubsub_eid;
@@ -3293,15 +3293,16 @@
 			return IKS_FILTER_EAT;
 		}
 	} else if (!strcasecmp(iks_name(item_content), "mailbox")) {
-		context = strsep(&item_id, "@");
+		mailbox = strsep(&item_id, "@");
 		sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
 		sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
-		if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
-			AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
-			AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
-			AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
-			AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
-			&pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
+		if (!(event = ast_event_new(AST_EVENT_MWI,
+			AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+			AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, item_id,
+			AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, oldmsgs,
+			AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, newmsgs,
+			AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+			AST_EVENT_IE_END))) {
 			return IKS_FILTER_EAT;
 		}
 	} else {




More information about the asterisk-commits mailing list