[RFC PATCH v2 0/5] ASoC: soc-pcm: fix trigger race conditions with shared BE

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Thu Oct 7 17:24:45 CEST 2021



>>>> Takashi, Mark, do you think that an all/none assumption on FE nonatomic
>>>> properties would make sense?
>>>
>>> As long as BE's are updated from FE's PCM callback, BE has to follow
>>> the atomicity of its FE, so we can't assume all or none globally.
>>
>> A BE may have more than one FEs. That's precisely the point of
>> mixers/demux, and if the BE has FEs with different 'atomicity' then I
>> don't see how locking can work: the BE operations are run in the context
>> of each of its FE, typically using the following loop:
>>
>> for_each_dpcm_be(fe, stream, dpcm) {
>>    do_something();
>> }
> 
> Do we really have the cases where FEs have different atomicity?
> I don't think it's a valid configuration, and we should catch it via
> WARN_ON() or such.

I don't think we have this configuration today, that's why I suggested
making the assumption it's an unsupported configuration.

That would allow us to use the relevant locking mechanism, as done for
PCM streams.

>> Applications will view multiple FEs as completely independent. They may
>> be opened/prepared/started/stopped/paused as needed. When the BE is
>> shared, then there is a need for consistency, such as starting the BE
>> when the first FE becomes active and stopping it when the last FE stops.
>>
>>> How is the expected lock granularity and the protection context?  Do
>>> we need a card global lock/mutex, or is it specific to each BE
>>> substream?
>>
>> We already have a dpcm_lock at the card level, which protects the
>> addition of BEs and BE states. That spin_lock is fine for most cases.
>>
>> The only real problem is the trigger, which is currently completely
>> unprotected: we have to serialize the BE triggers, otherwise you could
>> STOP before you START due to scheduling, or other problems that I saw in
>> my SoundWire tests with two START triggers, or the STOP never sent.
> 
> So it's about calling triggers to the same BE stream concurrently?
> If that's the case, can't we simply protect the trigger handling of
> each BE like below?

Using snd_pcm_stream_lock_irqsave(be_substream, flags); will prevent
multiple triggers indeed, but the state management is handled by
dpcm_lock, so I think we have to use dpcm_lock/mutex in all BE transitions.

if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))

if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))

The position of the lock also matters, we may have to take the lock
before walking through the list, since that list can be modified. that's
what Gyeongtaek Lee reported with a separate patch, I was hoping that we
can fix all BE state handling in a consistent manner.


More information about the Alsa-devel mailing list