[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r383119 - /team/rmudgett/bridge_phase/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Mar 14 19:59:47 CDT 2013
Author: rmudgett
Date: Thu Mar 14 19:59:44 2013
New Revision: 383119
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383119
Log:
First step to making bridge_channel->bridge accesses safe when
bridge-merges/channel-moves happen.
Modified:
team/rmudgett/bridge_phase/main/bridging.c
Modified: team/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=383119&r1=383118&r2=383119
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Thu Mar 14 19:59:44 2013
@@ -191,6 +191,49 @@
return current ? 0 : -1;
}
+/*!
+ * \internal
+ * \brief Lock the bridge associated with the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel that wants to lock the bridge.
+ *
+ * \details
+ * This is an upstream lock operation. The defined locking
+ * order is bridge then bridge_channel.
+ *
+ * \note On entry, neither the bridge nor bridge_channel is locked.
+ *
+ * \note The bridge_channel->bridge pointer changes because of a
+ * bridge-merge/channel-move operation between bridges.
+ *
+ * \return Nothing
+ */
+static void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_bridge *bridge;
+
+ for (;;) {
+ /* Safely get the bridge pointer */
+ ao2_lock(bridge_channel);
+ bridge = bridge_channel->bridge;
+ ao2_ref(bridge, +1);
+ ao2_unlock(bridge_channel);
+
+ /*
+ * The bridge pointer cannot change while the bridge or
+ * bridge_channel is locked.
+ */
+ ao2_lock(bridge);
+ if (bridge == bridge_channel->bridge) {
+ ao2_ref(bridge, -1);
+ return;
+ }
+ ao2_unlock(bridge);
+ ao2_ref(bridge, -1);
+ }
+}
+
void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
{
/* BUGBUG need cause code for the bridge_channel leaving the bridge. */
@@ -649,7 +692,7 @@
/* BUGBUG bridge join or impart needs to do CONNECTED_LINE updates if the channels are being swapped and it is a 1-1 bridge. */
/* Simply write the frame out to the bridge technology. */
- ao2_lock(bridge_channel->bridge);
+ ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
ao2_unlock(bridge_channel->bridge);
ast_frfree(frame);
@@ -1251,7 +1294,7 @@
*/
static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel)
{
- ao2_lock(bridge_channel->bridge);
+ ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel_suspend_nolock(bridge_channel);
ao2_unlock(bridge_channel->bridge);
}
@@ -1294,7 +1337,7 @@
*/
static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel)
{
- ao2_lock(bridge_channel->bridge);
+ ast_bridge_channel_lock_bridge(bridge_channel);
bridge_channel_unsuspend_nolock(bridge_channel);
ao2_unlock(bridge_channel->bridge);
}
@@ -1672,7 +1715,10 @@
ast_debug(1, "Joining bridge channel %p(%s) to bridge %p\n",
bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->bridge);
-/* BUGBUG the code is assuming that bridge_channel->bridge does not change which is just wrong. The bridge pointer can change with merges and moves. The locking protocol must be implemented. */
+ /*
+ * Directly locking the bridge is safe here because nobody else
+ * knows about this bridge_channel yet.
+ */
ao2_lock(bridge_channel->bridge);
if (!bridge_channel->bridge->callid) {
@@ -1690,7 +1736,7 @@
bridge_channel_wait(bridge_channel);
}
- ao2_lock(bridge_channel->bridge);
+ ast_bridge_channel_lock_bridge(bridge_channel);
ast_bridge_channel_pull(bridge_channel);
ast_bridge_reconfigured(bridge_channel->bridge);
@@ -2368,7 +2414,9 @@
/* Point to new bridge.*/
ao2_ref(bridge1, +1);
+ ao2_lock(bridge_channel);
bridge_channel->bridge = bridge1;
+ ao2_unlock(bridge_channel);
ao2_ref(bridge2, -1);
ast_bridge_channel_push(bridge_channel);
More information about the asterisk-commits
mailing list