<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>Random deadlocks playing WAV sounds (Windows, MSVC)</title>
		<link>http://www.allegro.cc/forums/view/615266</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Wed, 29 Apr 2015 06:46:22 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Not sure if this was fixed in 5.1.9 since there are no pre-built binaries available, although I don&#39;t see anything in the release notes, so here goes:</p><p>Playing a WAV sound via the audio stream API often causes Allegro to deadlock (I can&#39;t even close the display window).  This never happened in 5.0.10, so it&#39;s apparently a regression in 5.1.  Other types of sounds (Ogg, MOD) seem to be fine, except for WAV.  Unfortunately I can&#39;t track the bug down as it doesn&#39;t appear to happen when running my engine in debug mode.  Seems like a race condition of some sort.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Wed, 08 Apr 2015 10:50:21 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Could you test to see if it happens with the exact same file but in a different format (try keeping the depth (e.g. keep it 16 bit) the same as well)? I recall some changes in the streaming code, but almost none in the actual wav loading code (I see one change that seems innocuous at a first glance). The streaming code changes, however, could have screwed something up for particular file lengths.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Wed, 08 Apr 2015 20:56:30 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I will do some testing later anyway, but the deadlocks seem to have stopped since upgrading my engine to use Allegro 5.1.9.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Wed, 08 Apr 2015 23:01:03 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>There were some changes made in 5.1.9 to looping... so it&#39;s not impossible that this was fixed that way.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Thu, 09 Apr 2015 06:08:23 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Okay, it looks like 5.1.9 made things better, but the deadlocks still happen sometimes.  And you&#39;re right, it&#39;s not just with WAVs but with any supported stream format--I&#39;ve now seen my engine lock up twice trying to play background music in Ogg format.</p><p>From my testing, it appears to happen more often on slower machines; my i3 and i7 laptops hardly ever experience the issue, but I can reproduce it much more easily on my cruddy AMD E2 desktop.  Which, again, points to a race condition.  Now that I have Allegro building on Windows, I might try to look into it myself, but then there&#39;s the issue of my not being able to reproduce it under the debugger... <img src="http://www.allegro.cc/forums/smileys/undecided.gif" alt=":-/" /></p><p><b>Edit:</b> Well, I found the source of the deadlocks anyway: al_destroy_audio_stream.  I manually attached the debugger to a release build .exe (I had the .pdb for it) while it was locked up and it&#39;s stuck in an al_cond_wait.</p><p>Here&#39;s the function in my minisphere engine causing the lockup:
</p><div class="source-code"><div class="toolbar"><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number"> 166</span><span class="k1">bool</span>
<span class="number"> 167</span>reload_sound<span class="k2">(</span>sound_t<span class="k3">*</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_735.html" target="_blank">sound</a><span class="k2">)</span>
<span class="number"> 168</span><span class="k2">{</span>
<span class="number"> 169</span>  <a href="http://www.allegro.cc/manual/ALLEGRO_AUDIO_STREAM"><span class="a">ALLEGRO_AUDIO_STREAM</span></a><span class="k3">*</span> new_stream<span class="k2">;</span>
<span class="number"> 170</span>
<span class="number"> 171</span>  <span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span><span class="k2">(</span>new_stream <span class="k3">=</span> <a href="http://www.allegro.cc/manual/al_load_audio_stream"><span class="a">al_load_audio_stream</span></a><span class="k2">(</span>sound-&gt;path, <span class="n">4</span>, <span class="n">1024</span><span class="k2">)</span><span class="k2">)</span><span class="k2">)</span>
<span class="number"> 172</span>    <span class="k1">return</span> <span class="k1">false</span><span class="k2">;</span>
<span class="number"> 173</span>  <span class="k1">if</span> <span class="k2">(</span>sound-&gt;stream <span class="k3">!</span><span class="k3">=</span> NULL<span class="k2">)</span>
<span class="number"> 174</span>    <a href="http://www.allegro.cc/manual/al_destroy_audio_stream"><span class="a">al_destroy_audio_stream</span></a><span class="k2">(</span>sound-&gt;stream<span class="k2">)</span><span class="k2">;</span>  <span class="c">// &lt;-- deadlock here</span>
<span class="number"> 175</span>  sound-&gt;stream <span class="k3">=</span> new_stream<span class="k2">;</span>
<span class="number"> 176</span>  <a href="http://www.allegro.cc/manual/al_set_audio_stream_gain"><span class="a">al_set_audio_stream_gain</span></a><span class="k2">(</span>sound-&gt;stream, <span class="n">1</span>.<span class="n">0</span><span class="k2">)</span><span class="k2">;</span>
<span class="number"> 177</span>  <a href="http://www.allegro.cc/manual/al_attach_audio_stream_to_mixer"><span class="a">al_attach_audio_stream_to_mixer</span></a><span class="k2">(</span>sound-&gt;stream, <a href="http://www.allegro.cc/manual/al_get_default_mixer"><span class="a">al_get_default_mixer</span></a><span class="k2">(</span><span class="k2">)</span><span class="k2">)</span><span class="k2">;</span>
<span class="number"> 178</span>  <a href="http://www.allegro.cc/manual/al_set_audio_stream_playing"><span class="a">al_set_audio_stream_playing</span></a><span class="k2">(</span>sound-&gt;stream, <span class="k1">false</span><span class="k2">)</span><span class="k2">;</span>
<span class="number"> 179</span>  <span class="k1">return</span> <span class="k1">true</span><span class="k2">;</span>
<span class="number"> 180</span><span class="k2">}</span>
</div></div><p>

The reason this function exists is because, if you don&#39;t reload an audio stream after it plays through to completion, you can&#39;t play it again even if you manually seek to the start, as the feed thread has already terminated.  So to get around this, I manually recreate the stream each time my engine&#39;s play_sound() function is called.  This technique worked fine in 5.0, but apparently 5.1 doesn&#39;t seem to like it and deadlocks.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Thu, 09 Apr 2015 08:06:03 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Hmm, that doesn&#39;t seem very nice (that the thread exits), and probably should be changed. I&#39;ll investigate the deadlock anyway though.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Tue, 14 Apr 2015 07:07:41 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Yeah, that was the results of my study of the stream code: for streams created from files (<tt>al_load_audio_stream</tt>), the thread that feeds the stream exits permenantly if it runs out of data, with no way to restart it without another al_load_audio_stream() call.</p><p><b>Edit:</b> Two observations I&#39;ve made: 1) The deadlock is more likely to happen the sooner al_destroy_audio_stream() is called after creation, and 2) Calling <tt>al_drain_audio_stream</tt> first appears to fix the deadlocks.</p><p>I&#39;m beginning to wonder if it&#39;s not a race condition with the al_wait_for_event() call in <tt>_al_kcm_feed_stream</tt>.  From what I could tell from the documentation, the only event a stream can emit is <tt>ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT</tt>. This is just a theory, but if the stream happens to be destroyed while the feeder is waiting for a fragment event, could it get stuck waiting forever?</p><p><b>Edit 2:</b> Well, I was close.  Here&#39;s where the deadlock originates (helper.c:14):
</p><div class="source-code"><div class="toolbar"><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number"> 12</span>quit_event.type <span class="k3">=</span> _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE<span class="k2">;</span>
<span class="number"> 13</span><a href="http://www.allegro.cc/manual/al_emit_user_event"><span class="a">al_emit_user_event</span></a><span class="k2">(</span><a href="http://www.allegro.cc/manual/al_get_audio_stream_event_source"><span class="a">al_get_audio_stream_event_source</span></a><span class="k2">(</span>stream<span class="k2">)</span>, <span class="k3">&amp;</span>quit_event, NULL<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 14</span><a href="http://www.allegro.cc/manual/al_join_thread"><span class="a">al_join_thread</span></a><span class="k2">(</span>stream-&gt;feed_thread, NULL<span class="k2">)</span><span class="k2">;</span> <span class="c">// &lt;-- here</span>
<span class="number"> 15</span><a href="http://www.allegro.cc/manual/al_destroy_thread"><span class="a">al_destroy_thread</span></a><span class="k2">(</span>stream-&gt;feed_thread<span class="k2">)</span><span class="k2">;</span>
</div></div><p>

I then switched over to <tt>_al_kcm_feed_stream</tt> - It never gets the <tt>_KCM_STREAM_FEEDER_QUIT_EVENT_TYPE</tt> event, it just gets stuck responding to fragment events forever.</p><p>It&#39;s <b>exceedingly</b> difficult to reproduce in a debug build, I only managed to do it once and that was without the debugger attached--I had to attach it afterwards.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Tue, 14 Apr 2015 07:14:45 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Yeah, I tried to reproduce this, but I have not yet succeeded :/. Naturally I examined the code and nothing appeared wrong... I think what might happen here is that perhaps we can change it to keep that thread alive so you wouldn&#39;t have to re-create it to begin with (hopefully this won&#39;t introduce 10 bugs on its own).
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Sun, 19 Apr 2015 21:43:53 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I just found a reliable way to reproduce the deadlock, even in a debug build:<br /><span class="source-code"><a href="http://www.allegro.cc/manual/al_destroy_audio_stream"><span class="a">al_destroy_audio_stream</span></a><span class="k2">(</span><a href="http://www.allegro.cc/manual/al_load_audio_stream"><span class="a">al_load_audio_stream</span></a><span class="k2">(</span><span class="s">"test.ogg"</span>, <span class="n">4</span>, <span class="n">1024</span><span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></span></p><p>That&#39;s the cause: If you destroy a stream too quickly after it&#39;s created, it locks up.  I am attempting to diagnose it now.</p><p><b>Edit:</b> AH HA! I was right!  If the stream is destroyed too soon after it&#39;s created, <tt>_al_kcm_feed_stream</tt> deadlocks on the <tt>al_wait_for_event</tt> call at kcm_stream.c:682.  I confirmed this by breaking into the debugger while it was locked up and then attempting &quot;run to cursor&quot; on the next line after the event wait.  It never returns to the debugger.</p><p>This may not actually be a bug in the audio code but instead in the event queue system...</p><p><b>Edit 2:</b> Fixed with the following bit of shameless hackery:
</p><div class="source-code"><div class="toolbar"><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number"> 682</span><span class="k1">while</span> <span class="k2">(</span><span class="k3">!</span><a href="http://www.allegro.cc/manual/al_wait_for_event_timed"><span class="a">al_wait_for_event_timed</span></a><span class="k2">(</span>queue, <span class="k3">&amp;</span>event, <span class="n">0</span>.<span class="n">05</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 683</span>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/al_get_thread_should_stop"><span class="a">al_get_thread_should_stop</span></a><span class="k2">(</span>self<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 684</span>      event.type <span class="k3">=</span> _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE<span class="k2">;</span>
<span class="number"> 685</span>      <span class="k1">break</span><span class="k2">;</span>
<span class="number"> 686</span>   <span class="k2">}</span>
<span class="number"> 687</span><span class="k2">}</span>
</div></div><p>

<img src="http://www.allegro.cc/forums/smileys/tongue.gif" alt=":P" /> You should look into that event queue deadlock though.</p><p><b>Edit 3:</b> Any joy on diagnosing this?  It&#39;s definitely a race condition in the event queue system.  Best I can tell, if you emit an event too soon after the event source is created, it gets lost.  Thus in this case, the stream feeder gets stuck in a waitlock because the quit event has been &quot;lost in the mail&quot; so to speak and no other events are being emitted to satisfy the condition.  And since now the main thread is waiting on the feeder to quit... deadlock.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Mon, 20 Apr 2015 08:27:37 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Destroying the stream right away actually seems to deadlock for me too! Seems like we&#39;re in business... I&#39;ll see what I can do.</p><p>EDIT: Alright. Please try the attached patch, and see if it helps. It fixes the deadlock that I managed to reproduce, but I&#39;m specifically interested if it helps your actual use case in your game.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Tue, 28 Apr 2015 08:23:34 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>So at first I thought it wasn&#39;t fixed, but it turns out I accidentally linked against an older Allegro lib I built.  Oops!  I applied the patch, recompiled Allegro for both x86 and x64 and the deadlocks went away.  I even tried having it destroy and reload the stream a few times in succession; this obviously caused a sizable delay in loading sounds, but no deadlock! <img src="http://www.allegro.cc/forums/smileys/tongue.gif" alt=":P" /></p><p>Thanks for the fix.  This was a pretty annoying issue, and it seems I&#39;m not the first to discover it:<br /><a href="https://www.allegro.cc/forums/thread/610639">https://www.allegro.cc/forums/thread/610639</a></p><p>What&#39;s odd is that this never happened to me with 5.0.10.  What&#39;s changed since then?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Bruce Pascoe)</author>
		<pubDate>Tue, 28 Apr 2015 19:41:18 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Not sure, maybe something, somewhere got a little slower.</p><p>Anyway, I <a href="http://sourceforge.net/p/alleg/allegro/ci/5994b9b1284ca5dbae2a82817f9fa77c434cc989/">committed</a> that patch, so it all should be good now. Thanks for your help!
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (SiegeLord)</author>
		<pubDate>Wed, 29 Apr 2015 06:46:22 +0000</pubDate>
	</item>
</rss>
