提交 12ff414e 编写于 作者: K Kelly Anderson 提交者: Takashi Iwai

ALSA: pcm: fix infinite loop in snd_pcm_update_hw_ptr0()

When period interrupts are disabled, snd_pcm_update_hw_ptr0() compares
the current time against the time estimated for the current hardware
pointer to detect xruns.  The somewhat fuzzy threshold in the while loop
makes it possible that hdelta becomes negative; the comparison being
done with unsigned types then makes the loop go through the entire 263
negative range, and, depending on the value, never reach an unsigned
value that is small enough to stop the loop.  Doing this with interrupts
disabled results in the machine locking up.

To prevent this, ensure that the loop condition uses signed types for
both operands so that the comparison is correctly done.

Many thanks to Kelly Anderson for debugging this.
Reported-by: NNix <nix@esperi.org.uk>
Reported-by: N"Christopher K." <c.krooss@googlemail.com>
Reported-and-tested-by: NKelly Anderson <kelly@silka.with-linux.com>
Signed-off-by: NKelly Anderson <kelly@silka.with-linux.com>
[cl: remove unneeded casts; use a temp variable]
Signed-off-by: NClemens Ladisch <clemens@ladisch.de>
Cc: 2.6.38 <stable@kernel.org>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 84012657
...@@ -375,6 +375,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -375,6 +375,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
} }
if (runtime->no_period_wakeup) { if (runtime->no_period_wakeup) {
snd_pcm_sframes_t xrun_threshold;
/* /*
* Without regular period interrupts, we have to check * Without regular period interrupts, we have to check
* the elapsed time to detect xruns. * the elapsed time to detect xruns.
...@@ -383,7 +384,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -383,7 +384,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
goto no_delta_check; goto no_delta_check;
hdelta = jdelta - delta * HZ / runtime->rate; hdelta = jdelta - delta * HZ / runtime->rate;
while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
while (hdelta > xrun_threshold) {
delta += runtime->buffer_size; delta += runtime->buffer_size;
hw_base += runtime->buffer_size; hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary) if (hw_base >= runtime->boundary)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册