[asterisk-commits] dvossel: branch dvossel/masq_locking_order_trunk r222151 - /team/dvossel/masq...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Oct 5 18:08:38 CDT 2009


Author: dvossel
Date: Mon Oct  5 18:08:36 2009
New Revision: 222151

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=222151
Log:
In ast_do_masquerade, the channels ao2_container does not have
to be held the entire function.  These changes make it safe
to let the container lock go after unlinking takes place.


Modified:
    team/dvossel/masq_locking_order_trunk/main/channel.c

Modified: team/dvossel/masq_locking_order_trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/masq_locking_order_trunk/main/channel.c?view=diff&rev=222151&r1=222150&r2=222151
==============================================================================
--- team/dvossel/masq_locking_order_trunk/main/channel.c (original)
+++ team/dvossel/masq_locking_order_trunk/main/channel.c Mon Oct  5 18:08:36 2009
@@ -5109,8 +5109,18 @@
 	 * original channel's backend.  While the features are nice, which is the
 	 * reason we're keeping it, it's still awesomely weird. XXX */
 
+	/* The reasoning for the channels ao2_container lock here is complex.
+	 * 
+	 * In order to check for a race condition, the original channel must
+	 * be locked.  If it is determined that the masquerade should proceed
+	 * the original channel can absolutely not be unlocked until the end
+	 * of the function.  Since after determining the masquerade should
+	 * continue requires the channels to be unlinked from the ao2_container,
+	 * the container lock must be held first to achieve proper locking order.
+	 */
 	ao2_lock(channels);
 
+	/* lock the original channel to determine if the masquerade is require or not */
 	ast_channel_lock(original);
 
 	/* This checks to see if the masquerade has already happened or not.  There is a
@@ -5127,8 +5137,10 @@
 	/* now that we have verified no race condition exists, set the clone channel */
 	clonechan = original->masq;
 
-	/* since this function already holds the global containers lock, unlocking original
-	 * for deadlock avoidance will not result in a sort of masquerade race condition */
+	/* since this function already holds the global container lock, unlocking original
+	 * for deadlock avoidance will not result in any sort of masquerade race condition.
+	 * If masq is called by a different thread while this happens, it will be stuck waiting
+	 * until we unlock the container. */
 	while (ast_channel_trylock(clonechan)) {
 		CHANNEL_DEADLOCK_AVOIDANCE(original);
 	}
@@ -5140,6 +5152,9 @@
 	/* unlink from channels container as name (which is the hash value) will change */
 	ao2_unlink(channels, original);
 	ao2_unlink(channels, clonechan);
+
+	/* now that both channels are locked and unlinked from the container, it is safe to unlock it */
+	ao2_unlock(channels);
 
 	ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
 		clonechan->name, clonechan->_state, original->name, original->_state);
@@ -5397,12 +5412,14 @@
 done:
 	/* it is possible for the clone channel to disappear during this */
 	if (clonechan) {
+		ast_channel_unlock(original);
 		ast_channel_unlock(clonechan);
 		ao2_link(channels, clonechan);
-	}
-	ast_channel_unlock(original);
-	ao2_link(channels, original);
-	ao2_unlock(channels);
+		ao2_link(channels, original);
+	} else {
+		ast_channel_unlock(original);
+		ao2_link(channels, original);
+	}
 	return 0;
 }
 




More information about the asterisk-commits mailing list