[PATCH 2/3] winecoreaudio: Implement the lock-free callback design.

Joerg-Cyril.Hoehle at t-systems.com Joerg-Cyril.Hoehle at t-systems.com
Wed Feb 1 03:34:06 CST 2012


Hi,

> What does that not guarantee (that you'd like to have)?
Consider this scenario:

Play:
EnterCS-2
do some stuff, start playing
state=Playing;
LeaveCS-2

Stop:
EnterCS-1
do stuff
LeaveCS-1 ; because we want to wait for something to finish
wait
EnterCS-3
state=Stopped
LeaveCS-3

Now issue Stop + Play from 2 threads.
Play will start playing while the Stop thread is waiting.
Then CS-3 will stomp over the state, leading to inconsistent data structures.
The player thread is still running while the state variable indicates Stopped.


What can be done?
A. Design the system such that waiting can happen inside the CS.
winecoreaudio now can do that.


B. Design the system such that it accomodates transition states.
This means a much more complex state machine than the API describes.
"Can I restart playing if I'm mid-closing? mid-stopping?"
"Am I allowed to refuse starting playing when I acknowledged Stop earlier
 such that the app now believes I've stopped and submits the next song?"
It also likely begs for InterlockedCompareExchange and the sort.
You then have to be careful about which slots are valid when.
It is hard to get correct.
(An example of using Interlocked* is in dlls/mci*/mci*.c notification,
 can you spot the one fault?)

OO programmers (should) know this well: while mid-method, your object
state is not consistent; calling another method may call out to other
objects which can again call one of your API methods. But the average
API methods are not preprared to face the temporary inconsistent state.
Erlang avoids this by design.


C. Restart the transaction
Add a loop atop CS-1
After exiting CS-1 and waiting, check whether the state is the one you wish to reach.
Otherwise restart the loop.
(An example is PlaySound in dlls/winmm/playsound.c).
All implementations of interlocked lists do something like this:
check the final state and restart if not satisfying.


A variation on the above scenario, found in the MCI: the player thread wants to
enter Stopped state at the end, after waiting for all resources to be returned.
When is it allowed to modify the state variable?

Regards,
 Jörg Höhle


More information about the wine-devel mailing list