One of the most important (and thus difficult to debug) problems in kernel programming are race conditions. In the Linux kernel, they are usually avoided via spin-locks, mutexes or semaphores. In general, if a race condition can happen in an interrupt handler, it has to be managed atomically, and you have to use a spinlock to protect the critical session. If the critical section is not in interrupt handler code and if taking a relatively long time to execute is acceptable, you should use mutexes or semaphores instead.
As already seen, some pcm callbacks are atomic and some are
not. For example, the hw_params
callback is
non-atomic, while trigger
callback is
atomic. This means, the latter is called already in a spinlock
held by the PCM middle layer. Please take this atomicity into
account when you choose a locking scheme in the callbacks.
In the atomic callbacks, you cannot use functions which may call
schedule
or go to
sleep
. Semaphores and mutexes can sleep,
and hence they cannot be used inside the atomic callbacks
(e.g. trigger
callback).
To implement some delay in such a callback, please use
udelay()
or mdelay()
.
All three atomic callbacks (trigger, pointer, and ack) are called with local interrupts disabled.
The recent changes in PCM core code, however, allow all PCM
operations to be non-atomic. This assumes that the all caller
sides are in non-atomic contexts. For example, the function
snd_pcm_period_elapsed()
is called
typically from the interrupt handler. But, if you set up the
driver to use a threaded interrupt handler, this call can be in
non-atomic context, too. In such a case, you can set
nonatomic
filed of
snd_pcm object after creating it.
When this flag is set, mutex and rwsem are used internally in
the PCM core instead of spin and rwlocks, so that you can call
all PCM functions safely in a non-atomic context.