[alsa-devel] [PATCH 2/2] ALSA: x86: Avoid unconditional call of snd_pcm_period_elapsed()
Takashi Iwai
tiwai at suse.de
Fri Feb 10 10:25:07 CET 2017
On Tue, 07 Feb 2017 17:38:00 +0100,
Takashi Iwai wrote:
>
> At the interrupt handler, we usually call snd_pcm_period_elapsed() to
> inform the PCM core to proceed the hwptr. However, the hwptr update
> might have been already processed by the explicit call of PCM pointer
> callback via another thread. If both happen concurrently, the call of
> snd_pcm_period_elapsed() might be wrong.
>
> Here is the fix for this slightly possible race: had_process_ringbuf()
> returns the number of processed BDs, and the irq handler calls
> snd_pcm_period_elapsed() only when it's not zero.
Actually this looks like a wrong assumption. The call of
snd_pcm_period_elapsed() is still OK even after other thread already
updating hw_ptr, and it rather must call. The PCM timer notification
is triggered only in snd_pcm_period_elapsed(), thus without its call,
the PCM timer won't be updated properly. I drop this one.
Takashi
>
> Signed-off-by: Takashi Iwai <tiwai at suse.de>
> ---
> sound/x86/intel_hdmi_audio.c | 29 ++++++++++++++++++-----------
> 1 file changed, 18 insertions(+), 11 deletions(-)
>
> diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
> index 15147fec1a7e..a0c9a4e0c95d 100644
> --- a/sound/x86/intel_hdmi_audio.c
> +++ b/sound/x86/intel_hdmi_audio.c
> @@ -899,10 +899,13 @@ static void had_advance_ringbuf(struct snd_pcm_substream *substream,
> }
>
> /* process the current BD(s);
> - * returns the current PCM buffer byte position, or -EPIPE for underrun.
> + * returns the number of processed BDs, zero if no BD was processed,
> + * or -EPIPE for underrun.
> + * When @pos_ret is non-NULL, the current PCM buffer byte position is stored.
> */
> static int had_process_ringbuf(struct snd_pcm_substream *substream,
> - struct snd_intelhad *intelhaddata)
> + struct snd_intelhad *intelhaddata,
> + int *pos_ret)
> {
> int len, processed;
> unsigned long flags;
> @@ -917,7 +920,7 @@ static int had_process_ringbuf(struct snd_pcm_substream *substream,
> if (len < 0 || len > intelhaddata->period_bytes) {
> dev_dbg(intelhaddata->dev, "Invalid buf length %d\n",
> len);
> - len = -EPIPE;
> + processed = -EPIPE;
> goto out;
> }
>
> @@ -926,23 +929,27 @@ static int had_process_ringbuf(struct snd_pcm_substream *substream,
>
> /* len=0 => already empty, check the next buffer */
> if (++processed >= intelhaddata->num_bds) {
> - len = -EPIPE; /* all empty? - report underrun */
> + processed = -EPIPE; /* all empty? - report underrun */
> goto out;
> }
> had_advance_ringbuf(substream, intelhaddata);
> }
>
> - len = intelhaddata->period_bytes - len;
> - len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head;
> + if (pos_ret) {
> + len = intelhaddata->period_bytes - len;
> + len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head;
> + *pos_ret = len;
> + }
> out:
> spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
> - return len;
> + return processed;
> }
>
> /* called from irq handler */
> static void had_process_buffer_done(struct snd_intelhad *intelhaddata)
> {
> struct snd_pcm_substream *substream;
> + int processed;
>
> if (!intelhaddata->connected)
> return; /* disconnected? - bail out */
> @@ -952,9 +959,10 @@ static void had_process_buffer_done(struct snd_intelhad *intelhaddata)
> return; /* no stream? - bail out */
>
> /* process or stop the stream */
> - if (had_process_ringbuf(substream, intelhaddata) < 0)
> + processed = had_process_ringbuf(substream, intelhaddata, NULL);
> + if (processed < 0)
> snd_pcm_stop_xrun(substream);
> - else
> + else if (processed > 0)
> snd_pcm_period_elapsed(substream);
>
> had_substream_put(intelhaddata);
> @@ -1254,8 +1262,7 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
> if (!intelhaddata->connected)
> return SNDRV_PCM_POS_XRUN;
>
> - len = had_process_ringbuf(substream, intelhaddata);
> - if (len < 0)
> + if (had_process_ringbuf(substream, intelhaddata, &len) < 0)
> return SNDRV_PCM_POS_XRUN;
> return bytes_to_frames(substream->runtime, len);
> }
> --
> 2.11.0
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list