[alsa-devel] 2.6.30: xruns caused by "ALSA: pcm - Safer boundary checks"

Takashi Iwai tiwai at suse.de
Fri May 22 23:52:45 CEST 2009


At Fri, 22 May 2009 16:27:09 -0400,
Chuck Ebbert wrote:
> 
> Bug report: https://bugzilla.redhat.com/show_bug.cgi?id=498858
> 
> To reproduce, pause a video in mplayer and then hit play:
> 
> ALSA sound/core/pcm_lib.c:263: hda_codec: hw_ptr skipping! [Q] (pos=11263,
> delta=17400, period=1024, jdelta=21/362/0)

Does the patch fix the problem?


thanks,

Takashi

---
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index c172968..7366910 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -266,6 +266,7 @@ struct snd_pcm_runtime {
 	struct snd_pcm_substream *trigger_master;
 	struct timespec trigger_tstamp;	/* trigger timestamp */
 	int overrange;
+	unsigned int jiffies_set:1;	/* hw_ptr_jiffies is set */
 	snd_pcm_uframes_t avail_max;
 	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
 	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a2a792c..78edd6e 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -249,6 +249,8 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 			new_hw_ptr = hw_base + pos;
 		}
 	}
+	if (!runtime->jiffies_set)
+		goto no_jiffies_check;
 	/* Skip the jiffies check for hardwares with BATCH flag.
 	 * Such hardware usually just increases the position at each IRQ,
 	 * thus it can't give any strange position.
@@ -296,6 +298,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 	runtime->hw_ptr_jiffies = jiffies;
+	runtime->jiffies_set = 1;
 	runtime->hw_ptr_interrupt = hw_ptr_interrupt;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
@@ -336,7 +339,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 			hw_base = 0;
 		new_hw_ptr = hw_base + pos;
 	}
-	if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
+	if (runtime->jiffies_set &&
+	    ((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
 		hw_ptr_error(substream,
 			     "hw_ptr skipping! "
 			     "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -352,6 +356,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 	runtime->hw_ptr_jiffies = jiffies;
+	runtime->jiffies_set = 1;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -1478,7 +1483,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
 		runtime->status->hw_ptr %= runtime->buffer_size;
 	else
 		runtime->status->hw_ptr = 0;
-	runtime->hw_ptr_jiffies = jiffies;
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 	return 0;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index fc6f98e..5cf67a5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -978,6 +978,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_trigger_tstamp(substream);
+	runtime->jiffies_set = 0;
 	if (push) {
 		runtime->status->state = SNDRV_PCM_STATE_PAUSED;
 		if (substream->timer)
@@ -1041,6 +1042,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
 				 &runtime->trigger_tstamp);
 	runtime->status->suspended_state = runtime->status->state;
 	runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
+	runtime->jiffies_set = 0;
 	wake_up(&runtime->sleep);
 }
 
@@ -1234,6 +1236,7 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
 		runtime->status->hw_ptr % runtime->period_size;
 	runtime->silence_start = runtime->status->hw_ptr;
 	runtime->silence_filled = 0;
+	runtime->jiffies_set = 0;
 	return 0;
 }
 


More information about the Alsa-devel mailing list