This shows you the differences between two versions of the page.
| Next revision | Previous revision |
| ryanbeasley:notes:snd_locking [2006/08/04 01:38] – RyanBeasley | ryanbeasley:notes:snd_locking [2008/06/17 21:37] (current) – converted to 1.6 markup 127.0.0.1 |
|---|
| Another toughy are SNDCTL_DSP_SYNCGROUP and SNDCTL_DSP_SYNCSTART. Syncgroups are singly-linked lists of PCM channels set to begin playing at the same time. These lists are also kept in a singly linked list, since the number of entries is small and nearly all insert/remove operations are done at the head. The master list (and all member group lists) are protected by a single mutex, so it is important that a caller acquire this mutex first //without// any channel locks held. This is necessary for the SYNCSTART operation which iterates over all channels in a group, locks them, and begins playback/recording. | Another toughy are SNDCTL_DSP_SYNCGROUP and SNDCTL_DSP_SYNCSTART. Syncgroups are singly-linked lists of PCM channels set to begin playing at the same time. These lists are also kept in a singly linked list, since the number of entries is small and nearly all insert/remove operations are done at the head. The master list (and all member group lists) are protected by a single mutex, so it is important that a caller acquire this mutex first //without// any channel locks held. This is necessary for the SYNCSTART operation which iterates over all channels in a group, locks them, and begins playback/recording. |
| |
| Hack of a solution: in addition to a mutex, each channel maintains a conditional variable (//cv//) and in progress counter (//inprog//). For operations which might temporarily give up the mutex, //inprog// is incremented before releasing the mutex. Any other thread that acquires the channel lock should inspect //inprog// - if it is non-zero, that thread should call cv_wait() on the channel's lock & cv. (This is typically done in a loop.) When the owning thread reacquires the lock, it should decrement //inprog// and call cv_signal() on the lock & cv. | Hack of a solution: in addition to a mutex, each channel maintains a conditional variable (**cv**) and in progress counter (**inprog**). For operations which might temporarily give up the mutex, **inprog** is incremented before releasing the mutex. Any other thread that acquires the channel lock should inspect **inprog** - if it is non-zero, that thread should call cv_wait() on the channel's lock & cv. (This is typically done in a loop.) When the owning thread reacquires the lock, it should decrement **inprog** and call cv_signal() on the lock & cv. |
| |
| Implementing that scheme would require updating channel.c::chn_lock() to include the cv handling, then updating CHN_LOCK/CHN_UNLOCK macros to make use of these checks. | Implementing that scheme would require updating channel.c::chn_lock() to include the cv handling, then updating CHN_LOCK/CHN_UNLOCK macros to make use of these checks. |
| |
| ==== Interrupts ==== | ==== Interrupts ==== |
| | - CHN_LOCK(channel) |
| | - chn_{wr,rd}intr() |
| | - CHN_UNLOCK(channel) |
| |