Page MenuHomeFreeBSD

D44923.diff
No OneTemporary

D44923.diff

diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -264,6 +264,7 @@
int chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction);
int chn_kill(struct pcm_channel *c);
+void chn_shutdown(struct pcm_channel *c);
int chn_reset(struct pcm_channel *c, u_int32_t fmt, u_int32_t spd);
int chn_setvolume_multi(struct pcm_channel *c, int vc, int left, int right,
int center);
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1301,6 +1301,15 @@
return (0);
}
+void
+chn_shutdown(struct pcm_channel *c)
+{
+ CHN_LOCKASSERT(c);
+
+ chn_wakeup(c);
+ c->flags |= CHN_F_DEAD;
+}
+
int
chn_setvolume_multi(struct pcm_channel *c, int vc, int left, int right,
int center)
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -674,23 +674,50 @@
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
@@ -1000,15 +1027,11 @@
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);
}
@@ -1033,8 +1056,7 @@
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);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 20, 4:20 AM (21 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14730121
Default Alt Text
D44923.diff (2 KB)

Event Timeline