[Bug 48408] New: mixthread monopolizes buffer_list_lock if WaitForSingleObject returns quickly, causing livelock and game freeze
WineHQ Bugzilla
wine-bugs at winehq.org
Thu Jan 2 14:09:54 CST 2020
https://bugs.winehq.org/show_bug.cgi?id=48408
Bug ID: 48408
Summary: mixthread monopolizes buffer_list_lock if
WaitForSingleObject returns quickly, causing livelock
and game freeze
Product: Wine
Version: 5.0-rc3
Hardware: x86
OS: Linux
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: directx-dsound
Assignee: wine-bugs at winehq.org
Reporter: florian.will at gmail.com
Distribution: ---
Created attachment 66179
--> https://bugs.winehq.org/attachment.cgi?id=66179
C source for reproducing this issue, livelocks on my system
The default WaitForSingleObject implementation is not fast enough to trigger
this, but the bug manifests itself when starting wine-staging with WINEESYNC=1.
I originally reported this at
https://github.com/ValveSoftware/Proton/issues/3387 , but I am now able to
reproduce this on wine-staging. The problem is in dsound though.
The dsound mixthread locks the buffer_list_lock, then calls PerformMix(), then
releases the lock, then waits for something to happen using
WaitForSingleObject, then locks the buffer_list_lock again, in a loop.
This works fine when not using esync (I guess Valve's fsync also triggers the
same issue), since the default WaitForSingleObject implementation is slow
enough to allow other threads to acquire the buffer_list_lock while the
mixthread executes WaitForSingleObject. However, when esync is enabled AND the
mixthread has a lot of work to do (because there are many secondary sound
buffers), it apparently returns from WaitForSingleObject almost immediately,
and very quickly re-acquires the lock after releasing it. The lock
implementation does not guarantee fairness, and on my system, this results in
the mixthread monopolizing the buffer_list_lock.
If the main thread then wants to add a new secondary sound buffer to the list,
it attempts to acquire the buffer_list_lock exclusively, but it can take a very
long time to acquire the lock. This leads to a game freeze in Zusi 3 and maybe
other games / applications if there are lots of sound effects at the same time.
I have added a Sleep(1) in the mixthread before acquiring the lock, and it
fixed the freezes (but it will obviously cause audio stuttering to kick in
earlier than without the sleep). Disabling esync also fixes the freeze.
I came up with a simple reproducer, C source attached. Output is like this with
esync enabled:
[..]
Added buffer No. 283, took 0.056744 sec!
Added buffer No. 284, took 0.616793 sec!
Added buffer No. 285, took 16.775508 sec!
Added buffer No. 286, took 11.163868 sec!
Added buffer No. 287, took 26.308287 sec!
Obviously on more powerful systems with better single-thread CPU performance,
more buffers will be needed before it "almost-livelocks" like this. This output
is from my Phenom II X4 955. (If sound starts stuttering instead of the
freeze/lock, the bug did not manifest itself.)
With esync disabled (or when using my patched dsound.dll with "Sleep(1)"), it
never takes longer than 0.1 sec to add a buffer.
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list