<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6367">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">stasis/control:  Fix possible deadlock with swap channel<br><br>If an error occurs during a bridge impart it's possible that<br>the "bridge_after" callback might try to run before<br>control_swap_channel_in_bridge has been signalled to continue.<br>Since control_swap_channel_in_bridge is holding the control lock<br>and the callback needs it, a deadlock will occur.<br><br>* control_swap_channel_in_bridge now only holds the control<br>  lock while it's actually modifying the control structure and<br>  releases it while the bridge impart is running.<br>* bridge_after_cb is now tolerant of impart failures.<br><br>Change-Id: Ifd239aa93955b3eb475521f61e284fcb0da2c3b3<br>---<br>M res/stasis/control.c<br>1 file changed, 21 insertions(+), 8 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/67/6367/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/res/stasis/control.c b/res/stasis/control.c<br>index 219a2c6..ef461cd 100644<br>--- a/res/stasis/control.c<br>+++ b/res/stasis/control.c<br>@@ -991,8 +991,12 @@<br>  SCOPED_AO2LOCK(lock, control);<br>        struct ast_bridge_channel *bridge_channel;<br> <br>+        /* control->bridge may be NULL because of a race with<br>+      * control_swap_channel_in_bridge if an error occurrs<br>+         * during the bridge impart.  We need to be tolerant of that.<br>+         */<br>   ast_debug(3, "%s, %s: Channel leaving bridge\n",<br>-           ast_channel_uniqueid(chan), control->bridge->uniqueid);<br>+                ast_channel_uniqueid(chan), control->bridge ? control->bridge->uniqueid : "FAILED");<br> <br>    ast_assert(chan == control->channel);<br> <br>@@ -1002,16 +1006,19 @@<br> <br>       app_unsubscribe_bridge(control->app, control->bridge);<br> <br>-      /* No longer in the bridge */<br>-        control->bridge = NULL;<br>-<br>         /* Get the bridge channel so we don't depart from the wrong bridge */<br>     ast_channel_lock(chan);<br>       bridge_channel = ast_channel_get_bridge_channel(chan);<br>        ast_channel_unlock(chan);<br> <br>- /* Depart this channel from the bridge using the command queue if possible */<br>-        stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);<br>+        if (control->bridge) {<br>+            /* Depart this channel from the bridge using the command queue if possible */<br>+                stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);<br>+        }<br>+<br>+ /* No longer in the bridge */<br>+        control->bridge = NULL;<br>+<br>         if (stasis_app_channel_is_stasis_end_published(chan)) {<br>               /* The channel has had a StasisEnd published on it, but until now had remained in<br>              * the bridging system. This means that the channel moved from a Stasis bridge to a<br>@@ -1193,25 +1200,31 @@<br>                  ast_channel_pbx_set(chan, NULL);<br>              }<br> <br>+         control->bridge = NULL;<br>+           /* We can't be holding the control lock while impart is running<br>+           * or we could create a deadlock with bridge_after_cb which also<br>+              * tries to lock control.<br>+             */<br>+          ao2_unlock(control);<br>          res = ast_bridge_impart(bridge,<br>                       chan,<br>                         swap,<br>                         NULL, /* features */<br>                  AST_BRIDGE_IMPART_CHAN_DEPARTABLE);<br>+          ao2_lock(control);<br>            if (res != 0) {<br>                       ast_log(LOG_ERROR, "Error adding channel to bridge\n");<br>                     ast_channel_pbx_set(chan, control->pbx);<br>                   control->pbx = NULL;<br>                       return -1;<br>            }<br>-<br>-         ast_assert(stasis_app_get_bridge(control) == NULL);<br>           control->bridge = bridge;<br> <br>               ast_channel_lock(chan);<br>               set_interval_hook(chan);<br>              ast_channel_unlock(chan);<br>     }<br>+<br>  return 0;<br> }<br> <br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6367">change 6367</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6367"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ifd239aa93955b3eb475521f61e284fcb0da2c3b3 </div>
<div style="display:none"> Gerrit-Change-Number: 6367 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>