From: Richard Mudgett Date: Thu, 10 Nov 2011 23:01:31 +0000 (+0000) Subject: Fix potential deadlock calling ast_call() with channel locks held. X-Git-Tag: 10.1.0-rc1~99 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2b0dfa6152a68b22d0e498f2fee1336ca6ff1bd;p=thirdparty%2Fasterisk.git Fix potential deadlock calling ast_call() with channel locks held. Fixed app_queue.c:ring_entry() calling ast_call() with the channel locks held. Chan_local attempts to do deadlock avoidance in its ast_call() callback and could deadlock if a channel lock is already held. ........ Merged revisions 344539 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@344540 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_queue.c b/apps/app_queue.c index 27a2ef5c05..915175c965 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -3119,10 +3119,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies return 0; } - ast_channel_lock(tmp->chan); - while (ast_channel_trylock(qe->chan)) { - CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan); - } + ast_channel_lock_both(tmp->chan, qe->chan); if (qe->cancel_answered_elsewhere) { ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); @@ -3185,13 +3182,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); } + ast_channel_unlock(tmp->chan); + ast_channel_unlock(qe->chan); + /* Place the call, but don't wait on the answer */ if ((res = ast_call(tmp->chan, location, 0))) { /* Again, keep going even if there's an error */ ast_debug(1, "ast call on peer returned %d\n", res); ast_verb(3, "Couldn't call %s\n", tmp->interface); - ast_channel_unlock(tmp->chan); - ast_channel_unlock(qe->chan); do_hang(tmp); (*busies)++; update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); @@ -3199,6 +3197,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies } else if (qe->parent->eventwhencalled) { char vars[2048]; + ast_channel_lock_both(tmp->chan, qe->chan); + manager_event(EVENT_FLAG_AGENT, "AgentCalled", "Queue: %s\r\n" "AgentCalled: %s\r\n" @@ -3221,10 +3221,12 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); + + ast_channel_unlock(tmp->chan); + ast_channel_unlock(qe->chan); + ast_verb(3, "Called %s\n", tmp->interface); } - ast_channel_unlock(tmp->chan); - ast_channel_unlock(qe->chan); update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); return 1; @@ -3658,10 +3660,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte } else { struct ast_party_redirecting redirecting; - ast_channel_lock(o->chan); - while (ast_channel_trylock(in)) { - CHANNEL_DEADLOCK_AVOIDANCE(o->chan); - } + ast_channel_lock_both(o->chan, in); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan);