From: Stas Sergeev <stsp@aknet.ru>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@alsa-project.org
Subject: Re: snd_pcsp locking mess
Date: Tue, 27 May 2008 17:47:19 +0400 [thread overview]
Message-ID: <483C10E7.7070203@aknet.ru> (raw)
In-Reply-To: <s5hprrduwdk.wl%tiwai@suse.de>
[-- Attachment #1: Type: text/plain, Size: 840 bytes --]
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?
[-- Attachment #2: a.diff --]
[-- Type: text/x-patch, Size: 5117 bytes --]
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;
}
[-- Attachment #3: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
next prev parent reply other threads:[~2008-05-27 13:47 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20080518172258.D0DFB108060@picon.linux-foundation.org>
2008-05-18 18:20 ` snd_pcsp locking mess Stas Sergeev
2008-05-19 5:50 ` Takashi Iwai
2008-05-19 17:01 ` Stas Sergeev
2008-05-21 12:33 ` Takashi Iwai
2008-05-22 20:28 ` Stas Sergeev
2008-05-23 10:51 ` Takashi Iwai
2008-05-27 13:46 ` Stas Sergeev
2008-05-27 13:47 ` Stas Sergeev [this message]
2008-05-27 15:50 ` Takashi Iwai
2008-05-27 17:40 ` Stas Sergeev
2008-05-28 10:13 ` Takashi Iwai
2008-05-28 20:08 ` Stas Sergeev
2008-05-29 6:03 ` Takashi Iwai
2008-05-29 17:07 ` Stas Sergeev
2008-06-02 9:36 ` Takashi Iwai
2008-08-21 8:06 ` Stas Sergeev
2008-08-21 9:06 ` Takashi Iwai
2008-08-21 10:25 ` Stas Sergeev
2008-10-20 13:05 ` Takashi Iwai
2008-10-20 21:51 ` Stas Sergeev
2008-10-21 6:27 ` Takashi Iwai
2008-10-21 7:08 ` Stas Sergeev
2008-10-21 7:16 ` Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=483C10E7.7070203@aknet.ru \
--to=stsp@aknet.ru \
--cc=alsa-devel@alsa-project.org \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox