aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/sound/pcm/sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pcm/sound.c')
-rw-r--r--sys/dev/sound/pcm/sound.c64
1 files changed, 43 insertions, 21 deletions
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 7de099cfe5ca..57cbf37005a7 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -678,23 +678,50 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
return (err);
}
-static int
-pcm_killchan(device_t dev)
+static void
+pcm_killchans(struct snddev_info *d)
{
- struct snddev_info *d = device_get_softc(dev);
struct pcm_channel *ch;
int error;
+ bool found;
PCM_BUSYASSERT(d);
+ do {
+ found = false;
+ CHN_FOREACH(ch, d, channels.pcm) {
+ CHN_LOCK(ch);
+ /*
+ * Make sure no channel has went to sleep in the
+ * meantime.
+ */
+ chn_shutdown(ch);
+ /*
+ * We have to give a thread sleeping in chn_sleep() a
+ * chance to observe that the channel is dead.
+ */
+ if ((ch->flags & CHN_F_SLEEPING) == 0) {
+ found = true;
+ CHN_UNLOCK(ch);
+ break;
+ }
+ CHN_UNLOCK(ch);
+ }
- ch = CHN_FIRST(d, channels.pcm);
+ /*
+ * All channels are still sleeping. Sleep for a bit and try
+ * again to see if any of them is awake now.
+ */
+ if (!found) {
+ pause_sbt("pcmkillchans", SBT_1MS * 5, 0, 0);
+ continue;
+ }
- PCM_LOCK(d);
- error = pcm_chn_remove(d, ch);
- PCM_UNLOCK(d);
- if (error)
- return (error);
- return (pcm_chn_destroy(ch));
+ PCM_LOCK(d);
+ error = pcm_chn_remove(d, ch);
+ PCM_UNLOCK(d);
+ if (error == 0)
+ pcm_chn_destroy(ch);
+ } while (!CHN_EMPTY(d, channels.pcm));
}
static int
@@ -1005,15 +1032,11 @@ pcm_unregister(device_t dev)
CHN_FOREACH(ch, d, channels.pcm) {
CHN_LOCK(ch);
- if (ch->flags & CHN_F_SLEEPING) {
- /*
- * We are detaching, so do not wait for the timeout in
- * chn_read()/chn_write(). Wake up the thread and kill
- * the channel immediately.
- */
- CHN_BROADCAST(&ch->intr_cv);
- ch->flags |= CHN_F_DEAD;
- }
+ /*
+ * Do not wait for the timeout in chn_read()/chn_write(). Wake
+ * up the sleeping thread and kill the channel.
+ */
+ chn_shutdown(ch);
chn_abort(ch);
CHN_UNLOCK(ch);
}
@@ -1038,8 +1061,7 @@ pcm_unregister(device_t dev)
dsp_destroy_dev(dev);
(void)mixer_uninit(dev);
- while (!CHN_EMPTY(d, channels.pcm))
- pcm_killchan(dev);
+ pcm_killchans(d);
PCM_LOCK(d);
PCM_RELEASE(d);