From ae761c74738c04c11b72b539cc7e852bef6da260 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 9 Oct 2019 15:17:59 -0500 Subject: [PATCH] pbx: deadlock when outgoing dialed channel hangs up too quickly Here's the basic scenario that occurred when executing an AMI fast originate while at the same time something else locks the channels container, and also wants a lock on the dialed channel: 1. pbx_outgoing_attempt obtains a lock on a dialed channel 2. concurrently another thread obtains a lock on the channels container, and subsequently requests a lock on the dialed channel. It waits on #1. For instance, "core show channel dial, NULL, 0); @@ -7624,36 +7625,37 @@ static void *pbx_outgoing_exec(void *data) return NULL; } + /* We steal the channel so we get ownership of when it is hung up */ + chan = ast_dial_answered_steal(outgoing->dial); + if (!ast_strlen_zero(outgoing->app)) { struct ast_app *app = pbx_findapp(outgoing->app); if (app) { ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""), - ast_channel_name(ast_dial_answered(outgoing->dial))); - pbx_exec(ast_dial_answered(outgoing->dial), app, outgoing->appdata); + ast_channel_name(chan)); + pbx_exec(chan, app, outgoing->appdata); } else { ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app); } - } else { - struct ast_channel *answered = ast_dial_answered(outgoing->dial); + ast_hangup(chan); + } else { if (!ast_strlen_zero(outgoing->context)) { - ast_channel_context_set(answered, outgoing->context); + ast_channel_context_set(chan, outgoing->context); } if (!ast_strlen_zero(outgoing->exten)) { - ast_channel_exten_set(answered, outgoing->exten); + ast_channel_exten_set(chan, outgoing->exten); } if (outgoing->priority > 0) { - ast_channel_priority_set(answered, outgoing->priority); + ast_channel_priority_set(chan, outgoing->priority); } - if (ast_pbx_run(answered)) { - ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered)); - } else { - /* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */ - ast_dial_answered_steal(outgoing->dial); + if (ast_pbx_run(chan)) { + ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan)); + ast_hangup(chan); } }