Re: Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-26 Thread Alexandre Ratchov
On Sun, Sep 24, 2023 at 11:03:54PM +0300, Vitaliy Makkoveev wrote:
> Please test this diff, I have no midi(4) devices.
> 
> midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
> still kernel locked. Wipe out old selwakeup API and make them MP safe.
> knote_locked(9) will not grab kernel lock, so call it directly from
> interrupt handlers instead of scheduling software interrupts.
> 

Works for me (tested with a usb device), pulling the usb cable
properly wakes up any process waiting for input/output.

ok ratchov@ with the two changes below

> @@ -531,20 +518,8 @@ midiattach(struct device *parent, struct
>   }
>  #endif
>  
> - sc->inbuf.softintr = softintr_establish(IPL_SOFTMIDI,
> - midi_buf_wakeup, >inbuf);
> - if (sc->inbuf.softintr == NULL) {
> - printf("%s: can't establish input softintr\n", DEVNAME(sc));
> - return;
> - }
> -
> - sc->outbuf.softintr = softintr_establish(IPL_SOFTMIDI,
> - midi_buf_wakeup, >outbuf);
> - if (sc->outbuf.softintr == NULL) {
> - printf("%s: can't establish output softintr\n", DEVNAME(sc));
> - softintr_disestablish(sc->inbuf.softintr);
> - return;
> - }
> + klist_init_mutex(>inbuf.klist, _lock);
> + klist_init_mutex(>outbuf.klist, _lock);
>  
>   sc->hw_if = hwif;
>   sc->hw_hdl = hdl;
> @@ -580,27 +555,19 @@ mididetach(struct device *self, int flag
>   KERNEL_ASSERT_LOCKED();
>   if (sc->flags & FREAD) {
>   wakeup(>inbuf.blocking);
> - mtx_enter(_lock);
> - selwakeup(>inbuf.sel);
> - mtx_leave(_lock);
> + knote(>inbuf.klist, 0);

AFAIU, the knote() calls are not necessary because klist_invalidate()
already does the job.

>   }
>   if (sc->flags & FWRITE) {
>   wakeup(>outbuf.blocking);
> - mtx_enter(_lock);
> - selwakeup(>outbuf.sel);
> - mtx_leave(_lock);
> + knote(>outbuf.klist, 0);
>   }
>   sc->hw_if->close(sc->hw_hdl);
>   sc->flags = 0;
>   }
>  
> - klist_invalidate(>inbuf.sel.si_note);
> - klist_invalidate(>outbuf.sel.si_note);
> + klist_invalidate(>inbuf.klist);
> + klist_invalidate(>outbuf.klist);
>

Could you add two klist_free() calls here? They are simple asserts,
but they'd make the attach/detach functions more midi(4) would look
more like audio(4).



Re: Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-26 Thread Vitaliy Makkoveev
On Tue, Sep 26, 2023 at 10:37:29AM +0200, Alexandre Ratchov wrote:
> On Sun, Sep 24, 2023 at 11:03:54PM +0300, Vitaliy Makkoveev wrote:
> > Please test this diff, I have no midi(4) devices.
> > 
> > midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
> > still kernel locked. Wipe out old selwakeup API and make them MP safe.
> > knote_locked(9) will not grab kernel lock, so call it directly from
> > interrupt handlers instead of scheduling software interrupts.
> > 
> 
> Works for me (tested with a usb device), pulling the usb cable
> properly wakes up any process waiting for input/output.
> 
> ok ratchov@ with the two changes below
> 

Thanks for klist_invalidate() explanation. Updated diff below, will
commit it today later.

Index: sys/dev/midi.c
===
RCS file: /cvs/src/sys/dev/midi.c,v
retrieving revision 1.55
diff -u -p -r1.55 midi.c
--- sys/dev/midi.c  2 Jul 2022 08:50:41 -   1.55
+++ sys/dev/midi.c  26 Sep 2023 10:37:44 -
@@ -31,7 +31,6 @@
 #include 
 #include 
 
