Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 63029) +++ channels/chan_iax2.c (working copy) @@ -6585,6 +6585,7 @@ ((f.subclass != IAX_COMMAND_INVAL) || (f.frametype != AST_FRAME_IAX))) { unsigned char x; + int call_to_destroy; /* XXX This code is not very efficient. Surely there is a better way which still properly handles boundary conditions? XXX */ /* First we have to qualify that the ACKed value is within our window */ @@ -6598,6 +6599,7 @@ /* Ack the packet with the given timestamp */ if (option_debug && iaxdebug) ast_log(LOG_DEBUG, "Cancelling transmission of packet %d\n", x); + call_to_destroy = 0; AST_LIST_LOCK(&iaxq.queue); AST_LIST_TRAVERSE(&iaxq.queue, cur, list) { /* If it's our call, and our timestamp, mark -1 retries */ @@ -6605,13 +6607,22 @@ cur->retries = -1; /* Destroy call if this is the end */ if (cur->final) { - if (iaxdebug && option_debug) - ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", fr->callno); - iax2_destroy(fr->callno); + /* SLD FIXME: We hit a deadlock here when another thread was also busy + * destroying the same call. The deadlock was between &queue (held above), + * the iaxsl for this call, and the lock for the "owner" of this iax call. + * So instead we only do our destroy once we've released the queue mutex. + */ + /* iax2_destroy(fr->callno); */ + call_to_destroy = fr->callno; } } } AST_LIST_UNLOCK(&iaxq.queue); + if (call_to_destroy) { + if (iaxdebug && option_debug) + ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", call_to_destroy); + iax2_destroy(call_to_destroy); + } } /* Note how much we've received acknowledgement for */ if (iaxs[fr->callno])