Index: channel.c =================================================================== --- channel.c (revision 47810) +++ channel.c (working copy) @@ -739,13 +739,21 @@ int done; ast_mutex_lock(&chlock); - for (c = channels; c; c = c->next) { - if (prev) { /* look for next item */ - if (c != prev) /* not this one */ - continue; - /* found, prepare to return c->next */ - c = c->next; + /* If prev is set, use it to determin where we start searching + * otherwise scan from the start of the channel list + */ + if (!prev) + c = channels; + else { + for (c = channels; c; c = c->next) { + if (c == prev) { + c = c->next; + break; + } } + } + /* Starting point found, so search as per supplied parameters */ + for (; c; c = c->next) { if (name) { /* want match by name */ if ((!namelen && strcasecmp(c->name, name)) || (namelen && strncasecmp(c->name, name, namelen))) @@ -764,19 +772,30 @@ /* exit if chan not found or mutex acquired successfully */ done = (c == NULL) || (ast_mutex_trylock(&c->lock) == 0); /* this is slightly unsafe, as we _should_ hold the lock to access c->name */ - if (!done && c) + if (!done && c) { ast_log(LOG_DEBUG, "Avoiding %s for '%s'\n", msg, c->name); + if( retries == 10 ) { + /* We are about to fail due to a deadlock, so report this + * while we still have the list lock. + */ + ast_log(LOG_WARNING, "Avoided %s for '%p', %d retries!\n", + msg, c, retries); + /* As we have deadlocked, we will skip this channel and + * see if there is another match. + * NOTE: No point doing this for a get-list-head, or full-name match, + * as there can be no more matches. + */ + if ( (prev || name || exten) && !(name && !namelen)) { + prev = c; + retries = -1; + } + } + } ast_mutex_unlock(&chlock); if (done) return c; usleep(1); } - /* - * c is surely not null, but we don't have the lock so cannot - * access c->name - */ - ast_log(LOG_WARNING, "Avoided %s for '%p', %d retries!\n", - msg, c, retries); return NULL; }