-#define IPL_SOFTMIDI   IPL_SOFTNET
 #define DEVNAME(sc)((sc)->dev.dv_xname)
 
 intmidiopen(dev_t, int, int, struct proc *);
@@ -65,41 +64,38 @@ struct cfdriver midi_cd = {
 
 void filt_midiwdetach(struct knote *);
 int filt_midiwrite(struct knote *, long);
+int filt_midimodify(struct kevent *, struct knote *);
+int filt_midiprocess(struct knote *, struct kevent *);
 
 const struct filterops midiwrite_filtops = {
-   .f_flags= FILTEROP_ISFD,
+   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach   = NULL,
.f_detach   = filt_midiwdetach,
.f_event= filt_midiwrite,
+   .f_modify   = filt_midimodify,
+   .f_process  = filt_midiprocess,
 };
 
 void filt_midirdetach(struct knote *);
 int filt_midiread(struct knote *, long);
 
 const struct filterops midiread_filtops = {
-   .f_flags= FILTEROP_ISFD,
+   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach   = NULL,
.f_detach   = filt_midirdetach,
.f_event= filt_midiread,
+   .f_modify   = filt_midimodify,
+   .f_process  = filt_midiprocess,
 };
 
 void
-midi_buf_wakeup(void *addr)
+midi_buf_wakeup(struct midi_buffer *buf)
 {
-   struct midi_buffer *buf = addr;
-
if (buf->blocking) {
wakeup(>blocking);
buf->blocking = 0;
}
-   /*
-* As long as selwakeup() grabs the KERNEL_LOCK() make sure it is
-* already held here to avoid lock ordering problems with `audio_lock'
-*/
-   KERNEL_ASSERT_LOCKED();
-   mtx_enter(_lock);
-   selwakeup(>sel);
-   mtx_leave(_lock);
+   knote_locked(>klist, 0);
 }
 
 void
@@ -117,13 +113,7 @@ midi_iintr(void *addr, int data)
 
MIDIBUF_WRITE(mb, data);
 
-   /*
-* As long as selwakeup() needs to be protected by the
-* KERNEL_LOCK() we have to delay the wakeup to another
-* context to keep the interrupt context KERNEL_LOCK()
-* free.
-*/
-   softintr_schedule(sc->inbuf.softintr);
+   midi_buf_wakeup(mb);
 }
 
 int
@@ -226,14 +216,7 @@ void
 midi_out_stop(struct midi_softc *sc)
 {
sc->isbusy = 0;
-
-   /*
-* As long as selwakeup() needs to be protected by the
-* KERNEL_LOCK() we have to delay the wakeup to another
-* context to keep the interrupt context KERNEL_LOCK()
-* free.
-*/
-   softintr_schedule(sc->outbuf.softintr);
+   midi_buf_wakeup(>outbuf);
 }
 
 void
@@ -342,11 +325,11 @@ midikqfilter(dev_t dev, struct knote *kn
error = 0;
switch (kn->kn_filter) {
case EVFILT_READ:
-   klist = >inbuf.sel.si_note;
+   klist = >inbuf.klist;
kn->kn_fop = _filtops;
break;
case EVFILT_WRITE:
-   klist = >outbuf.sel.si_note;
+   klist = >outbuf.klist;
kn->kn_fop = _filtops;
break;
default:
@@ -355,9 +338,7 @@ midikqfilter(dev_t dev, struct knote *kn
}
kn->kn_hook = (void *)sc;
 
-   mtx_enter(_lock);
-   klist_insert_locked(klist, kn);
-   mtx_leave(_lock);
+   klist_insert(klist, kn);
 done:
device_unref(>dev);
return error;
@@ -368,24 +349,15 @@ filt_midirdetach(struct knote *kn)
 {
struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
 
-   mtx_enter(_lock);
-   klist_remove_locked(>inbuf.sel.si_note, kn);
-   mtx_leave(_lock);
+   klist_remove(>inbuf.klist, kn);
 }
 
 int
 filt_midiread(struct knote *kn, long hint)
 {
struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
-   int retval;
-
-   if ((hint & NOTE_SUBMIT) == 0)
-   mtx_enter(_lock);
-   retval = !MIDIBUF_ISEMPTY(>inbuf);
-   if ((hint & NOTE_SUBMIT) == 0)
-   

Re: Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-26 Thread Alexandre Ratchov
On Mon, Sep 25, 2023 at 04:58:56PM +0300, Vitaliy Makkoveev wrote:
> On Mon, Sep 25, 2023 at 05:39:34AM +, Visa Hankala wrote:
> > On Sun, Sep 24, 2023 at 11:03:54PM +0300, Vitaliy Makkoveev wrote:
> > > Please test this diff, I have no midi(4) devices.
> > > 
> > > midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
> > > still kernel locked. Wipe out old selwakeup API and make them MP safe.
> > > knote_locked(9) will not grab kernel lock, so call it directly from
> > > interrupt handlers instead of scheduling software interrupts.
> > 
> > https://marc.info/?l=openbsd-tech=167604232828221 has minor takeaways
> > if you pay attention.
> > 
> 
> The only significant difference is mididetach() where you did not replaced
> selwakeup() with knote(). Did I missed something?
> 
> @@ -577,30 +562,20 @@ mididetach(struct device *self, int flag
>* in read/write/ioctl, which return EIO.
>*/
>   if (sc->flags) {
> - KERNEL_ASSERT_LOCKED();
> - if (sc->flags & FREAD) {
> + if (sc->flags & FREAD)
>   wakeup(>inbuf.blocking);
> - mtx_enter(_lock);
> - selwakeup(>inbuf.sel);
> - mtx_leave(_lock);
> - }

IIRC, klist_invalidate() wakes up the process, so the selwakeup()
section should be removed. Does this sound correct?

This is how audio(4) detaches, BTW.



Re: Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-25 Thread Vitaliy Makkoveev
On Mon, Sep 25, 2023 at 05:39:34AM +, Visa Hankala wrote:
> On Sun, Sep 24, 2023 at 11:03:54PM +0300, Vitaliy Makkoveev wrote:
> > Please test this diff, I have no midi(4) devices.
> > 
> > midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
> > still kernel locked. Wipe out old selwakeup API and make them MP safe.
> > knote_locked(9) will not grab kernel lock, so call it directly from
> > interrupt handlers instead of scheduling software interrupts.
> 
> https://marc.info/?l=openbsd-tech=167604232828221 has minor takeaways
> if you pay attention.
> 

The only significant difference is mididetach() where you did not replaced
selwakeup() with knote(). Did I missed something?

@@ -577,30 +562,20 @@ mididetach(struct device *self, int flag
 * in read/write/ioctl, which return EIO.
 */
if (sc->flags) {
-   KERNEL_ASSERT_LOCKED();
-   if (sc->flags & FREAD) {
+   if (sc->flags & FREAD)
wakeup(>inbuf.blocking);
-   mtx_enter(_lock);
-   selwakeup(>inbuf.sel);
-   mtx_leave(_lock);
-   }

> > Index: sys/dev/midi.c
> > ===
> > RCS file: /cvs/src/sys/dev/midi.c,v
> > retrieving revision 1.55
> > diff -u -p -r1.55 midi.c
> > --- sys/dev/midi.c  2 Jul 2022 08:50:41 -   1.55
> > +++ sys/dev/midi.c  24 Sep 2023 19:57:56 -
> > @@ -31,7 +31,6 @@
> >  #include 
> >  #include 
> >  
> > -#define IPL_SOFTMIDI   IPL_SOFTNET
> >  #define DEVNAME(sc)((sc)->dev.dv_xname)
> >  
> >  intmidiopen(dev_t, int, int, struct proc *);
> > @@ -65,41 +64,38 @@ struct cfdriver midi_cd = {
> >  
> >  void filt_midiwdetach(struct knote *);
> >  int filt_midiwrite(struct knote *, long);
> > +int filt_midimodify(struct kevent *, struct knote *);
> > +int filt_midiprocess(struct knote *, struct kevent *);
> >  
> >  const struct filterops midiwrite_filtops = {
> > -   .f_flags= FILTEROP_ISFD,
> > +   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
> > .f_attach   = NULL,
> > .f_detach   = filt_midiwdetach,
> > .f_event= filt_midiwrite,
> > +   .f_modify   = filt_midimodify,
> > +   .f_process  = filt_midiprocess,
> >  };
> >  
> >  void filt_midirdetach(struct knote *);
> >  int filt_midiread(struct knote *, long);
> >  
> >  const struct filterops midiread_filtops = {
> > -   .f_flags= FILTEROP_ISFD,
> > +   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
> > .f_attach   = NULL,
> > .f_detach   = filt_midirdetach,
> > .f_event= filt_midiread,
> > +   .f_modify   = filt_midimodify,
> > +   .f_process  = filt_midiprocess,
> >  };
> >  
> >  void
> > -midi_buf_wakeup(void *addr)
> > +midi_buf_wakeup(struct midi_buffer *buf)
> >  {
> > -   struct midi_buffer *buf = addr;
> > -
> > if (buf->blocking) {
> > wakeup(>blocking);
> > buf->blocking = 0;
> > }
> > -   /*
> > -* As long as selwakeup() grabs the KERNEL_LOCK() make sure it is
> > -* already held here to avoid lock ordering problems with `audio_lock'
> > -*/
> > -   KERNEL_ASSERT_LOCKED();
> > -   mtx_enter(_lock);
> > -   selwakeup(>sel);
> > -   mtx_leave(_lock);
> > +   knote_locked(>klist, 0);
> >  }
> >  
> >  void
> > @@ -117,13 +113,7 @@ midi_iintr(void *addr, int data)
> >  
> > MIDIBUF_WRITE(mb, data);
> >  
> > -   /*
> > -* As long as selwakeup() needs to be protected by the
> > -* KERNEL_LOCK() we have to delay the wakeup to another
> > -* context to keep the interrupt context KERNEL_LOCK()
> > -* free.
> > -*/
> > -   softintr_schedule(sc->inbuf.softintr);
> > +   midi_buf_wakeup(mb);
> >  }
> >  
> >  int
> > @@ -226,14 +216,7 @@ void
> >  midi_out_stop(struct midi_softc *sc)
> >  {
> > sc->isbusy = 0;
> > -
> > -   /*
> > -* As long as selwakeup() needs to be protected by the
> > -* KERNEL_LOCK() we have to delay the wakeup to another
> > -* context to keep the interrupt context KERNEL_LOCK()
> > -* free.
> > -*/
> > -   softintr_schedule(sc->outbuf.softintr);
> > +   midi_buf_wakeup(>outbuf);
> >  }
> >  
> >  void
> > @@ -342,11 +325,11 @@ midikqfilter(dev_t dev, struct knote *kn
> > error = 0;
> > switch (kn->kn_filter) {
> > case EVFILT_READ:
> > -   klist = >inbuf.sel.si_note;
> > +   klist = >inbuf.klist;
> > kn->kn_fop = _filtops;
> > break;
> > case EVFILT_WRITE:
> > -   klist = >outbuf.sel.si_note;
> > +   klist = >outbuf.klist;
> > kn->kn_fop = _filtops;
> > break;
> > default:
> > @@ -355,9 +338,7 @@ midikqfilter(dev_t dev, struct knote *kn
> > }
> > kn->kn_hook = (void *)sc;
> >  
> > -   mtx_enter(_lock);
> > -   klist_insert_locked(klist, kn);
> > -   mtx_leave(_lock);
> > +   

Re: Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-24 Thread Visa Hankala
On Sun, Sep 24, 2023 at 11:03:54PM +0300, Vitaliy Makkoveev wrote:
> Please test this diff, I have no midi(4) devices.
> 
> midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
> still kernel locked. Wipe out old selwakeup API and make them MP safe.
> knote_locked(9) will not grab kernel lock, so call it directly from
> interrupt handlers instead of scheduling software interrupts.

https://marc.info/?l=openbsd-tech=167604232828221 has minor takeaways
if you pay attention.

> Index: sys/dev/midi.c
> ===
> RCS file: /cvs/src/sys/dev/midi.c,v
> retrieving revision 1.55
> diff -u -p -r1.55 midi.c
> --- sys/dev/midi.c2 Jul 2022 08:50:41 -   1.55
> +++ sys/dev/midi.c24 Sep 2023 19:57:56 -
> @@ -31,7 +31,6 @@
>  #include 
>  #include 
>  
> -#define IPL_SOFTMIDI IPL_SOFTNET
>  #define DEVNAME(sc)  ((sc)->dev.dv_xname)
>  
>  int  midiopen(dev_t, int, int, struct proc *);
> @@ -65,41 +64,38 @@ struct cfdriver midi_cd = {
>  
>  void filt_midiwdetach(struct knote *);
>  int filt_midiwrite(struct knote *, long);
> +int filt_midimodify(struct kevent *, struct knote *);
> +int filt_midiprocess(struct knote *, struct kevent *);
>  
>  const struct filterops midiwrite_filtops = {
> - .f_flags= FILTEROP_ISFD,
> + .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
>   .f_attach   = NULL,
>   .f_detach   = filt_midiwdetach,
>   .f_event= filt_midiwrite,
> + .f_modify   = filt_midimodify,
> + .f_process  = filt_midiprocess,
>  };
>  
>  void filt_midirdetach(struct knote *);
>  int filt_midiread(struct knote *, long);
>  
>  const struct filterops midiread_filtops = {
> - .f_flags= FILTEROP_ISFD,
> + .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
>   .f_attach   = NULL,
>   .f_detach   = filt_midirdetach,
>   .f_event= filt_midiread,
> + .f_modify   = filt_midimodify,
> + .f_process  = filt_midiprocess,
>  };
>  
>  void
> -midi_buf_wakeup(void *addr)
> +midi_buf_wakeup(struct midi_buffer *buf)
>  {
> - struct midi_buffer *buf = addr;
> -
>   if (buf->blocking) {
>   wakeup(>blocking);
>   buf->blocking = 0;
>   }
> - /*
> -  * As long as selwakeup() grabs the KERNEL_LOCK() make sure it is
> -  * already held here to avoid lock ordering problems with `audio_lock'
> -  */
> - KERNEL_ASSERT_LOCKED();
> - mtx_enter(_lock);
> - selwakeup(>sel);
> - mtx_leave(_lock);
> + knote_locked(>klist, 0);
>  }
>  
>  void
> @@ -117,13 +113,7 @@ midi_iintr(void *addr, int data)
>  
>   MIDIBUF_WRITE(mb, data);
>  
> - /*
> -  * As long as selwakeup() needs to be protected by the
> -  * KERNEL_LOCK() we have to delay the wakeup to another
> -  * context to keep the interrupt context KERNEL_LOCK()
> -  * free.
> -  */
> - softintr_schedule(sc->inbuf.softintr);
> + midi_buf_wakeup(mb);
>  }
>  
>  int
> @@ -226,14 +216,7 @@ void
>  midi_out_stop(struct midi_softc *sc)
>  {
>   sc->isbusy = 0;
> -
> - /*
> -  * As long as selwakeup() needs to be protected by the
> -  * KERNEL_LOCK() we have to delay the wakeup to another
> -  * context to keep the interrupt context KERNEL_LOCK()
> -  * free.
> -  */
> - softintr_schedule(sc->outbuf.softintr);
> + midi_buf_wakeup(>outbuf);
>  }
>  
>  void
> @@ -342,11 +325,11 @@ midikqfilter(dev_t dev, struct knote *kn
>   error = 0;
>   switch (kn->kn_filter) {
>   case EVFILT_READ:
> - klist = >inbuf.sel.si_note;
> + klist = >inbuf.klist;
>   kn->kn_fop = _filtops;
>   break;
>   case EVFILT_WRITE:
> - klist = >outbuf.sel.si_note;
> + klist = >outbuf.klist;
>   kn->kn_fop = _filtops;
>   break;
>   default:
> @@ -355,9 +338,7 @@ midikqfilter(dev_t dev, struct knote *kn
>   }
>   kn->kn_hook = (void *)sc;
>  
> - mtx_enter(_lock);
> - klist_insert_locked(klist, kn);
> - mtx_leave(_lock);
> + klist_insert(klist, kn);
>  done:
>   device_unref(>dev);
>   return error;
> @@ -368,24 +349,15 @@ filt_midirdetach(struct knote *kn)
>  {
>   struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
>  
> - mtx_enter(_lock);
> - klist_remove_locked(>inbuf.sel.si_note, kn);
> - mtx_leave(_lock);
> + klist_remove(>inbuf.klist, kn);
>  }
>  
>  int
>  filt_midiread(struct knote *kn, long hint)
>  {
>   struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
> - int retval;
> -
> - if ((hint & NOTE_SUBMIT) == 0)
> - mtx_enter(_lock);
> - retval = !MIDIBUF_ISEMPTY(>inbuf);
> - if ((hint & NOTE_SUBMIT) == 0)
> - mtx_leave(_lock);
>  
> - return (retval);
> + return (!MIDIBUF_ISEMPTY(>inbuf));
>  }
>  
>  void
> @@ -393,24 

Please test; midi(4): make midi{read,write}_filtops mp safe

2023-09-24 Thread Vitaliy Makkoveev
Please test this diff, I have no midi(4) devices.

midi(4) already uses `audio_lock' mutex(9) for filterops, but they are
still kernel locked. Wipe out old selwakeup API and make them MP safe.
knote_locked(9) will not grab kernel lock, so call it directly from
interrupt handlers instead of scheduling software interrupts.

Index: sys/dev/midi.c
===
RCS file: /cvs/src/sys/dev/midi.c,v
retrieving revision 1.55
diff -u -p -r1.55 midi.c
--- sys/dev/midi.c  2 Jul 2022 08:50:41 -   1.55
+++ sys/dev/midi.c  24 Sep 2023 19:57:56 -
@@ -31,7 +31,6 @@
 #include 
 #include 
 
-#define IPL_SOFTMIDI   IPL_SOFTNET
 #define DEVNAME(sc)((sc)->dev.dv_xname)
 
 intmidiopen(dev_t, int, int, struct proc *);
@@ -65,41 +64,38 @@ struct cfdriver midi_cd = {
 
 void filt_midiwdetach(struct knote *);
 int filt_midiwrite(struct knote *, long);
+int filt_midimodify(struct kevent *, struct knote *);
+int filt_midiprocess(struct knote *, struct kevent *);
 
 const struct filterops midiwrite_filtops = {
-   .f_flags= FILTEROP_ISFD,
+   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach   = NULL,
.f_detach   = filt_midiwdetach,
.f_event= filt_midiwrite,
+   .f_modify   = filt_midimodify,
+   .f_process  = filt_midiprocess,
 };
 
 void filt_midirdetach(struct knote *);
 int filt_midiread(struct knote *, long);
 
 const struct filterops midiread_filtops = {
-   .f_flags= FILTEROP_ISFD,
+   .f_flags= FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach   = NULL,
.f_detach   = filt_midirdetach,
.f_event= filt_midiread,
+   .f_modify   = filt_midimodify,
+   .f_process  = filt_midiprocess,
 };
 
 void
-midi_buf_wakeup(void *addr)
+midi_buf_wakeup(struct midi_buffer *buf)
 {
-   struct midi_buffer *buf = addr;
-
if (buf->blocking) {
wakeup(>blocking);
buf->blocking = 0;
}
-   /*
-* As long as selwakeup() grabs the KERNEL_LOCK() make sure it is
-* already held here to avoid lock ordering problems with `audio_lock'
-*/
-   KERNEL_ASSERT_LOCKED();
-   mtx_enter(_lock);
-   selwakeup(>sel);
-   mtx_leave(_lock);
+   knote_locked(>klist, 0);
 }
 
 void
@@ -117,13 +113,7 @@ midi_iintr(void *addr, int data)
 
MIDIBUF_WRITE(mb, data);
 
-   /*
-* As long as selwakeup() needs to be protected by the
-* KERNEL_LOCK() we have to delay the wakeup to another
-* context to keep the interrupt context KERNEL_LOCK()
-* free.
-*/
-   softintr_schedule(sc->inbuf.softintr);
+   midi_buf_wakeup(mb);
 }
 
 int
@@ -226,14 +216,7 @@ void
 midi_out_stop(struct midi_softc *sc)
 {
sc->isbusy = 0;
-
-   /*
-* As long as selwakeup() needs to be protected by the
-* KERNEL_LOCK() we have to delay the wakeup to another
-* context to keep the interrupt context KERNEL_LOCK()
-* free.
-*/
-   softintr_schedule(sc->outbuf.softintr);
+   midi_buf_wakeup(>outbuf);
 }
 
 void
@@ -342,11 +325,11 @@ midikqfilter(dev_t dev, struct knote *kn
error = 0;
switch (kn->kn_filter) {
case EVFILT_READ:
-   klist = >inbuf.sel.si_note;
+   klist = >inbuf.klist;
kn->kn_fop = _filtops;
break;
case EVFILT_WRITE:
-   klist = >outbuf.sel.si_note;
+   klist = >outbuf.klist;
kn->kn_fop = _filtops;
break;
default:
@@ -355,9 +338,7 @@ midikqfilter(dev_t dev, struct knote *kn
}
kn->kn_hook = (void *)sc;
 
-   mtx_enter(_lock);
-   klist_insert_locked(klist, kn);
-   mtx_leave(_lock);
+   klist_insert(klist, kn);
 done:
device_unref(>dev);
return error;
@@ -368,24 +349,15 @@ filt_midirdetach(struct knote *kn)
 {
struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
 
-   mtx_enter(_lock);
-   klist_remove_locked(>inbuf.sel.si_note, kn);
-   mtx_leave(_lock);
+   klist_remove(>inbuf.klist, kn);
 }
 
 int
 filt_midiread(struct knote *kn, long hint)
 {
struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
-   int retval;
-
-   if ((hint & NOTE_SUBMIT) == 0)
-   mtx_enter(_lock);
-   retval = !MIDIBUF_ISEMPTY(>inbuf);
-   if ((hint & NOTE_SUBMIT) == 0)
-   mtx_leave(_lock);
 
-   return (retval);
+   return (!MIDIBUF_ISEMPTY(>inbuf));
 }
 
 void
@@ -393,24 +365,39 @@ filt_midiwdetach(struct knote *kn)
 {
struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
 
-   mtx_enter(_lock);
-   klist_remove_locked(>outbuf.sel.si_note, kn);
-   mtx_leave(_lock);
+   klist_remove(>outbuf.klist, kn);
 }
 
 int
 filt_midiwrite(struct knote *kn,