pcm & exclusive sleep mutex with Oct19 CURRENT
Mathew Kanner
mat at cnd.mcgill.ca
Tue Oct 21 11:44:55 PDT 2003
Hello Paolo,
See below.
On Oct 20, Paolo Pisati wrote:
> from my dmesg:
> [snip]
> exclusive sleep mutex pcm0:mixer (pcm mixer) r = 0 (0xc2d34540) locked @ /usr/src/sys/dev/sound/pcm/mixer.c:322
Could you try deleting the snd_mtxlock and snd_mtxunlock in
mixer_hwvol_init() in mixer.c? I think it's uneeded as the function
is only called in particular device instance creation and no-one
should be able touch it yet.
>
> acquiring duplicate lock of same type: "pcm channel"
> 1st pcm0:record:0 @ /usr/src/sys/dev/sound/pcm/sound.c:195
> 2nd pcm0:play:0 @ /usr/src/sys/dev/sound/pcm/sound.c:195
> Stack backtrace:
Please try my "wild guess" patch that is attached. I tried to
re-arrange the routine to only hold one locked channel at a time. I
suppose another option would be flag the lock type as having
duplicates ok.
--Mat
--
If you optimize everything, you will always be unhappy.
- Don Knuth
-------------- next part --------------
--- dspold.c Sun Sep 14 17:49:38 2003
+++ dsp.c Tue Oct 21 14:38:44 2003
@@ -174,6 +174,8 @@
intrmask_t s;
u_int32_t fmt;
int devtype;
+ int rdref;
+ int error;
s = spltty();
d = dsp_get_info(i_dev);
@@ -209,6 +211,8 @@
panic("impossible devtype %d", devtype);
}
+ rdref = 0;
+
/* lock snddev so nobody else can monkey with it */
pcm_lock(d);
@@ -251,67 +255,66 @@
return EBUSY;
}
/* got a channel, already locked for us */
- }
-
- if (flags & FWRITE) {
- /* open for write */
- wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
- if (!wrch) {
- /* no channel available */
- if (flags & FREAD) {
- /* just opened a read channel, release it */
- pcm_chnrelease(rdch);
- }
- /* exit */
- pcm_unlock(d);
- splx(s);
- return EBUSY;
- }
- /* got a channel, already locked for us */
- }
-
- i_dev->si_drv1 = rdch;
- i_dev->si_drv2 = wrch;
-
- /* Bump refcounts, reset and unlock any channels that we just opened,
- * and then release device lock.
- */
- if (flags & FREAD) {
if (chn_reset(rdch, fmt)) {
pcm_chnrelease(rdch);
i_dev->si_drv1 = NULL;
- if (wrch && (flags & FWRITE)) {
- pcm_chnrelease(wrch);
- i_dev->si_drv2 = NULL;
- }
pcm_unlock(d);
splx(s);
return ENODEV;
}
+
if (flags & O_NONBLOCK)
rdch->flags |= CHN_F_NBIO;
pcm_chnref(rdch, 1);
CHN_UNLOCK(rdch);
+ rdref = 1;
+ /*
+ * Record channel created, ref'ed and unlocked
+ */
}
+
if (flags & FWRITE) {
- if (chn_reset(wrch, fmt)) {
- pcm_chnrelease(wrch);
- i_dev->si_drv2 = NULL;
- if (flags & FREAD) {
- CHN_LOCK(rdch);
- pcm_chnref(rdch, -1);
- pcm_chnrelease(rdch);
- i_dev->si_drv1 = NULL;
- }
- pcm_unlock(d);
- splx(s);
- return ENODEV;
+ /* open for write */
+ wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
+ error = 0;
+
+ if (!wrch)
+ error = EBUSY; /* XXX Right return code? */
+ else if (chn_reset(wrch, fmt))
+ error = ENODEV;
+
+ if (error != 0) {
+ if (wrch) {
+ /*
+ * Free play channel
+ */
+ pcm_chnrelease(wrch);
+ i_dev->si_drv2 = NULL;
}
- if (flags & O_NONBLOCK)
- wrch->flags |= CHN_F_NBIO;
- pcm_chnref(wrch, 1);
- CHN_UNLOCK(wrch);
+ if (rdref) {
+ /*
+ * Lock, deref and release previously created record channel
+ */
+ CHN_LOCK(rdch);
+ pcm_chnref(rdch, -1);
+ pcm_chnrelease(rdch);
+ i_dev->si_drv1 = NULL;
+ }
+
+ pcm_unlock(d);
+ splx(s);
+ return error;
+ }
+
+ if (flags & O_NONBLOCK)
+ wrch->flags |= CHN_F_NBIO;
+ pcm_chnref(wrch, 1);
+ CHN_UNLOCK(wrch);
}
+
+ i_dev->si_drv1 = rdch;
+ i_dev->si_drv2 = wrch;
+
pcm_unlock(d);
splx(s);
return 0;
More information about the freebsd-current
mailing list