Duplicate wake-ups in pcm_lib.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks to Takashi's advice, I managed to find out the reason why I was
seeing null events returned by poll(). This could explain why
PulseAudio doesn't seem to sleep much. It turns out that we have two
calls to wakeup() in pcm_lib.c, and a nice race condition it seems.
See the log below.

A wake-up is generated during the period interrupt, and a second
wake-up is generated during the write loop, after the application was
awaken but just before the pointers are updated. This second wake-up
shouldn't exist, since the write loop actually fills the ring buffer.
By the time the second wake-up is actually handled, there's really no
space left in the buffer and a null event is generated; it'll wake-up
the application a second time for nothing. Maybe we should move the
call to snd_pcm_update_hw_ptr() after the transfer took place?

Can anyone apply the attached patches (only adds printks) and confirm
this issue on their platforms? That would be very useful.
Happy holidays everyone
- Pierre


alsa-lib/test/pcm --verbose -Dhw -c2 -r48000 -f440  --method write_and_poll

[  371.369865] snd_intel8x0_interrupt
[  371.369876]  snd_intel8x0_update
[  371.369884] snd_pcm_period_elapsed
[  371.369890]  snd_pcm_update_hw_ptr_interrupt
[  371.369900]    snd_pcm_update_hw_ptr_post
[  371.369909]     wakeup in snd_pcm_update_hw_ptr_post
sound/core/pcm_lib.c: 214, avail 8194, avail_min 8192
[  371.369935] ALSA: poll event  POLLOUT|POLLWRNORM, avail 8194 avail_min 8192
[  371.375449] snd_pcm_lib_write1: in
[  371.375457] snd_pcm_lib_write1 loop
[  371.375462]  snd_pcm_update_hw_ptr
[  371.375472]    snd_pcm_update_hw_ptr_post
[  371.375481]     wakeup in snd_pcm_update_hw_ptr_post
sound/core/pcm_lib.c: 214, avail 8462, avail_min 8192

>>Between these two points, the appl_ptr is updated, and there's no space left in the buffer. The wake-up is generated too early.

[  371.375514] snd_pcm_lib_write1: out
[  371.375524] ALSA: null poll event, avail 270 avail_min 8192
[  371.540532] snd_intel8x0_interrupt
[  371.540542]  snd_intel8x0_update
[  371.540551] snd_pcm_period_elapsed
[  371.540556]  snd_pcm_update_hw_ptr_interrupt
[  371.540566]    snd_pcm_update_hw_ptr_post
[  371.540575]     wakeup in snd_pcm_update_hw_ptr_post
sound/core/pcm_lib.c: 214, avail 8194, avail_min 8192
[  371.540601] ALSA: poll event  POLLOUT|POLLWRNORM, avail 8194 avail_min 8192
[  371.543734] snd_pcm_lib_write1: in
[  371.543741] snd_pcm_lib_write1 loop
[  371.543746]  snd_pcm_update_hw_ptr
[  371.543755]    snd_pcm_update_hw_ptr_post
[  371.543764]     wakeup in snd_pcm_update_hw_ptr_post
sound/core/pcm_lib.c: 214, avail 8347, avail_min 8192
[  371.543797] snd_pcm_lib_write1: out
[  371.543807] ALSA: null poll event, avail 155 avail_min 8192
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 30f4108..d6f831f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -191,6 +191,8 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
 {
 	snd_pcm_uframes_t avail;
 
+        printk(KERN_ERR "   snd_pcm_update_hw_ptr_post");
+        
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		avail = snd_pcm_playback_avail(runtime);
 	else
@@ -208,8 +210,10 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
 			return -EPIPE;
 		}
 	}
-	if (avail >= runtime->control->avail_min)
+	if (avail >= runtime->control->avail_min) {
+                printk(KERN_ERR "    wakeup in snd_pcm_update_hw_ptr_post %s: %d, avail %d, avail_min %d",__FILE__,__LINE__,avail,runtime->control->avail_min );
 		wake_up(&runtime->sleep);
+        }
 	return 0;
 }
 
@@ -231,6 +235,8 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 	snd_pcm_sframes_t hdelta, delta;
 	unsigned long jdelta;
 
+        printk(KERN_ERR " snd_pcm_update_hw_ptr_interrupt");
+        
 	old_hw_ptr = runtime->status->hw_ptr;
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
 	if (pos == SNDRV_PCM_POS_XRUN) {
@@ -363,6 +369,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 	snd_pcm_sframes_t delta;
 	unsigned long jdelta;
 
+        printk(KERN_ERR " snd_pcm_update_hw_ptr");
+        
 	old_hw_ptr = runtime->status->hw_ptr;
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
 	if (pos == SNDRV_PCM_POS_XRUN) {
@@ -1634,6 +1642,8 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime;
 	unsigned long flags;
 
+        printk(KERN_ERR "snd_pcm_period_elapsed");
+        
 	if (PCM_RUNTIME_CHECK(substream))
 		return;
 	runtime = substream->runtime;
@@ -1756,6 +1766,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 	snd_pcm_uframes_t offset = 0;
 	int err = 0;
 
+        printk(KERN_ERR "snd_pcm_lib_write1: in");
+        
 	if (size == 0)
 		return 0;
 
@@ -1780,8 +1792,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
-		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
+		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
+                    printk(KERN_ERR "snd_pcm_lib_write1 loop");
+                    snd_pcm_update_hw_ptr(substream);
+                }
 		avail = snd_pcm_playback_avail(runtime);
 		if (!avail) {
 			if (nonblock) {
@@ -1836,6 +1850,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
  _end_unlock:
 	snd_pcm_stream_unlock_irq(substream);
  _end:
+        printk(KERN_ERR "snd_pcm_lib_write1: out");
 	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
@@ -1998,7 +2013,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
 		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
+                {
+                    printk(KERN_ERR "snd_pcm_lib_read1 loop");
+                    snd_pcm_update_hw_ptr(substream);
+                }
 		avail = snd_pcm_capture_avail(runtime);
 		if (!avail) {
 			if (runtime->status->state ==
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 29ab46a..048052a 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2903,13 +2903,16 @@ static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
 	case SNDRV_PCM_STATE_PAUSED:
 		if (avail >= runtime->control->avail_min) {
 			mask = POLLOUT | POLLWRNORM;
+                        printk(KERN_ERR "ALSA: poll event  POLLOUT|POLLWRNORM, avail %d avail_min %d",avail,runtime->control->avail_min );
 			break;
 		}
+                printk(KERN_ERR "ALSA: null poll event, avail %d avail_min %d",avail,runtime->control->avail_min );
 		/* Fall through */
 	case SNDRV_PCM_STATE_DRAINING:
 		mask = 0;
 		break;
 	default:
+                printk(KERN_ERR "ALSA: default, avail %d avail_min %d",avail,runtime->control->avail_min );
 		mask = POLLOUT | POLLWRNORM | POLLERR;
 		break;
 	}
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux