http://bugs.winehq.org/show_bug.cgi?id=28464
Summary: winmm causes DSOUND_callback Wave queue corrupted Product: Wine Version: 1.3.25 Platform: x86 OS/Version: All Status: UNCONFIRMED Severity: normal Priority: P2 Component: winmm&mci AssignedTo: wine-bugs@winehq.org ReportedBy: hoehle@users.sourceforge.net
WHDR_DONE should only be set immediately before invoking the DriverCallback, because some apps poll for that flag and don't depend on notifications or callbacks.
WOD_MarkDoneHeaders must find another way to isolate done headers.
Because the queue of done headers is not isolated properly, attachment #36494 to bug #28056 exhibits a log (around line 4250) where 2 threads, namely the app calling waveOutWrite and the winmm feeder thread both grab the same list and send the same notifications.
0034:trace:driver:DriverCallback (, 32bit function 0003,, 03BD,, 017D3A90, 00000000) 0036:trace:winmm:WINMM_BeginPlaying ... 0036:trace:oss:AudioRenderClient_ReleaseBuffer (0x17d34f0)->(512, 0) 0034:trace:driver:DriverCallback (, 32bit function 0003,, 03BD,, 017D3AB0, 00000000) 0034:trace:driver:DriverCallback (, 32bit function 0003,, 03BD,, 017D3AD0, 00000000) 0034:trace:winmm:WOD_PushData (0xc000) 0036:trace:driver:DriverCallback (, 32bit function 0003,, 03BD,, 017D3AB0, 00000000) 0036:trace:driver:DriverCallback (, 32bit function 0003,, 03BD,, 017D3AD0, 00000000)
What happens is that the first thread removes the first header from device>first. At the time the second thread kicks in, apparently more headers are marked done. But since they are all part of the same linked queue, the later ones trigger 2 notifications each.
err:dsound:DSOUND_callback Wave queue corrupted! is the result of getting notifications twice.
Nice race condition!
BTW, but that's another issue, the code says "NotifyClient should never be called while holding the device lock". However that's exactly what can happen via waveOutWrite -> WINMM_ValidateAndLock -> WINMM_BeginPlaying -> WOD_PushData -> NotifyClient. I suggest a per device slot updated via InterlockedExchangePointer holding the queue of pending notifications. The top-level wave* commands (and the winmm feeder thread too) would then drain that queue. (The feeder thread could even delegate that to another (timer?) thread.) Alternatively, Push/PullData return that queue.
http://bugs.winehq.org/show_bug.cgi?id=28464
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |aeikum@codeweavers.com
http://bugs.winehq.org/show_bug.cgi?id=28464
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Severity|normal |major
--- Comment #1 from Jörg Höhle hoehle@users.sourceforge.net 2011-09-21 20:18:24 CDT --- Issuing notifications twice causes havoc in all winmm applications (incl. all dsound emulation -> winmm -> mmdevapi ones) => major bug
http://bugs.winehq.org/show_bug.cgi?id=28464
Dan Kegel dank@kegel.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dank@kegel.com
--- Comment #2 from Dan Kegel dank@kegel.com 2011-09-21 22:43:27 CDT --- Could you write a conformance test that tickles this bug?
http://bugs.winehq.org/show_bug.cgi?id=28464
--- Comment #3 from Jörg Höhle hoehle@users.sourceforge.net 2011-09-22 14:34:56 CDT --- Sorry, I see better investments of my time. I'd rather add GetPosition, WHDR_BEGIN/ENDLOOP and waveOutRestart tests to winmm/tests/wave.c
The log file is there, and my explanation of the behaviour logical, with one fault: at the time the second threads kicks in, there need not be more buffers marked done, having >1 buffers marked done initially is enough. The first thread returns device->first, and the second device->oldfirst->lpNext, so the second buffer is notified twice. That's exactly what the log shows: A9 is notified once, AB and AD twice.
Several things must occur concurrently to trigger the bug: - several buffers marked done and - waveOutWrite concurrent with feeder thread.
BTW, I already wrote 2/3 of a patch.
http://bugs.winehq.org/show_bug.cgi?id=28464
Dmitry Timoshkov dmitry@baikal.ru changed:
What |Removed |Added ---------------------------------------------------------------------------- OS/Version|All |other
http://bugs.winehq.org/show_bug.cgi?id=28464
--- Comment #4 from Jörg Höhle hoehle@users.sourceforge.net 2011-09-23 03:46:49 CDT --- Created attachment 36518 --> http://bugs.winehq.org/attachment.cgi?id=36518 Set WHDR_DONE right before DriverCallback
This patch separates the to_play queue from the done queue.
Note that threading might allow thread #2 to issue DriverCallback before thread #1... The notification order would be messed up! There's no solution to this short of having a unique thread send out all asynchronous notifications (cf. bug #3930, it looks like native actually does that).
http://bugs.winehq.org/show_bug.cgi?id=28464
--- Comment #5 from Jörg Höhle hoehle@users.sourceforge.net 2011-09-26 09:02:07 CDT --- Note that the WHDR_DONE patch is incomplete without my other patch: winmm: waveOutReset returns all buffers -- submitted today http://www.winehq.org/pipermail/wine-patches/2011-September/107249.html
http://bugs.winehq.org/show_bug.cgi?id=28464
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Severity|major |normal
--- Comment #6 from Jörg Höhle hoehle@users.sourceforge.net 2011-10-07 08:57:51 CDT --- All my patches are in git since 1.3.30. All that's remaining is the possibility that notifications are sent out of order when both the winmm feeder and the app thread call WOD_PushData simultaneously.
One solution path looks like dissociating writing from notification sending in PushData. Only the feeder thread shall send WHDR_DONE, except in the case of waveOutReset. The app thread shall still write directly (via PushData) from within waveOutWrite, not necessarily delegating to the feeder thread.
http://bugs.winehq.org/show_bug.cgi?id=28464
xangel1@mail.ru changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |xangel1@mail.ru
http://bugs.winehq.org/show_bug.cgi?id=28464
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Summary|winmm causes |winmm may send WHDR_DONE |DSOUND_callback Wave queue |notifications in wrong |corrupted |order Severity|normal |enhancement
http://bugs.winehq.org/show_bug.cgi?id=28464
--- Comment #7 from Austin English austinenglish@gmail.com 2013-11-13 16:50:58 CST --- This is your friendly reminder that there has been no bug activity for 2 years. Is this still an issue in current (1.7.6 or newer) wine? If so, please attach the terminal output in 1.7.6 (see http://wiki.winehq.org/FAQ#get_log).
https://bugs.winehq.org/show_bug.cgi?id=28464
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |ABANDONED
--- Comment #8 from Austin English austinenglish@gmail.com --- Abandoned.
https://bugs.winehq.org/show_bug.cgi?id=28464
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #9 from Austin English austinenglish@gmail.com --- Closing.
https://bugs.winehq.org/show_bug.cgi?id=28464
Rosanne DiMesio dimesio@earthlink.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |mywine@schiermeier-it.de
--- Comment #10 from Rosanne DiMesio dimesio@earthlink.net --- *** Bug 55514 has been marked as a duplicate of this bug. ***