Page MenuHomeFreeBSD

D44923.id137592.diff
No OneTemporary

D44923.id137592.diff

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,43 @@
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) {
+ /*
+ * We found an awake channel, proceed with destroying
+ * it. If we force-destroy all channels without
+ * checking if they are sleeping or not, we might panic
+ * in cv_timedwait_sig() after calling
+ * chn_lockdestroy() on a sleeping channel, because it
+ * will still be using a freed lock/cv.
+ */
+ if ((ch->flags & CHN_F_SLEEPING) == 0) {
+ found = true;
+ break;
+ }
+ }
+ /*
+ * All channels are still sleeping. Try again to see if any of
+ * them is awake now.
+ */
+ if (!found)
+ continue;
- ch = CHN_FIRST(d, channels.pcm);
-
- 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
@@ -1034,8 +1054,7 @@
d->rec_sysctl_tree = NULL;
}
- 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
Tue, Feb 3, 12:36 PM (13 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28424096
Default Alt Text
D44923.id137592.diff (1 KB)

Event Timeline