mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-30 04:22:44 +00:00
snd_dummy: Fix callout(9) races
Use callout_init_mtx(9) to associate the callback with the driver's lock. Also make sure the callout is stopped properly during detach. While here, introduce a dummy_active() function to know when it's appropriate to stop or not reschedule the callout. Sponsored by: The FreeBSD Foundation MFC after: 2 days Reviewed by: dev_submerge.ch, markj Differential Revision: https://reviews.freebsd.org/D47459
This commit is contained in:
parent
56b7685ae3
commit
5bd08172b4
@ -67,6 +67,24 @@ struct dummy_softc {
|
|||||||
struct mtx *lock;
|
struct mtx *lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
dummy_active(struct dummy_softc *sc)
|
||||||
|
{
|
||||||
|
struct dummy_chan *ch;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
snd_mtxassert(sc->lock);
|
||||||
|
|
||||||
|
for (i = 0; i < sc->chnum; i++) {
|
||||||
|
ch = &sc->chans[i];
|
||||||
|
if (ch->run)
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No channel is running at the moment. */
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dummy_chan_io(void *arg)
|
dummy_chan_io(void *arg)
|
||||||
{
|
{
|
||||||
@ -74,7 +92,9 @@ dummy_chan_io(void *arg)
|
|||||||
struct dummy_chan *ch;
|
struct dummy_chan *ch;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
snd_mtxlock(sc->lock);
|
/* Do not reschedule if no channel is running. */
|
||||||
|
if (!dummy_active(sc))
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < sc->chnum; i++) {
|
for (i = 0; i < sc->chnum; i++) {
|
||||||
ch = &sc->chans[i];
|
ch = &sc->chans[i];
|
||||||
@ -89,8 +109,6 @@ dummy_chan_io(void *arg)
|
|||||||
snd_mtxlock(sc->lock);
|
snd_mtxlock(sc->lock);
|
||||||
}
|
}
|
||||||
callout_schedule(&sc->callout, 1);
|
callout_schedule(&sc->callout, 1);
|
||||||
|
|
||||||
snd_mtxunlock(sc->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -179,15 +197,15 @@ dummy_chan_trigger(kobj_t obj, void *data, int go)
|
|||||||
|
|
||||||
switch (go) {
|
switch (go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
if (!callout_active(&sc->callout))
|
|
||||||
callout_reset(&sc->callout, 1, dummy_chan_io, sc);
|
|
||||||
ch->ptr = 0;
|
ch->ptr = 0;
|
||||||
ch->run = 1;
|
ch->run = 1;
|
||||||
|
callout_reset(&sc->callout, 1, dummy_chan_io, sc);
|
||||||
break;
|
break;
|
||||||
case PCMTRIG_STOP:
|
case PCMTRIG_STOP:
|
||||||
case PCMTRIG_ABORT:
|
case PCMTRIG_ABORT:
|
||||||
ch->run = 0;
|
ch->run = 0;
|
||||||
if (callout_active(&sc->callout))
|
/* If all channels are stopped, stop the callout as well. */
|
||||||
|
if (!dummy_active(sc))
|
||||||
callout_stop(&sc->callout);
|
callout_stop(&sc->callout);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -292,6 +310,7 @@ dummy_attach(device_t dev)
|
|||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc");
|
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc");
|
||||||
|
callout_init_mtx(&sc->callout, sc->lock, 0);
|
||||||
|
|
||||||
sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0);
|
sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0);
|
||||||
sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0);
|
sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0);
|
||||||
@ -316,7 +335,6 @@ dummy_attach(device_t dev)
|
|||||||
if (pcm_register(dev, status))
|
if (pcm_register(dev, status))
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
mixer_init(dev, &dummy_mixer_class, sc);
|
mixer_init(dev, &dummy_mixer_class, sc);
|
||||||
callout_init(&sc->callout, 1);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -327,8 +345,8 @@ dummy_detach(device_t dev)
|
|||||||
struct dummy_softc *sc = device_get_softc(dev);
|
struct dummy_softc *sc = device_get_softc(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
callout_drain(&sc->callout);
|
|
||||||
err = pcm_unregister(dev);
|
err = pcm_unregister(dev);
|
||||||
|
callout_drain(&sc->callout);
|
||||||
snd_mtxfree(sc->lock);
|
snd_mtxfree(sc->lock);
|
||||||
|
|
||||||
return (err);
|
return (err);
|
||||||
|
Loading…
Reference in New Issue
Block a user