[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