diff options
author | Richard Mudgett <rmudgett@digium.com> | 2016-04-19 16:58:32 -0500 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2016-04-20 15:45:38 -0500 |
commit | 9942d50aa5cca7f864344069e924d9b254380638 (patch) | |
tree | b59808d871f537fdf34501f9a3e0222f199db14d /main/bridge_channel.c | |
parent | b1b34607830a55bedbc37c303ee1488a2c62c948 (diff) |
bridge: Hold off more than one imparting channel at a time.
An earlier patch blocked the ast_bridge_impart() call until the channel
either entered the target bridge or it failed. Unfortuantely, if the
target bridge is stasis and the imprted channel is not a stasis channel,
stasis bounces the channel out of the bridge to come back into the bridge
as a proper stasis channel. When the channel is bounced out, that
released the block on ast_bridge_impart() to continue. If the impart was
a result of a transfer, then it became a race to see if the swap channel
would get hung up before the imparted channel could come back into the
stasis bridge. If the imparted channel won then everything is fine. If
the swap channel gets hung up first then the transfer will fail because
the swap channel is leaving the bridge.
* Allow a chain of ast_bridge_impart()'s to happen before any are
unblocked to prevent the race condition described above. When the channel
finally joins the bridge or completely fails to join the bridge then the
ast_bridge_impart() instances are unblocked.
ASTERISK-25947
Reported by: Richard Mudgett
ASTERISK-24649
Reported by: John Bigelow
ASTERISK-24782
Reported by: John Bigelow
Change-Id: I8fef369171f295f580024ab4971e95c799d0dde1
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r-- | main/bridge_channel.c | 26 |
1 files changed, 2 insertions, 24 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c index e45ad1759..4baae3cc5 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2637,27 +2637,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch ao2_iterator_destroy(&iter); } -void bridge_channel_internal_wait(struct bridge_channel_internal_cond *cond) -{ - ast_mutex_lock(&cond->lock); - while (!cond->done) { - ast_cond_wait(&cond->cond, &cond->lock); - } - ast_mutex_unlock(&cond->lock); -} - -void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond) -{ - if (cond) { - ast_mutex_lock(&cond->lock); - cond->done = 1; - ast_cond_signal(&cond->cond); - ast_mutex_unlock(&cond->lock); - } -} - -int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, - struct bridge_channel_internal_cond *cond) +int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) { int res = 0; struct ast_bridge_features *channel_features; @@ -2687,7 +2667,6 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, bridge_channel->bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); - bridge_channel_internal_signal(cond); return -1; } ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge); @@ -2722,8 +2701,6 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, } bridge_reconfigured(bridge_channel->bridge, !bridge_channel->inhibit_colp); - bridge_channel_internal_signal(cond); - if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) { /* * Indicate a source change since this channel is entering the @@ -2735,6 +2712,7 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE); } + bridge_channel_impart_signal(bridge_channel->chan); ast_bridge_unlock(bridge_channel->bridge); /* Must release any swap ref after unlocking the bridge. */ |