static struct opbx_channel *channel_find_locked(const struct opbx_channel *prev, const char *name, const int namelen, const char *context, const char *exten) { const char *msg = prev ? "deadlock" : "initial deadlock"; int retries, done; struct opbx_channel *c; for (retries = 0; retries < 10; retries++) { opbx_mutex_lock(&chlock); for (c = channels; c; c = c->next) { if (!prev) { /* want head of list */ if (!name && !exten) break; if (name) { /* want match by full name */ if (!namelen) { if (!strcasecmp(c->name, name)) break; else continue; } /* want match by name prefix */ if (!strncasecmp(c->name, name, namelen)) break; } else if (exten) { /* want match by context and exten */ if (context && (strcasecmp(c->context, context) && strcasecmp(c->macrocontext, context))) continue; /* match by exten */ if (strcasecmp(c->exten, exten) && strcasecmp(c->macroexten, exten)) continue; else break; } } else if (c == prev) { /* found, return c->next */ c = c->next; break; } } /* exit if chan not found or mutex acquired successfully */ done = (c == NULL) || (opbx_mutex_trylock(&c->lock) == 0); /* this is slightly unsafe, as we _should_ hold the lock to access c->name */ if (!done && c) opbx_log(LOG_DEBUG, "Avoiding %s for '%s'\n", msg, c->name); opbx_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 */ opbx_log(LOG_WARNING, "Avoided %s for '%p', %d retries!\n", msg, c, retries); return NULL; }