[asterisk-commits] file: branch file/chanlist r51219 - /team/file/chanlist/main/channel.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Jan 17 22:57:44 MST 2007


Author: file
Date: Wed Jan 17 23:57:44 2007
New Revision: 51219

URL: http://svn.digium.com/view/asterisk?view=rev&rev=51219
Log:
Hey look! It's a new channel_find_locked. This one will skip over channels that may deadlock instead of stopping in the middle of things and just generally looks better.

Modified:
    team/file/chanlist/main/channel.c

Modified: team/file/chanlist/main/channel.c
URL: http://svn.digium.com/view/asterisk/team/file/chanlist/main/channel.c?view=diff&rev=51219&r1=51218&r2=51219
==============================================================================
--- team/file/chanlist/main/channel.c (original)
+++ team/file/chanlist/main/channel.c Wed Jan 17 23:57:44 2007
@@ -879,55 +879,64 @@
 					       const char *context, const char *exten)
 {
 	const char *msg = prev ? "deadlock" : "initial deadlock";
-	int retries;
-	struct ast_channel *c;
-
-	for (retries = 0; retries < 10; retries++) {
-		int done;
-		AST_RWLIST_RDLOCK(&channels);
-		AST_RWLIST_TRAVERSE(&channels, c, chan_list) {
-			if (prev) {	/* look for next item */
-				if (c != prev)	/* not this one */
-					continue;
-				/* found, prepare to return c->next */
-				c = AST_RWLIST_NEXT(c, chan_list);
-			}
-			if (name) { /* want match by name */
-				if ((!namelen && strcasecmp(c->name, name)) ||
-				    (namelen && strncasecmp(c->name, name, namelen)))
-					continue;	/* name match failed */
-			} else if (exten) {
-				if (context && strcasecmp(c->context, context) &&
-				    strcasecmp(c->macrocontext, context))
-					continue;	/* context match failed */
-				if (strcasecmp(c->exten, exten) &&
-				    strcasecmp(c->macroexten, exten))
-					continue;	/* exten match failed */
-			}
-			/* if we get here, c points to the desired record */
-			break;
-		}
-		/* exit if chan not found or mutex acquired successfully */
-		/* this is slightly unsafe, as we _should_ hold the lock to access c->name */
-		done = c == NULL || ast_channel_trylock(c) == 0;
-		if (!done) {
+	struct ast_channel *c = NULL;
+
+	AST_RWLIST_RDLOCK(&channels);
+
+	/* Find relative starting point */
+	if (prev)
+		c = AST_RWLIST_NEXT(prev, chan_list);
+	else
+		c = AST_RWLIST_FIRST(&channels);
+
+	/* If we have no starting point, unlock and return no channel */
+	if (!c) {
+		AST_RWLIST_UNLOCK(&channels);
+		return NULL;
+	}
+
+	/* Go into a loop looking for the channel and locking it */
+	do {
+		int retries = 0;
+
+		/* If we need to match specific data, do so here */
+		if (name) {
+			if ((!namelen && strcasecmp(c->name, name)) ||
+			    (namelen && strncasecmp(c->name, name, namelen)))
+				continue;
+		} else if (exten) {
+			if (context && strcasecmp(c->context, context) &&
+			    strcasecmp(c->macrocontext, context))
+				continue;
+			if (strcasecmp(c->exten, exten) &&
+			    strcasecmp(c->macroexten, exten))
+				continue;
+		}
+
+		/* If we got here we reached a channel that we want to lock and return, so attempt to lock it */
+		for (retries = 0; retries < 10; retries++) {
+			if (!ast_channel_trylock(c))
+				break;
+			usleep(1);
+		}
+
+		/* If we failed to get the lock either return now because we matched data, or skip over the channel */
+		if (retries == 10) {
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Avoiding %s for channel '%p'\n", msg, c);
-		}
-		AST_RWLIST_UNLOCK(&channels);
-		if (done)
-			return c;
-		usleep(1);	/* give other threads a chance before retrying */
-	}
-	/*
- 	 * c is surely not null, but we don't have the lock so cannot
-	 * access c->name
-	 */
-	if (option_debug)
-		ast_log(LOG_DEBUG, "Failure, could not lock '%p' after %d retries!\n",
-			c, retries);
-
-	return NULL;
+			if (name || exten) {
+				c = NULL;
+				break;
+			}
+		} else {
+			/* Everything went fine and channel is locked... let's return it! */
+			break;
+		}
+	} while ((c = AST_RWLIST_NEXT(c, chan_list)));
+
+	AST_RWLIST_UNLOCK(&channels);
+
+	return c;
 }
 
 /*! \brief Browse channels in use */



More information about the asterisk-commits mailing list