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:
parent
1652b7bde4
commit
42e67fd3e7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=102064
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user