[alsa-devel] [RFC][PATCH] ALSA: firewire-lib: permit process context only to flush queued packets for better PCM period granularity

Takashi Sakamoto o-takashi at sakamocchi.jp
Wed May 11 19:21:43 CEST 2016


Hi Clemens,

On May 11 2016 16:31, Clemens Ladisch wrote:
> Sorry for the delay.
> 
> Takashi Sakamoto wrote:
>> These three commits were merged to improve PCM pointer granularity.
>> commit 76fb87894828 ("ALSA: firewire-lib: taskletize the snd_pcm_period_elapsed() call")
>> commit e9148dddc3c7 ("ALSA: firewire-lib: flush completed packets when reading PCM position")
>> commit 92b862c7d685 ("ALSA: firewire-lib: optimize packet flushing")
>>
>> The point of them is to handle queued packets not only in software IRQ
>> context of IR/IT contexts, but also in process context. This idea
>> introduced a cyclic call of 'struct snd_pcm_ops.pointer()'.
> 
> There is no recursion because of the tasklet.  The only problem is that
> the tasklet could be scheduled repeatedly because new packets continue
> to arrive.  But even when this happens, it's harmless.
> 
>> The last commit adds 'pointer_flush' member to 'struct amdtp_stream'
>> to avoid the situation. On the other hand, This solution is weak at
>> race condition between the process context and the software IRQ
>> context of IR/IT contexts.
>>
>> Practically, this race is not so critical because it influences process
>> context to skip flushing queued packets and to get worse granularity of
>> PCM pointer.
> 
> When a race causes pointer_flush to be read as true although it should
> be false, there is simply a superfluous call to flush_completions.
> 
> When pointer_flush is read as false although it should be true, then the
> buffer_pointer value _might_ not be the most current one (due to the
> missing flush), but this is unlikely to happen because the buffer_pointer
> was just updated by update_pcm_pointers().  In any case, the just-
> scheduled tasklet will inform the application about the new pointer.
> 
>> The similar solution can be achieved by 'in_interrupt()' macro. This
>> commit applies the macro to solve the race condition against
>> 'pointer_flush'.
> 
>>  unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
>>  {
>> -	/* this optimization is allowed to be racy */
>> -	if (s->pointer_flush && amdtp_stream_running(s))
>> ...
>> +	if (!in_interrupt() && amdtp_stream_running(s))
>>  		fw_iso_context_flush_completions(s->context);
>> -	else
>> -		s->pointer_flush = true;
>>
>>  	return ACCESS_ONCE(s->pcm_buffer_pointer);
>>  }
> 
> Looks good.
> 
> Acked-by: Clemens Ladisch <clemens at ladisch.de>

OK. Thanks for reviewing. I've posted a patch with updated comments and
the tag.

>> And I think there's another race condition against processing each packets
>> by calling out/in_stream_callback(), but I cannot observe the race.
> 
> As you already found out, fw_iso_context_flush_completions() is thread
> safe.


Regards

Takashi Sakamoto


More information about the Alsa-devel mailing list