Re: snd_pcsp locking mess

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

 



Hello.

Takashi Iwai wrote:
> No, close callback is always after the hw_free callback.
> So, in hw_free callback, you just need to assure that hrtimer callback
> is finished (and/or cancel it).  After that, you are free to work
> without considering hrtimer stuff.
Here is my first attempt on that.
The optimization you mention above
is possible, but I haven't done it
(yet). Because I think it will obscure
things.
I can't really say if this code is
better than before - it looks cleaner
but adds 3 locks.

> We don't drop pcm substream lock here because we don't need to acquire
> it.
Why not? Because it is not recommended
to use any more, or for some other
reason? I mostly need the hrtimer
callback to be protected from all
the pcm callbacks, modulo the (IMO
questionable) optimization. So why
not would I just use the substream
lock?
diff -r 63405ae5a92b drivers/pcsp/pcsp.c
--- a/drivers/pcsp/pcsp.c	Tue May 27 15:37:48 2008 +0400
+++ b/drivers/pcsp/pcsp.c	Tue May 27 17:24:31 2008 +0400
@@ -73,6 +73,9 @@
 	pcsp_chip.pcspkr = 1;
 
 	spin_lock_init(&pcsp_chip.substream_lock);
+	spin_lock_init(&pcsp_chip.dmabuf_lock);
+	spin_lock_init(&pcsp_chip.ptr_lock);
+	spin_lock_init(&pcsp_chip.timer_lock);
 
 	pcsp_chip.card = card;
 	pcsp_chip.port = 0x61;
diff -r 63405ae5a92b drivers/pcsp/pcsp.h
--- a/drivers/pcsp/pcsp.h	Tue May 27 15:37:48 2008 +0400
+++ b/drivers/pcsp/pcsp.h	Tue May 27 17:24:31 2008 +0400
@@ -61,6 +61,9 @@
 	struct hrtimer timer;
 	unsigned short port, irq, dma;
 	spinlock_t substream_lock;
+	spinlock_t dmabuf_lock;
+	spinlock_t ptr_lock;
+	spinlock_t timer_lock;
 	struct snd_pcm_substream *playback_substream;
 	size_t playback_ptr;
 	size_t period_ptr;
diff -r 63405ae5a92b drivers/pcsp/pcsp_lib.c
--- a/drivers/pcsp/pcsp_lib.c	Tue May 27 15:37:48 2008 +0400
+++ b/drivers/pcsp/pcsp_lib.c	Tue May 27 17:24:31 2008 +0400
@@ -40,34 +40,23 @@
 	}
 
 	spin_lock_irq(&chip->substream_lock);
-	/* Takashi Iwai says regarding this extra lock:
-
-	If the irq handler handles some data on the DMA buffer, it should
-	do snd_pcm_stream_lock().
-	That protects basically against all races among PCM callbacks, yes.
-	However, there are two remaining issues:
-	1. The substream pointer you try to lock isn't protected _before_
-	  this lock yet.
-	2. snd_pcm_period_elapsed() itself acquires the lock.
-	The requirement of another lock is because of 1.  When you get
-	chip->playback_substream, it's not protected.
-	Keeping this lock while snd_pcm_period_elapsed() assures the substream
-	is still protected (at least, not released).  And the other status is
-	handled properly inside snd_pcm_stream_lock() in
-	snd_pcm_period_elapsed().
-
-	*/
 	if (!chip->playback_substream)
 		goto exit_nr_unlock1;
 	substream = chip->playback_substream;
-	snd_pcm_stream_lock(substream);
+
+	spin_lock(&chip->timer_lock);
 	if (!atomic_read(&chip->timer_active))
 		goto exit_nr_unlock2;
 
 	runtime = substream->runtime;
 	fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3;
+	spin_lock(&chip->ptr_lock);
 	/* assume it is mono! */
+	spin_lock(&chip->dmabuf_lock);
+	if (!runtime->dma_area)
+		goto exit_nr_unlock4;
 	val = runtime->dma_area[chip->playback_ptr + fmt_size - 1];
+	spin_unlock(&chip->dmabuf_lock);
 	if (snd_pcm_format_signed(runtime->format))
 		val ^= 0x80;
 	timer_cnt = val * CUR_DIV() / 256;
@@ -101,13 +90,15 @@
 	/* wrap the pointer _before_ calling snd_pcm_period_elapsed(),
 	 * or ALSA will BUG on us. */
 	chip->playback_ptr %= buffer_bytes;
-
-	snd_pcm_stream_unlock(substream);
+	spin_unlock(&chip->ptr_lock);
+	spin_unlock(&chip->timer_lock);
 
 	if (periods_elapsed) {
 		snd_pcm_period_elapsed(substream);
+		spin_lock(&chip->ptr_lock);
 		chip->period_ptr += periods_elapsed * period_bytes;
 		chip->period_ptr %= buffer_bytes;
+		spin_unlock(&chip->ptr_lock);
 	}
 
 	spin_unlock_irq(&chip->substream_lock);
@@ -121,8 +112,11 @@
 	hrtimer_forward(&chip->timer, chip->timer.expires, ktime_set(0, ns));
 	return HRTIMER_RESTART;
 
+exit_nr_unlock4:
+	spin_unlock(&chip->dmabuf_lock);
+	spin_unlock(&chip->ptr_lock);
 exit_nr_unlock2:
-	snd_pcm_stream_unlock(substream);
+	spin_unlock(&chip->timer_lock);
 exit_nr_unlock1:
 	spin_unlock_irq(&chip->substream_lock);
 	return HRTIMER_NORESTART;
@@ -142,7 +136,9 @@
 	chip->val61 = inb(0x61) | 0x03;
 	outb_p(0x92, 0x43);	/* binary, mode 1, LSB only, ch 2 */
 	spin_unlock(&i8253_lock);
+	spin_lock(&chip->timer_lock);
 	atomic_set(&chip->timer_active, 1);
+	spin_unlock(&chip->timer_lock);
 	chip->thalf = 0;
 
 	hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
@@ -156,7 +152,9 @@
 	if (!atomic_read(&chip->timer_active))
 		return;
 
+	spin_lock(&chip->timer_lock);
 	atomic_set(&chip->timer_active, 0);
+	spin_unlock(&chip->timer_lock);
 	spin_lock(&i8253_lock);
 	/* restore the timer */
 	outb_p(0xb6, 0x43);	/* binary, mode 3, LSB/MSB, ch 2 */
@@ -184,19 +182,25 @@
 				       struct snd_pcm_hw_params *hw_params)
 {
 	int err;
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+	spin_lock_irq(&chip->dmabuf_lock);
 	err = snd_pcm_lib_malloc_pages(substream,
 				      params_buffer_bytes(hw_params));
-	if (err < 0)
-		return err;
-	return 0;
+	spin_unlock_irq(&chip->dmabuf_lock);
+	return err;
 }
 
 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
 {
+	int err;
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: hw_free called\n");
 #endif
-	return snd_pcm_lib_free_pages(substream);
+	spin_lock_irq(&chip->dmabuf_lock);
+	err = snd_pcm_lib_free_pages(substream);
+	spin_unlock_irq(&chip->dmabuf_lock);
+	return err;
 }
 
 static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
@@ -211,8 +215,10 @@
 			snd_pcm_lib_period_bytes(substream),
 			substream->runtime->periods);
 #endif
+	spin_lock_irq(&chip->ptr_lock);
 	chip->playback_ptr = 0;
 	chip->period_ptr = 0;
+	spin_unlock_irq(&chip->ptr_lock);
 	return 0;
 }
 
_______________________________________________
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