Call selwakeup() from an MP-protected taskqueue.
authorSimon Schubert <corecode@dragonflybsd.org>
Sat, 5 Jan 2008 13:34:22 +0000 (13:34 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Sat, 5 Jan 2008 13:34:22 +0000 (13:34 +0000)
Before, we would call selwakeup() from interrupt context.  This
was working as long kern.intr_mpsafe == 0.  selwakeup() however needs
the MP lock held, so we can't call it directly from the interrupt
when running with kern.intr_mpsafe=1.

Instead, perform the wakeup from a "bottom half" taskqueue SWI to make the
sound devices intr_mpsafe, as they claim to be.

sys/dev/sound/pcm/buffer.c
sys/dev/sound/pcm/buffer.h
sys/dev/sound/pcm/channel.c
sys/dev/sound/pcm/sound.h

index 71ca492..0bf4522 100644 (file)
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/sound/pcm/buffer.c,v 1.25.2.3 2007/04/26 08:21:43 ariff Exp $
- * $DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.9 2007/06/16 19:48:05 hasso Exp $
+ * $DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.10 2008/01/05 13:34:22 corecode Exp $
  */
 
 #include <dev/sound/pcm/sound.h>
 
 #include "feeder_if.h"
 
-SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.9 2007/06/16 19:48:05 hasso Exp $");
+SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.10 2008/01/05 13:34:22 corecode Exp $");
+
+/*
+ * sndbuf_seltask is a taskqueue callback routine, called from
+ * taskqueue_swi, which runs under the MP lock.
+ *
+ * The only purpose is to be able to selwakeup() from a sound
+ * interrupt, which is running without MP lock held and thus
+ * can't call selwakeup() directly.
+ */
+static void
+sndbuf_seltask(void *context, int pending)
+{
+       struct snd_dbuf *b = context;
+
+       selwakeup(sndbuf_getsel(b));
+}
 
 struct snd_dbuf *
 sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
@@ -42,6 +58,7 @@ sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
        ksnprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
        b->dev = dev;
        b->channel = channel;
+       TASK_INIT(&b->seltask, 0, sndbuf_seltask, b);
 
        return b;
 }
index 89458fa..dd0e624 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/sound/pcm/buffer.h,v 1.10.2.2 2007/05/13 20:50:31 ariff Exp $
- * $DragonFly: src/sys/dev/sound/pcm/buffer.h,v 1.4 2007/06/16 19:48:05 hasso Exp $
+ * $DragonFly: src/sys/dev/sound/pcm/buffer.h,v 1.5 2008/01/05 13:34:22 corecode Exp $
  */
 
 #define SND_DMA(b) (sndbuf_getflags((b)) & SNDBUF_F_DMA)
@@ -55,6 +55,7 @@ struct snd_dbuf {
        bus_dma_tag_t dmatag;
        bus_addr_t buf_addr;
        struct selinfo sel;
+       struct task seltask;
        struct pcm_channel *channel;
        char name[SNDBUF_NAMELEN];
 };
index 415af37..68460d7 100644 (file)
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/sound/pcm/channel.c,v 1.99.2.5 2007/05/13 20:53:39 ariff Exp $
- * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.14 2007/06/16 20:07:22 dillon Exp $
+ * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.15 2008/01/05 13:34:22 corecode Exp $
  */
 
 #include "use_isa.h"
@@ -35,7 +35,7 @@
 
 #include "feeder_if.h"
 
-SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.14 2007/06/16 20:07:22 dillon Exp $");
+SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.15 2008/01/05 13:34:22 corecode Exp $");
 
 #define MIN_CHUNK_SIZE                 256     /* for uiomove etc. */
 #if 0
@@ -141,8 +141,20 @@ chn_wakeup(struct pcm_channel *c)
        CHN_LOCKASSERT(c);
        if (SLIST_EMPTY(&c->children)) {
                /*if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))*/
-               if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c))
-                       selwakeup(sndbuf_getsel(bs));
+               if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c)) {
+                       /*
+                        * We would call selwakeup() here, but as we
+                        * are in interrupt context, we'd have to
+                        * aquire the MP lock before.
+                        * Instead, we'll queue a task in a software
+                        * interrupt, which will run with the MP lock
+                        * held.
+                        *
+                        * buffer.c:sndbuf_seltask will then call
+                        * selwakeup() from safer context.
+                        */
+                       taskqueue_enqueue(taskqueue_swi, &bs->seltask);
+               }
        } else {
                SLIST_FOREACH(pce, &c->children, link) {
                        CHN_LOCK(pce->channel);
index 20be441..a58e96e 100644 (file)
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/sound/pcm/sound.h,v 1.63.2.3 2007/05/13 20:53:39 ariff Exp $
- * $DragonFly: src/sys/dev/sound/pcm/sound.h,v 1.13 2007/06/16 20:07:22 dillon Exp $
+ * $DragonFly: src/sys/dev/sound/pcm/sound.h,v 1.14 2008/01/05 13:34:22 corecode Exp $
  */
 
 /*
@@ -65,6 +65,7 @@
 #include <sys/sysctl.h>
 #include <sys/kobj.h>
 #include <sys/thread2.h>
+#include <sys/taskqueue.h>
 
 #include <machine/clock.h>     /* for DELAY */