<br><br><div class="gmail_quote">2008/7/4 Russell Bryant &lt;<a href="mailto:russell@digium.com">russell@digium.com</a>&gt;:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d"><br>
----- &quot;Stephen Davies&quot; &lt;<a href="mailto:stephen.l.davies@gmail.com">stephen.l.davies@gmail.com</a>&gt; wrote:<br>
&gt; I think the discussion reveals that the magic trylock while loop looks<br></div><div class="Ih2E3d">
&gt; neato but doesn&#39;t really solve the problem. &nbsp;Tzafrir and Luigi pointed<br>
&gt; out some flaws.<br>
<br>
</div>It doesn&#39;t just look neato. &nbsp;It does actually work, except for when the recursive property of the locks are used.<br>
<div class="Ih2E3d"></div></blockquote><div><br><br>OK point taken. &nbsp; Ish. &nbsp;Because interestingly I&#39;ve fixed a deadlock recently in chan_local that was to do with the fact that a mutex had two outstanding locks. &nbsp;So when the magic trylock look in local_queue_frame tried to do its thing, the underlying lock never got released and you STILL end up with a deadlock (or livelock)<br>
<br>Here was the fix for that:<br><br><div>Index: channels/chan_local.c</div><div>===================================================================</div><div>--- channels/chan_local.c<span class="Apple-tab-span" style="white-space:pre">        </span>(revision 105553)</div>
<div>+++ channels/chan_local.c<span class="Apple-tab-span" style="white-space:pre">        </span>(working copy)</div><div>@@ -153,6 +153,7 @@</div><div>&nbsp;static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)</div>
<div>&nbsp;{</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>struct ast_channel *other = NULL;</div><div>+<span class="Apple-tab-span" style="white-space:pre">        </span>int doublelock = 0;</div><div>&nbsp;</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>/* Recalculate outbound channel */</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>other = isoutbound ? p-&gt;owner : p-&gt;chan;</div>
<div>@@ -175,11 +176,23 @@</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>/* Ensure that we have both channels locked */</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>while (other &amp;&amp; ast_channel_trylock(other)) {</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                </span>ast_mutex_unlock(&amp;p-&gt;lock);</div><div>-<span class="Apple-tab-span" style="white-space:pre">                </span>if (us)</div><div>+<span class="Apple-tab-span" style="white-space:pre">                </span>if (us) {</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                        </span>ast_channel_unlock(us);</div><div>+<span class="Apple-tab-span" style="white-space:pre">                        </span>/* SLD: In some circumstances with generators running on the local channel it is possible</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                        </span> &nbsp; for there to be two locks on the us channel. &nbsp;Essential to drop them both to avoid a</div><div>+<span class="Apple-tab-span" style="white-space:pre">                        </span> &nbsp; deadlock */</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                        </span>if (!ast_channel_unlock(us)) {</div><div>+<span class="Apple-tab-span" style="white-space:pre">                                </span>doublelock = 1;</div><div>+<span class="Apple-tab-span" style="white-space:pre">                                </span>if (option_debug &gt; 2)</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                                        </span>ast_log(LOG_VERBOSE, &quot;local_queue_frame had to unlock \&quot;us\&quot; twice\n&quot;);</div><div>+<span class="Apple-tab-span" style="white-space:pre">                        </span>}</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                </span>usleep(1);</div><div>-<span class="Apple-tab-span" style="white-space:pre">                </span>if (us)</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                </span>if (us) {</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                        </span>ast_channel_lock(us);</div><div>+<span class="Apple-tab-span" style="white-space:pre">                        </span>if (doublelock)</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">                                </span>ast_mutex_lock(us);</div><div>+<span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                </span>ast_mutex_lock(&amp;p-&gt;lock);</div>
<div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">                </span>other = isoutbound ? p-&gt;owner : p-&gt;chan;</div><div>&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br></div><br>Thinking back, there was a point in the past when the use of recursive locks was started. &nbsp; Or maybe I&#39;m remembering wrong and it was a point at which they became mandatory.<br>
<br>Anyway - I guess that the magic trylock look technique was used way back before the recursive mutexes came in.<br><br>&lt;goes to look at <a href="http://1.0.9.">1.0.9.</a>..&gt;<br><br>Yep - I can see it in there; though often without the while.<br>
<br>But even 1.0.9 Asterisk required recursive mutexes - so it was before then...<br><br>Steve<br></div></div>