aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authordvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-04-28 21:33:16 +0000
committerdvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-04-28 21:33:16 +0000
commit6774aa6bf186dd88580070e83dad785af0064a03 (patch)
tree3cf571e0bb0490c95dd36e0570f30d418fbffdd3 /channels
parentf42fdaa03fdce019cafb9ce65c017448854325cf (diff)
Merged revisions 259870 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ................ r259870 | dvossel | 2010-04-28 16:20:03 -0500 (Wed, 28 Apr 2010) | 39 lines Merged revisions 259858 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r259858 | dvossel | 2010-04-28 16:16:03 -0500 (Wed, 28 Apr 2010) | 33 lines resolves deadlocks in chan_local Issue_1. In the local_hangup() 3 locks must be held at the same time... pvt, pvt->chan, and pvt->owner. Proper deadlock avoidance is done when the channel to hangup is the outbound chan_local channel, but when it is not the outbound channel we have an issue... We attempt to do deadlock avoidance only on the tech pvt, when both the tech pvt and the pvt->owner are locked coming into that loop. By never giving up the pvt->owner channel deadlock avoidance is not entirely possible. This patch resolves that by doing deadlock avoidance on both the pvt->owner and the pvt when trying to get the pvt->chan lock. Issue_2. ast_prod() is used in ast_activate_generator() to queue a frame on the channel and make the channel's read function get called. This function is used in ast_activate_generator() while the channel is locked, which mean's the channel will have a lock both from the generator code and the frame_queue code by the time it gets to chan_local.c's local_queue_frame code... local_queue_frame contains some of the same crazy deadlock avoidance that local_hangup requires, and this recursive lock prevents that deadlock avoidance from happening correctly. This patch removes ast_prod() from the channel lock so only one lock is held during the local_queue_frame function. (closes issue #17185) Reported by: schmoozecom Patches: issue_17185_v1.diff uploaded by dvossel (license 671) issue_17185_v2.diff uploaded by dvossel (license 671) Tested by: schmoozecom, GameGamer43 Review: https://reviewboard.asterisk.org/r/631/ ........ ................ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.1@259930 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_local.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 7ed607d2c..2cd02c961 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -580,12 +580,12 @@ static int local_hangup(struct ast_channel *ast)
/* Deadlock avoidance */
while (p->owner && ast_channel_trylock(p->owner)) {
ast_mutex_unlock(&p->lock);
- if (ast) {
- ast_channel_unlock(ast);
+ if (p->chan) {
+ ast_channel_unlock(p->chan);
}
usleep(1);
- if (ast) {
- ast_channel_lock(ast);
+ if (p->chan) {
+ ast_channel_lock(p->chan);
}
ast_mutex_lock(&p->lock);
}
@@ -600,8 +600,17 @@ static int local_hangup(struct ast_channel *ast)
} else {
ast_module_user_remove(p->u_owner);
while (p->chan && ast_channel_trylock(p->chan)) {
- DEADLOCK_AVOIDANCE(&p->lock);
+ ast_mutex_unlock(&p->lock);
+ if (p->owner) {
+ ast_channel_unlock(p->owner);
+ }
+ usleep(1);
+ if (p->owner) {
+ ast_channel_lock(p->owner);
+ }
+ ast_mutex_lock(&p->lock);
}
+
p->owner = NULL;
if (p->chan) {
ast_queue_hangup(p->chan);