[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