Apply reference counting patch. Fixes problem of two applications

opening the device, eg one read only and one write only, and the
reference count being non-zero when both exit rendering device
permanently busy.

PR:		kern/35004
Submitted by:	Bill Wells
MFC after:	3 days
This commit is contained in:
Orion Hodson 2002-08-18 14:17:06 +00:00
parent 1652b7bde4
commit 42e67fd3e7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=102064

View File

@ -283,40 +283,34 @@ dsp_open(dev_t i_dev, int flags, int mode, struct thread *td)
/* finished with snddev, new channels still locked */
/* bump refcounts, reset and unlock any channels that we just opened */
if (rdch) {
if (flags & FREAD) {
if (chn_reset(rdch, fmt)) {
pcm_lock(d);
pcm_chnrelease(rdch);
if (wrch && (flags & FWRITE))
pcm_chnrelease(wrch);
pcm_unlock(d);
splx(s);
return ENODEV;
}
if (flags & O_NONBLOCK)
rdch->flags |= CHN_F_NBIO;
} else
CHN_LOCK(rdch);
if (flags & FREAD) {
if (chn_reset(rdch, fmt)) {
pcm_lock(d);
pcm_chnrelease(rdch);
if (wrch && (flags & FWRITE))
pcm_chnrelease(wrch);
pcm_unlock(d);
splx(s);
return ENODEV;
}
if (flags & O_NONBLOCK)
rdch->flags |= CHN_F_NBIO;
pcm_chnref(rdch, 1);
CHN_UNLOCK(rdch);
}
if (wrch) {
if (flags & FWRITE) {
if (chn_reset(wrch, fmt)) {
pcm_lock(d);
pcm_chnrelease(wrch);
if (rdch && (flags & FREAD))
pcm_chnrelease(rdch);
pcm_unlock(d);
splx(s);
return ENODEV;
}
if (flags & O_NONBLOCK)
wrch->flags |= CHN_F_NBIO;
} else
CHN_LOCK(wrch);
if (flags & FWRITE) {
if (chn_reset(wrch, fmt)) {
pcm_lock(d);
pcm_chnrelease(wrch);
if (rdch && (flags & FREAD))
pcm_chnrelease(rdch);
pcm_unlock(d);
splx(s);
return ENODEV;
}
if (flags & O_NONBLOCK)
wrch->flags |= CHN_F_NBIO;
pcm_chnref(wrch, 1);
CHN_UNLOCK(wrch);
@ -345,18 +339,23 @@ dsp_close(dev_t i_dev, int flags, int mode, struct thread *td)
if (rdch) {
CHN_LOCK(rdch);
if (pcm_chnref(rdch, -1) > 0) {
CHN_UNLOCK(rdch);
exit = 1;
}
CHN_UNLOCK(rdch);
}
if (wrch) {
CHN_LOCK(wrch);
if (pcm_chnref(wrch, -1) > 0) {
CHN_UNLOCK(wrch);
exit = 1;
}
CHN_UNLOCK(wrch);
}
/* XXX And what happens if one of the channels had 2 references and
the other has but one? The latter won't get reset. Can that
happen? */
if (exit) {
i_dev->si_drv1 = NULL;
i_dev->si_drv2 = NULL;
pcm_unlock(d);
splx(s);
return 0;
@ -367,9 +366,6 @@ dsp_close(dev_t i_dev, int flags, int mode, struct thread *td)
if (pcm_getfakechan(d))
pcm_getfakechan(d)->flags = 0;
i_dev->si_drv1 = NULL;
i_dev->si_drv2 = NULL;
dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
pcm_unlock(d);
@ -385,6 +381,8 @@ dsp_close(dev_t i_dev, int flags, int mode, struct thread *td)
chn_reset(wrch, 0);
pcm_chnrelease(wrch);
}
i_dev->si_drv1 = NULL;
i_dev->si_drv2 = NULL;
splx(s);
return 0;