Merge branch 'master' into kq_devices
authorSamuel J. Greear <sjg@thesjg.com>
Wed, 7 Jul 2010 15:57:10 +0000 (15:57 +0000)
committerSamuel J. Greear <sjg@thesjg.com>
Wed, 7 Jul 2010 15:57:10 +0000 (15:57 +0000)
62 files changed:
lib/libc/sys/kqueue.2
sys/bus/firewire/fwdev.c
sys/bus/usb/usb.c
sys/dev/drm/drmP.h
sys/dev/drm/drm_drv.c
sys/dev/drm/drm_fops.c
sys/dev/misc/cmx/cmx.c
sys/dev/misc/dcons/dcons_os.c
sys/dev/misc/hotplug/hotplug.c
sys/dev/misc/kbd/kbd.c
sys/dev/misc/mse/mse.c
sys/dev/misc/nmdm/nmdm.c
sys/dev/misc/psm/psm.c
sys/dev/misc/snp/snp.c
sys/dev/misc/spic/spic.c
sys/dev/misc/syscons/sysmouse.c
sys/dev/misc/tw/tw.c
sys/dev/raid/aac/aac.c
sys/dev/raid/vinum/vinum.c
sys/dev/raid/vinum/vinumext.h
sys/dev/serial/rp/rp.c
sys/dev/sound/pcm/dsp.c
sys/dev/usbmisc/ugen/ugen.c
sys/dev/usbmisc/uhid/uhid.c
sys/dev/usbmisc/ums/ums.c
sys/dev/usbmisc/uscanner/uscanner.c
sys/dev/video/bktr/bktr_os.c
sys/dev/video/cxm/cxm.c
sys/emulation/linux/linux_epoll.c
sys/kern/kern_event.c
sys/kern/kern_memio.c
sys/kern/kern_nrandom.c
sys/kern/kern_udev.c
sys/kern/subr_bus.c
sys/kern/subr_log.c
sys/kern/sys_generic.c
sys/kern/sys_pipe.c
sys/kern/tty_pty.c
sys/kern/tty_tty.c
sys/kern/uipc_socket.c
sys/net/bpf.c
sys/net/i4b/driver/i4b_rbch.c
sys/net/i4b/driver/i4b_tel.c
sys/net/i4b/layer4/i4b_i4bdrv.c
sys/net/tun/if_tun.c
sys/platform/pc32/acpica5/acpi_machdep.c
sys/platform/pc32/apm/apm.c
sys/platform/pc32/isa/asc.c
sys/platform/pc64/acpica5/acpi_machdep.c
sys/platform/pc64/apm/apm.c
sys/platform/pc64/isa/asc.c
sys/platform/vkernel/platform/console.c
sys/platform/vkernel64/platform/console.c
sys/sys/event.h
sys/sys/proc.h
sys/sys/random.h
sys/vfs/devfs/devfs_vnops.c
tools/test/kqueue/Makefile [new file with mode: 0644]
tools/test/kqueue/kqueue_oob.c [new file with mode: 0644]
tools/test/select/Makefile [new file with mode: 0644]
tools/test/select/select_many_write.c [new file with mode: 0644]
tools/test/select/select_oob.c [new file with mode: 0644]

index 1ad5ce1..6327eb0 100644 (file)
@@ -278,6 +278,13 @@ For sockets, the low water mark and socket error handling is
 identical to the
 .Dv EVFILT_READ
 case.
+.It Dv EVFILT_EXCEPT
+Takes a descriptor as the identifier, and returns whenever one of the
+specified exceptional conditions has occurred on the descriptor. Conditions
+are specified in
+.Va fflags .
+Currently, a filter can monitor the reception of out-of-band data with
+.Dv NOTE_OOB .
 .It Dv EVFILT_AIO
 The sigevent portion of the AIO request is filled in, with
 .Va sigev_notify_kqueue
index f71dad7..0db8bc9 100644 (file)
@@ -50,6 +50,7 @@
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 
 #include <sys/bus.h>
 #include <sys/ctype.h>
@@ -77,20 +78,26 @@ static      d_open_t        fw_open;
 static d_close_t       fw_close;
 static d_ioctl_t       fw_ioctl;
 static d_poll_t        fw_poll;
+static d_kqfilter_t    fw_kqfilter;
 static d_read_t        fw_read;        /* for Isochronous packet */
 static d_write_t       fw_write;
 static d_mmap_t        fw_mmap;
 static d_strategy_t    fw_strategy;
 
+static void fwfilt_detach(struct knote *);
+static int fwfilt_read(struct knote *, long);
+static int fwfilt_write(struct knote *, long);
+
 struct dev_ops firewire_ops = 
 {
-       { "fw", CDEV_MAJOR, D_MEM },
+       { "fw", CDEV_MAJOR, D_MEM | D_KQFILTER },
        .d_open =       fw_open,
        .d_close =      fw_close,
        .d_read =       fw_read,
        .d_write =      fw_write,
        .d_ioctl =      fw_ioctl,
        .d_poll =       fw_poll,
+       .d_kqfilter =   fw_kqfilter,
        .d_mmap =       fw_mmap,
        .d_strategy =   fw_strategy,
 };
@@ -740,6 +747,87 @@ fw_poll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops fw_read_filterops =
+       { 1, NULL, fwfilt_detach, fwfilt_read };
+static struct filterops fw_write_filterops =
+       { 1, NULL, fwfilt_detach, fwfilt_write };
+
+static int
+fw_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct firewire_softc *sc;
+       struct fw_xferq *ir;
+       struct knote *kn = ap->a_kn;
+       int unit = DEV2UNIT(dev);
+       struct klist *klist;
+
+       /*
+        * XXX Implement filters for mem?
+        */
+       if (DEV_FWMEM(dev)) {
+               ap->a_result = 1;
+               return (0);
+       }
+
+       sc = devclass_get_softc(firewire_devclass, unit);
+       ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &fw_read_filterops;
+               kn->kn_hook = (caddr_t)ir;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &fw_write_filterops;
+               kn->kn_hook = (caddr_t)ir;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &ir->rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+fwfilt_detach(struct knote *kn)
+{
+       struct fw_xferq *ir = (struct fw_xferq *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &ir->rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+fwfilt_read(struct knote *kn, long hint)
+{
+       struct fw_xferq *ir = (struct fw_xferq *)kn->kn_hook;
+       int ready = 0;
+
+       if (STAILQ_FIRST(&ir->q) != NULL)
+               ready = 1;
+
+       return (ready);
+}
+
+static int
+fwfilt_write(struct knote *kn, long hint)
+{
+       /* XXX should be fixed */
+       return (1);
+}
+
 static int
 fw_mmap (struct dev_mmap_args *ap)
 {  
index 0a3414f..e504487 100644 (file)
@@ -70,6 +70,7 @@
 #include <sys/conf.h>
 #include <sys/device.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/select.h>
 #include <sys/vnode.h>
 #include <sys/signalvar.h>
@@ -148,14 +149,19 @@ d_close_t usbclose;
 d_read_t usbread;
 d_ioctl_t usbioctl;
 d_poll_t usbpoll;
+d_kqfilter_t usbkqfilter;
+
+static void usbfilt_detach(struct knote *);
+static int usbfilt(struct knote *, long);
 
 struct dev_ops usb_ops = {
-       { "usb", USB_CDEV_MAJOR, 0 },
+       { "usb", USB_CDEV_MAJOR, D_KQFILTER },
        .d_open =       usbopen,
        .d_close =      usbclose,
        .d_read =       usbread,
        .d_ioctl =      usbioctl,
        .d_poll =       usbpoll,
+       .d_kqfilter =   usbkqfilter
 };
 
 static void    usb_discover(device_t);
@@ -718,6 +724,64 @@ usbpoll(struct dev_poll_args *ap)
        }
 }
 
+static struct filterops usbfiltops =
+       { 1, NULL, usbfilt_detach, usbfilt };
+
+int
+usbkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &usbfiltops;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &usb_selevent.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+usbfilt_detach(struct knote *kn)
+{
+       struct klist *klist;
+
+       crit_enter();
+       klist = &usb_selevent.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+usbfilt(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = USBUNIT(dev);
+       int ready = 0;
+
+       if (unit == USB_DEV_MINOR) {
+               crit_enter();
+               if (usb_nevents > 0)
+                       ready = 1;
+               crit_exit();
+       }
+
+       return (ready);
+}
+
 /* Explore device tree from the root. */
 static void
 usb_discover(device_t self)
index 3f98d20..2ead778 100644 (file)
@@ -57,6 +57,7 @@ struct drm_file;
 #include <sys/bus.h>
 #include <sys/signalvar.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/tree.h>
 #include <sys/taskqueue.h>
 #include <vm/vm.h>
@@ -731,6 +732,7 @@ d_open_t drm_open;
 d_close_t drm_close;
 d_read_t drm_read;
 d_poll_t drm_poll;
+d_kqfilter_t drm_kqfilter;
 d_mmap_t drm_mmap;
 extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
 
index 1220b14..12f79ab 100644 (file)
@@ -119,12 +119,13 @@ static drm_ioctl_desc_t             drm_ioctls[256] = {
 };
 
 static struct dev_ops drm_cdevsw = {
-       { "drm", 145, D_TRACKCLOSE },
+       { "drm", 145, D_TRACKCLOSE | D_KQFILTER },
        .d_open =       drm_open,
        .d_close =      drm_close,
        .d_read =       drm_read,
        .d_ioctl =      drm_ioctl,
        .d_poll =       drm_poll,
+       .d_kqfilter =   drm_kqfilter,
        .d_mmap =       drm_mmap
 };
 
index a6a4cd5..db820fc 100644 (file)
@@ -113,3 +113,35 @@ int drm_poll(struct dev_poll_args *ap)
 {
        return 0;
 }
+
+static int
+drmfilt(struct knote *kn, long hint)
+{
+       return (0);
+}
+
+static void
+drmfilt_detach(struct knote *kn) {}
+
+static struct filterops drmfiltops =
+        { 1, NULL, drmfilt_detach, drmfilt };
+
+int
+drm_kqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+       case EVFILT_WRITE:
+               kn->kn_fop = &drmfiltops;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       return (0);
+}
index 7aa26d5..89f778b 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/uio.h>
@@ -131,18 +132,24 @@ static d_close_t  cmx_close;
 static d_read_t                cmx_read;
 static d_write_t       cmx_write;
 static d_poll_t                cmx_poll;
+static d_kqfilter_t    cmx_kqfilter;
 #ifdef CMX_INTR
 static void            cmx_intr(void *arg);
 #endif
 
+static void cmx_filter_detach(struct knote *);
+static int cmx_filter_read(struct knote *, long);
+static int cmx_filter_write(struct knote *, long);
+
 #define CDEV_MAJOR     185
 static struct dev_ops cmx_ops = {
-       { "cmx", CDEV_MAJOR, 0 },
+       { "cmx", CDEV_MAJOR, D_KQFILTER },
        .d_open =       cmx_open,
        .d_close =      cmx_close,
        .d_read =       cmx_read,
        .d_write =      cmx_write,
        .d_poll =       cmx_poll,
+       .d_kqfilter =   cmx_kqfilter
 };
 
 /*
@@ -687,6 +694,96 @@ cmx_poll(struct dev_poll_args *ap)
        return revents;
 }
 
+static struct filterops cmx_read_filterops =
+       { 1, NULL, cmx_filter_detach, cmx_filter_read };
+static struct filterops cmx_write_filterops =
+       { 1, NULL, cmx_filter_detach, cmx_filter_write };
+
+/*
+ * Kevent handler.  Writing is always possible, reading is only possible
+ * if BSR_BULK_IN_FULL is set.  Will start the cmx_tick callout and
+ * set sc->polling.
+ */
+static int
+cmx_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct cmx_softc *sc;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       sc = devclass_get_softc(cmx_devclass, minor(dev));
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &cmx_read_filterops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &cmx_write_filterops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+cmx_filter_detach(struct knote *kn)
+{
+       struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+cmx_filter_read(struct knote *kn, long hint)
+{
+       struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
+       int ready = 0;
+        uint8_t bsr = 0;
+
+        if (sc == NULL || sc->dying) {
+               kn->kn_flags |= EV_EOF;
+                return (1);
+       }
+
+        bsr = cmx_read_BSR(sc);
+       if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
+               ready = 1;
+       } else {
+               CMX_LOCK(sc);
+               if (!sc->polling) {
+                       sc->polling = 1;
+                       callout_reset(&sc->ch, POLL_TICKS,
+                                     cmx_tick, sc);
+               }
+               CMX_UNLOCK(sc);
+       }
+
+       return (ready);
+}
+
+static int
+cmx_filter_write(struct knote *kn, long hint)
+{
+       return (1);
+}
+
 #ifdef CMX_INTR
 /*
  * Interrupt handler.  Currently has no function except to
index f684a71..25e24e5 100644 (file)
@@ -94,13 +94,14 @@ static d_close_t    dcons_close;
 static d_ioctl_t       dcons_ioctl;
 
 static struct dev_ops dcons_ops = {
-       { "dcons", CDEV_MAJOR, D_TTY },
+       { "dcons", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       dcons_open,
        .d_close =      dcons_close,
        .d_read =       ttyread,
        .d_write =      ttywrite,
        .d_ioctl =      dcons_ioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter,
        .d_revoke =     ttyrevoke
 };
 
index 4faafbb..dd77692 100644 (file)
@@ -29,6 +29,7 @@
 #include <sys/lock.h>
 #include <sys/selinfo.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/uio.h>
 #include <sys/thread.h>
 #include <sys/thread2.h>
@@ -42,13 +43,18 @@ static d_open_t             hotplugopen;
 static d_close_t       hotplugclose;
 static d_read_t                hotplugread;
 static d_poll_t                hotplugpoll;
+static d_kqfilter_t    hotplugkqfilter;
+
+static void hotplugfiltdetach(struct knote *);
+static int hotplugfilt(struct knote *, long);
 
 static struct dev_ops hotplug_ops = {
-       { "hotplug", CDEV_MAJOR, 0 },
+       { "hotplug", CDEV_MAJOR, D_KQFILTER },
        .d_open =       hotplugopen,
        .d_close =      hotplugclose,
        .d_read =       hotplugread,
        .d_poll =       hotplugpoll,
+       .d_kqfilter =   hotplugkqfilter
 };
 
 struct hotplug_event_info {
@@ -119,6 +125,62 @@ hotplugpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops hotplugfiltops =
+       { 1, NULL, hotplugfiltdetach, hotplugfilt };
+
+static int
+hotplugkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &hotplugfiltops;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       lockmgr(&hpsc.lock, LK_EXCLUSIVE);
+       crit_enter();
+       klist = &hpsc.sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+       lockmgr(&hpsc.lock, LK_RELEASE);
+
+       return (0);
+}
+
+static void
+hotplugfiltdetach(struct knote *kn)
+{
+       struct klist *klist;
+
+       lockmgr(&hpsc.lock, LK_EXCLUSIVE);
+       crit_enter();
+       klist = &hpsc.sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+       lockmgr(&hpsc.lock, LK_RELEASE);
+}
+
+static int
+hotplugfilt(struct knote *kn, long hint)
+{
+       int ready = 0;
+
+       lockmgr(&hpsc.lock, LK_EXCLUSIVE);
+       if (!TAILQ_EMPTY(&hpsc.queue))
+               ready = 1;
+       lockmgr(&hpsc.lock, LK_RELEASE);
+
+       return (ready);
+}
+
 int
 hotplug_get_event(struct hotplug_event *he)
 {
index c4266d9..a612c84 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/proc.h>
 #include <sys/tty.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/vnode.h>
 #include <sys/uio.h>
 #include <sys/thread.h>
@@ -495,17 +496,22 @@ static d_read_t           genkbdread;
 static d_write_t       genkbdwrite;
 static d_ioctl_t       genkbdioctl;
 static d_poll_t                genkbdpoll;
+static d_kqfilter_t    genkbdkqfilter;
+
+static void genkbdfiltdetach(struct knote *);
+static int genkbdfilter(struct knote *, long);
 
 #define CDEV_MAJOR     112
 
 static struct dev_ops kbd_ops = {
-       { "kbd", CDEV_MAJOR, 0 },
+       { "kbd", CDEV_MAJOR, D_KQFILTER },
        .d_open =       genkbdopen,
        .d_close =      genkbdclose,
        .d_read =       genkbdread,
        .d_write =      genkbdwrite,
        .d_ioctl =      genkbdioctl,
        .d_poll =       genkbdpoll,
+       .d_kqfilter =   genkbdkqfilter
 };
 
 /*
@@ -767,6 +773,75 @@ genkbdpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops genkbdfiltops =
+       { 1, NULL, genkbdfiltdetach, genkbdfilter };
+
+static int
+genkbdkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       genkbd_softc_t sc;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &genkbdfiltops;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       sc = dev->si_drv1;
+       klist = &sc->gkb_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+genkbdfiltdetach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       genkbd_softc_t sc;
+       struct klist *klist;
+
+       crit_enter();
+       sc = dev->si_drv1;
+       klist = &sc->gkb_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+genkbdfilter(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       keyboard_t *kbd;
+       genkbd_softc_t sc;
+       int ready = 0;
+
+       crit_enter();
+       sc = dev->si_drv1;
+        kbd = kbd_get_keyboard(KBD_INDEX(dev));
+       if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
+               kn->kn_flags |= EV_EOF; /* the keyboard has gone */
+               ready = 1;
+       } else {
+               if (sc->gkb_q_length > 0)
+                        ready = 1;
+        }
+       crit_exit();
+
+       return (ready);
+}
+
 static int
 genkbd_event(keyboard_t *kbd, int event, void *arg)
 {
index a7c432c..e65b672 100644 (file)
@@ -52,6 +52,7 @@
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/selinfo.h>
 #include <sys/uio.h>
 #include <sys/rman.h>
@@ -135,6 +136,10 @@ static     d_close_t       mseclose;
 static d_read_t        mseread;
 static  d_ioctl_t      mseioctl;
 static d_poll_t        msepoll;
+static d_kqfilter_t    msekqfilter;
+
+static void msefilter_detach(struct knote *);
+static int msefilter(struct knote *, long);
 
 #define CDEV_MAJOR 27
 static struct dev_ops mse_ops = {
@@ -144,6 +149,7 @@ static struct dev_ops mse_ops = {
        .d_read =       mseread,
        .d_ioctl =      mseioctl,
        .d_poll =       msepoll,
+       .d_kqfilter =   msekqfilter
 };
 
 static void            mseintr (void *);
@@ -634,6 +640,66 @@ msepoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops msefiltops =
+       { 1, NULL, msefilter_detach, msefilter };
+
+static int
+msekqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &msefiltops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_selp.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+msefilter_detach(struct knote *kn)
+{
+       mse_softc_t *sc = (mse_softc_t *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->sc_selp.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+msefilter(struct knote *kn, long hint)
+{
+       mse_softc_t *sc = (mse_softc_t *)kn->kn_hook;
+       int ready = 0;
+
+       crit_enter();
+       if (sc->sc_bytesread != sc->mode.packetsize ||
+           sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
+           (sc->sc_obuttons ^ sc->sc_buttons) != 0)
+               ready = 1;
+
+       crit_exit();
+
+       return (ready);
+}
+
 /*
  * msetimeout: watchdog timer routine.
  */
index f49d4f3..bd40c45 100644 (file)
@@ -70,13 +70,14 @@ static      d_ioctl_t       nmdmioctl;
 
 #define        CDEV_MAJOR      18
 static struct dev_ops nmdm_ops = {
-       { "pts", CDEV_MAJOR, D_TTY },
+       { "pts", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       nmdmopen,
        .d_close =      nmdmclose,
        .d_read =       nmdmread,
        .d_write =      nmdmwrite,
        .d_ioctl =      nmdmioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter,
        .d_revoke =     ttyrevoke
 };
 
index 30c4405..08332fc 100644 (file)
@@ -72,6 +72,7 @@
 #include <sys/conf.h>
 #include <sys/device.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/syslog.h>
 #include <sys/malloc.h>
 #include <sys/rman.h>
@@ -242,6 +243,7 @@ static d_close_t psmclose;
 static d_read_t psmread;
 static d_ioctl_t psmioctl;
 static d_poll_t psmpoll;
+static d_kqfilter_t psmkqfilter;
 
 static int enable_aux_dev (KBDC);
 static int disable_aux_dev (KBDC);
@@ -261,6 +263,8 @@ static int reinitialize (struct psm_softc *, int);
 static char *model_name (int);
 static void psmintr (void *);
 static void psmtimeout (void *);
+static void psmfilter_detach(struct knote *);
+static int psmfilter(struct knote *, long);
 
 /* vendor specific features */
 typedef int probefunc_t (struct psm_softc *);
@@ -342,12 +346,13 @@ static struct isa_pnp_id psm_ids[] = {
 #define CDEV_MAJOR        21
 
 static struct dev_ops psm_ops = {
-       { PSM_DRIVER_NAME, CDEV_MAJOR, 0 },
+       { PSM_DRIVER_NAME, CDEV_MAJOR, D_KQFILTER },
        .d_open =       psmopen,
        .d_close =      psmclose,
        .d_read =       psmread,
        .d_ioctl =      psmioctl,
        .d_poll =       psmpoll,
+       .d_kqfilter =   psmkqfilter
 };
 
 /* debug message level */
@@ -2399,6 +2404,63 @@ psmpoll(struct dev_poll_args *ap)
     return (0);
 }
 
+static struct filterops psmfiltops =
+       { 1, NULL, psmfilter_detach, psmfilter };
+
+static int
+psmkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &psmfiltops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+psmfilter_detach(struct knote *kn)
+{
+       struct psm_softc *sc = (struct psm_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+psmfilter(struct knote *kn, long hint)
+{
+       struct psm_softc *sc = (struct psm_softc *)kn->kn_hook;
+       int ready = 0;
+
+       crit_enter();
+       if (sc->queue.count > 0)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
 /* vendor/model specific routines */
 
 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
index c9e7987..e31c2df 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/tty.h>
 #include <sys/conf.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/kernel.h>
 #include <sys/queue.h>
 #include <sys/snoop.h>
@@ -40,9 +41,13 @@ static       d_read_t        snpread;
 static d_write_t       snpwrite;
 static d_ioctl_t       snpioctl;
 static d_poll_t        snppoll;
+static d_kqfilter_t    snpkqfilter;
 static d_clone_t       snpclone;
 DEVFS_DECLARE_CLONE_BITMAP(snp);
 
+static void snpfilter_detach(struct knote *);
+static int snpfilter(struct knote *, long);
+
 #if NSNP <= 1
 #define SNP_PREALLOCATED_UNITS 4
 #else
@@ -51,13 +56,14 @@ DEVFS_DECLARE_CLONE_BITMAP(snp);
 
 #define CDEV_MAJOR 53
 static struct dev_ops snp_ops = {
-       { "snp", CDEV_MAJOR, 0 },
+       { "snp", CDEV_MAJOR, D_KQFILTER },
        .d_open =       snpopen,
        .d_close =      snpclose,
        .d_read =       snpread,
        .d_write =      snpwrite,
        .d_ioctl =      snpioctl,
        .d_poll =       snppoll,
+       .d_kqfilter =   snpkqfilter
 };
 
 static struct linesw snpdisc = {
@@ -582,6 +588,66 @@ snppoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops snpfiltops =
+        { 1, NULL, snpfilter_detach, snpfilter };
+
+static int
+snpkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct snoop *snp = dev->si_drv1;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &snpfiltops;
+               kn->kn_hook = (caddr_t)snp;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &snp->snp_sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+snpfilter_detach(struct knote *kn)
+{
+       struct snoop *snp = (struct snoop *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &snp->snp_sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+snpfilter(struct knote *kn, long hint)
+{
+       struct snoop *snp = (struct snoop *)kn->kn_hook;
+       int ready = 0;
+
+       /*
+        * If snoop is down, we don't want to poll forever so we return 1.
+        * Caller should see if we down via FIONREAD ioctl().  The last should
+        * return -1 to indicate down state.
+        */
+       if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0)
+               ready = 1;
+
+       return (ready);
+}
+
 static int
 snpclone(struct dev_clone_args *ap)
 {
index 5228c2d..42ef04e 100644 (file)
@@ -57,6 +57,7 @@
 #include <sys/bus.h>
 #include <sys/rman.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/tty.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
@@ -86,14 +87,19 @@ static d_close_t    spicclose;
 static d_read_t                spicread;
 static d_ioctl_t       spicioctl;
 static d_poll_t                spicpoll;
+static d_kqfilter_t    spickqfilter;
+
+static void spicfilt_detach(struct knote *);
+static int spicfilt(struct knote *, long);
 
 static struct dev_ops spic_ops = {
-       { "spic", CDEV_MAJOR, 0 },
+       { "spic", CDEV_MAJOR, D_KQFILTER },
         .d_open =      spicopen,
         .d_close =     spicclose,
         .d_read =      spicread,
         .d_ioctl =     spicioctl,
         .d_poll =      spicpoll,
+       .d_kqfilter =   spickqfilter
 };
 
 #define SCBUFLEN 128
@@ -538,6 +544,62 @@ spicpoll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops spicfiltops =
+       { 1, NULL, spicfilt_detach, spicfilt };
+
+static int
+spickqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+       struct spic_softc *sc;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sc = devclass_get_softc(spic_devclass, 0);
+               kn->kn_fop = &spicfiltops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+spicfilt_detach(struct knote *kn)
+{
+       struct spic_softc *sc = (struct spic_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+spicfilt(struct knote *kn, long hint)
+{
+       struct spic_softc *sc = (struct spic_softc *)kn->kn_hook;
+       int ready = 0;
+
+       crit_enter();
+       if (sc->sc_count)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
 
 static device_method_t spic_methods[] = {
        DEVMETHOD(device_probe,         spic_probe),
index ba3ea51..e0fb193 100644 (file)
@@ -53,12 +53,13 @@ static d_close_t    smclose;
 static d_ioctl_t       smioctl;
 
 static struct dev_ops sm_ops = {
-       { "sysmouse", CDEV_MAJOR, D_TTY },
+       { "sysmouse", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       smopen,
        .d_close =      smclose,
        .d_read =       ttyread,
        .d_ioctl =      smioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter,
        .d_revoke =     ttyrevoke
 };
 
index 587280c..5ba33db 100644 (file)
 #include <sys/syslog.h>
 #include <sys/selinfo.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/thread2.h>
 
 #ifdef HIRESTIME
@@ -215,6 +216,10 @@ static     d_close_t       twclose;
 static d_read_t        twread;
 static d_write_t       twwrite;
 static d_poll_t        twpoll;
+static d_kqfilter_t    twkqfilter;
+
+static void twfilter_detach(struct knote *);
+static int twfilter(struct knote *, long);
 
 #define CDEV_MAJOR 19
 static struct dev_ops tw_ops = {
@@ -224,6 +229,7 @@ static struct dev_ops tw_ops = {
        .d_read =       twread,
        .d_write =      twwrite,
        .d_poll =       twpoll,
+       .d_kqfilter =   twkqfilter
 };
 
 /*
@@ -542,6 +548,64 @@ twpoll(struct dev_poll_args *ap)
   return(0);
 }
 
+static struct filterops twfiltops =
+       { 1, NULL, twfilter_detach, twfilter };
+
+static int
+twkqfilter(struct dev_kqfilter_args *ap)
+{
+  cdev_t dev = ap->a_head.a_dev;
+  struct knote *kn = ap->a_kn;
+  struct klist *klist;
+  struct tw_sc *sc;
+
+  ap->a_result = 0;
+
+  switch (kn->kn_filter) {
+  case EVFILT_READ:
+    sc = &tw_sc[TWUNIT(dev)];
+    kn->kn_fop = &twfiltops;
+    kn->kn_hook = (caddr_t)sc;
+    break;
+  default:
+    ap->a_result = 1;
+    return (0);
+  }
+
+  crit_enter();
+  klist = &sc->sc_selp.si_note;
+  SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+  crit_exit();
+
+  return (0);
+}
+
+static void
+twfilter_detach(struct knote *kn)
+{
+  struct tw_sc *sc = (struct tw_sc *)kn->kn_hook;
+  struct klist *klist;
+
+  crit_enter();
+  klist = &sc->sc_selp.si_note;
+  SLIST_REMOVE(klist, kn, knote, kn_selnext);
+  crit_exit();
+}
+
+static int
+twfilter(struct knote *kn, long hint)
+{
+  struct tw_sc *sc = (struct tw_sc *)kn->kn_hook;
+  int ready = 0;
+
+  crit_enter();
+  if(sc->sc_nextin != sc->sc_nextout)
+    ready = 1;
+  crit_exit();
+
+  return (ready);
+}
+
 /*
  * X-10 Protocol
  */
index 09bd875..cdafcdd 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/kthread.h>
 #include <sys/sysctl.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 
 #include <sys/bus.h>
 #include <sys/conf.h>
@@ -213,6 +214,9 @@ static d_open_t             aac_open;
 static d_close_t       aac_close;
 static d_ioctl_t       aac_ioctl;
 static d_poll_t                aac_poll;
+static d_kqfilter_t    aac_kqfilter;
+static void            aac_filter_detach(struct knote *kn);
+static int             aac_filter(struct knote *kn, long hint);
 static int             aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) __unused;
 static void            aac_handle_aif(struct aac_softc *sc,
                                           struct aac_fib *fib);
@@ -227,11 +231,12 @@ static void               aac_ioctl_event(struct aac_softc *sc,
 #define AAC_CDEV_MAJOR 150
 
 static struct dev_ops aac_ops = {
-       { "aac", AAC_CDEV_MAJOR, 0 },
+       { "aac", AAC_CDEV_MAJOR, D_KQFILTER },
        .d_open =       aac_open,
        .d_close =      aac_close,
        .d_ioctl =      aac_ioctl,
        .d_poll =       aac_poll,
+       .d_kqfilter =   aac_kqfilter
 };
 
 DECLARE_DUMMY_MODULE(aac);
@@ -3084,6 +3089,64 @@ aac_poll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops aac_filterops =
+       { 1, NULL, aac_filter_detach, aac_filter };
+
+static int
+aac_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct aac_softc *sc = dev->si_drv1;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &aac_filterops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->rcv_select.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+aac_filter_detach(struct knote *kn)
+{
+       struct aac_softc *sc = (struct aac_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->rcv_select.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+aac_filter(struct knote *kn, long hint)
+{
+       struct aac_softc *sc = (struct aac_softc *)kn->kn_hook;
+       int ready = 0;
+
+       AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
+       if (sc->aac_aifq_tail != sc->aac_aifq_head)
+               ready = 1;
+       AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
+
+       return (ready);
+}
+
+
 static void
 aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
 {
index a9ca135..979dc2d 100644 (file)
@@ -45,6 +45,8 @@
 #include "vinumhdr.h"
 #include <sys/sysproto.h>                                  /* for sync(2) */
 #include <sys/devicestat.h>
+#include <sys/poll.h>
+#include <sys/event.h>
 #ifdef VINUMDEBUG
 #include <sys/reboot.h>
 int debug = 0;
@@ -56,13 +58,14 @@ extern struct mc malloced[];
 
 struct dev_ops vinum_ops =
 {
-       { "vinum", VINUM_CDEV_MAJOR, D_DISK },
+       { "vinum", VINUM_CDEV_MAJOR, D_DISK | D_KQFILTER },
        .d_open =       vinumopen,
        .d_close =      vinumclose,
        .d_read =       physread,
        .d_write =      physwrite,
        .d_ioctl =      vinumioctl,
        .d_poll =       vinumpoll,
+       .d_kqfilter =   vinumkqfilter,
        .d_strategy =   vinumstrategy,
        .d_dump =       vinumdump,
        .d_psize =      vinumsize,
@@ -579,6 +582,37 @@ vinumpoll(struct dev_poll_args *ap)
     return(0);
 }
 
+void
+vinumfilt_detach(struct knote *kn) {}
+
+int
+vinumfilt(struct knote *kn, long hint)
+{
+    cdev_t dev = (cdev_t)kn->kn_hook;
+
+    if (seltrue(dev, POLLIN | POLLRDNORM))
+        return (1);
+
+    return (0);
+}
+
+struct filterops vinumfiltops =
+    { 1, NULL, vinumfilt_detach, vinumfilt };
+
+int
+vinumkqfilter(struct dev_kqfilter_args *ap)
+{
+    if (ap->a_kn->kn_filter == EVFILT_READ) {
+        ap->a_kn->kn_fop = &vinumfiltops;
+        ap->a_kn->kn_hook = (caddr_t)ap->a_head.a_dev;
+        ap->a_result = 0;
+    } else {
+        ap->a_result = 1;
+    }
+
+    return (0);
+}
+
 /* Local Variables: */
 /* fill-column: 50 */
 /* End: */
index 94ed10f..687f7fc 100644 (file)
@@ -139,6 +139,10 @@ d_ioctl_t vinumioctl;
 d_dump_t vinumdump;
 d_psize_t vinumsize;
 d_poll_t vinumpoll;
+d_kqfilter_t vinumkqfilter;
+
+int vinumfilt(struct knote *, long);
+void vinumfilt_detach(struct knote *);
 
 int vinumstart(cdev_t dev, struct bio *bio, int reviveok);
 int launch_requests(struct request *rq, int reviveok);
index d831ad7..4cee213 100644 (file)
@@ -572,13 +572,14 @@ static    d_ioctl_t       rpioctl;
 
 #define        CDEV_MAJOR      81
 struct dev_ops rp_ops = {
-       { "rp", CDEV_MAJOR, D_TTY },
+       { "rp", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       rpopen,
        .d_close =      rpclose,
        .d_read =       ttyread,
        .d_write =      rpwrite,
        .d_ioctl =      rpioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter,
        .d_revoke =     ttyrevoke
 };
 
index 48fdd42..c799e0f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <sys/param.h>
 #include <sys/queue.h>
+#include <sys/event.h>
 
 #include <dev/sound/pcm/dsp.h>
 #include <dev/sound/pcm/sound.h>
@@ -43,8 +44,13 @@ static d_read_t dsp_read;
 static d_write_t dsp_write;
 static d_ioctl_t dsp_ioctl;
 static d_poll_t dsp_poll;
+static d_kqfilter_t dsp_kqfilter;
 static d_mmap_t dsp_mmap;
 
+static void dsp_filter_detach(struct knote *);
+static int dsp_filter_read(struct knote *, long);
+static int dsp_filter_write(struct knote *, long);
+
 struct dev_ops dsp_cdevsw = {
        { "dsp", SND_CDEV_MAJOR, 0},
        /*.d_flags =    D_NEEDGIANT,*/
@@ -54,6 +60,7 @@ struct dev_ops dsp_cdevsw = {
        .d_write =      dsp_write,
        .d_ioctl =      dsp_ioctl,
        .d_poll =       dsp_poll,
+       .d_kqfilter =   dsp_kqfilter,
        .d_mmap =       dsp_mmap,
 };
 
@@ -1109,6 +1116,96 @@ dsp_poll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops dsp_read_filtops =
+       { 1, NULL, dsp_filter_detach, dsp_filter_read };
+static struct filterops dsp_write_filtops =
+       { 1, NULL, dsp_filter_detach, dsp_filter_write };
+
+static int
+dsp_kqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+       struct cdev *i_dev = ap->a_head.a_dev;
+       struct pcm_channel *wrch = NULL, *rdch = NULL;
+       struct snd_dbuf *bs;
+
+       getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+       ap->a_result = 1;
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               if (rdch) {
+                       kn->kn_fop = &dsp_read_filtops;
+                       kn->kn_hook = (caddr_t)rdch;
+                       bs = rdch->bufsoft;
+                       ap->a_result = 0;
+               }
+               break;
+       case EVFILT_WRITE:
+               if (wrch) {
+                       kn->kn_fop = &dsp_write_filtops;
+                       kn->kn_hook = (caddr_t)wrch;
+                       bs = wrch->bufsoft;
+                       ap->a_result = 0;
+               }
+               break;
+       }
+
+       if (ap->a_result == 0) {
+               crit_enter();
+               klist = &sndbuf_getsel(bs)->si_note;
+               SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+               crit_exit();
+       }
+
+       relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+
+       return (0);
+}
+
+static void
+dsp_filter_detach(struct knote *kn)
+{
+       struct pcm_channel *ch = (struct pcm_channel *)kn->kn_hook;
+       struct snd_dbuf *bs = ch->bufsoft;
+       struct klist *klist;
+
+       CHN_LOCK(ch);
+       crit_enter();
+       klist = &sndbuf_getsel(bs)->si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+       CHN_UNLOCK(ch);
+}
+
+static int
+dsp_filter_read(struct knote *kn, long hint)
+{
+       struct pcm_channel *rdch = (struct pcm_channel *)kn->kn_hook;
+       struct thread *td = curthread;
+       int ready;
+
+       CHN_LOCK(rdch);
+       ready = chn_poll(rdch, 1, td);
+       CHN_UNLOCK(rdch);
+
+       return (ready);
+}
+
+static int
+dsp_filter_write(struct knote *kn, long hint)
+{
+       struct pcm_channel *wrch = (struct pcm_channel *)kn->kn_hook;
+       struct thread *td = curthread;
+       int ready;
+
+       CHN_LOCK(wrch);
+       ready = chn_poll(wrch, 1, td);
+       CHN_UNLOCK(wrch);
+
+       return (ready);
+}
+
 static int
 dsp_mmap(struct dev_mmap_args *ap)
 {
index 8588c92..fcce4b0 100644 (file)
@@ -64,6 +64,7 @@
 #include <sys/select.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -140,17 +141,23 @@ d_read_t  ugenread;
 d_write_t ugenwrite;
 d_ioctl_t ugenioctl;
 d_poll_t  ugenpoll;
+d_kqfilter_t ugenkqfilter;
+
+static void ugen_filt_detach(struct knote *);
+static int ugen_filt_read(struct knote *, long);
+static int ugen_filt_write(struct knote *, long);
 
 #define UGEN_CDEV_MAJOR        114
 
 static struct dev_ops ugen_ops = {
-       { "ugen", UGEN_CDEV_MAJOR, 0 },
+       { "ugen", UGEN_CDEV_MAJOR, D_KQFILTER },
        .d_open =       ugenopen,
        .d_close =      ugenclose,
        .d_read =       ugenread,
        .d_write =      ugenwrite,
        .d_ioctl =      ugenioctl,
        .d_poll =       ugenpoll,
+       .d_kqfilter =   ugenkqfilter
 };
 
 static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
@@ -1501,5 +1508,147 @@ ugenpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops ugen_filtops_read =
+       { 1, NULL, ugen_filt_detach, ugen_filt_read };
+static struct filterops ugen_filtops_write =
+       { 1, NULL, ugen_filt_detach, ugen_filt_write };
+
+int
+ugenkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+        struct ugen_softc *sc;
+        struct ugen_endpoint *sce;
+
+        sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+
+       ap->a_result = 1;
+
+       if (sc->sc_dying)
+               return (0);
+
+        /* Do not allow filter on a control endpoint */
+        if (UGENENDPOINT(dev) == USB_CONTROL_ENDPOINT)
+               return (0);
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+               kn->kn_fop = &ugen_filtops_read;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       case EVFILT_WRITE:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+               kn->kn_fop = &ugen_filtops_write;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       if (sce->edesc != NULL || sce->pipeh != NULL) {
+               crit_enter();
+               klist = &sce->rsel.si_note;
+               SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+               crit_exit();
+       }
+
+       return (0);
+}
+
+static void
+ugen_filt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+        struct ugen_softc *sc;
+        struct ugen_endpoint *sce;
+       struct klist *klist;
+
+        sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+               break;
+       case EVFILT_WRITE:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+               break;
+       default:
+               return;
+       }
+
+       if (sce->edesc != NULL || sce->pipeh != NULL) {
+               crit_enter();
+               klist = &sce->rsel.si_note;
+               SLIST_REMOVE(klist, kn, knote, kn_selnext);
+               crit_exit();
+       }
+}
+
+static int
+ugen_filt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct ugen_softc *sc;
+       struct ugen_endpoint *sce;
+       int ready = 0;
+
+       sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+       sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+
+       switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+       case UE_INTERRUPT:
+               if (sce->q.c_cc > 0)
+                       ready = 1;
+               break;
+       case UE_ISOCHRONOUS:
+               if (sce->cur != sce->fill)
+                       ready = 1;
+               break;
+       case UE_BULK:
+               ready = 1;
+               break;
+       default:
+               break;
+       }
+
+       return (ready);
+}
+
+static int
+ugen_filt_write(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct ugen_softc *sc;
+       struct ugen_endpoint *sce;
+       int ready = 0;
+
+       sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+       sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+
+       switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+       case UE_INTERRUPT:
+               if (sce->q.c_cc > 0)
+                       ready = 1;
+               break;
+       case UE_ISOCHRONOUS:
+               if (sce->cur != sce->fill)
+                       ready = 1;
+               break;
+       case UE_BULK:
+               ready = 1;
+               break;
+       default:
+               break;
+       }
+
+       return (ready);
+}
+
 DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
 
index 8818eac..f69d443 100644 (file)
@@ -64,6 +64,7 @@
 #include <sys/proc.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -132,17 +133,23 @@ d_read_t  uhidread;
 d_write_t      uhidwrite;
 d_ioctl_t      uhidioctl;
 d_poll_t       uhidpoll;
+d_kqfilter_t   uhidkqfilter;
+
+static void uhidfilt_detach(struct knote *);
+static int uhidfilt_read(struct knote *, long);
+static int uhidfilt_write(struct knote *, long);
 
 #define                UHID_CDEV_MAJOR 122
 
 static struct dev_ops uhid_ops = {
-       { "uhid", UHID_CDEV_MAJOR, 0 },
+       { "uhid", UHID_CDEV_MAJOR, D_KQFILTER },
        .d_open =       uhidopen,
        .d_close =      uhidclose,
        .d_read =       uhidread,
        .d_write =      uhidwrite,
        .d_ioctl =      uhidioctl,
        .d_poll =       uhidpoll,
+       .d_kqfilter =   uhidkqfilter
 };
 
 static void uhid_intr(usbd_xfer_handle, usbd_private_handle,
@@ -691,5 +698,87 @@ uhidpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops uhidfiltops_read =
+       { 1, NULL, uhidfilt_detach, uhidfilt_read };
+static struct filterops uhidfiltops_write =
+       { 1, NULL, uhidfilt_detach, uhidfilt_write };
+
+int
+uhidkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct uhid_softc *sc;
+       struct klist *klist;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       if (sc->sc_dying) {
+               ap->a_result = 1;
+               return (0);
+       }
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &uhidfiltops_read;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &uhidfiltops_write;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+uhidfilt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct uhid_softc *sc;
+       struct klist *klist;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+uhidfilt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct uhid_softc *sc;
+       int ready = 0;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       crit_enter();
+       if (sc->sc_q.c_cc > 0)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
+static int
+uhidfilt_write(struct knote *kn, long hint)
+{
+       return (1);
+}
+
 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
 
index 01bd6f4..dae6af5 100644 (file)
@@ -56,6 +56,7 @@
 #include <sys/select.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -141,16 +142,21 @@ static d_close_t ums_close;
 static d_read_t  ums_read;
 static d_ioctl_t ums_ioctl;
 static d_poll_t  ums_poll;
+static d_kqfilter_t ums_kqfilter;
+
+static void ums_filt_detach(struct knote *);
+static int ums_filt(struct knote *, long);
 
 #define UMS_CDEV_MAJOR 111
 
 static struct dev_ops ums_ops = {
-       { "ums", UMS_CDEV_MAJOR, 0 },
+       { "ums", UMS_CDEV_MAJOR, D_KQFILTER },
        .d_open =       ums_open,
        .d_close =      ums_close,
        .d_read =       ums_read,
        .d_ioctl =      ums_ioctl,
        .d_poll =       ums_poll,
+       .d_kqfilter =   ums_kqfilter
 };
 
 static device_probe_t ums_match;
@@ -697,6 +703,64 @@ ums_poll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops ums_filtops =
+       { 1, NULL, ums_filt_detach, ums_filt };
+
+static int
+ums_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct ums_softc *sc;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
+               kn->kn_fop = &ums_filtops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+ums_filt_detach(struct knote *kn)
+{
+       struct ums_softc *sc = (struct ums_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+ums_filt(struct knote *kn, long hint)
+{
+       struct ums_softc *sc = (struct ums_softc *)kn->kn_hook;
+       int ready = 0;
+
+       crit_enter();
+       if (sc->qcount)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
 int
 ums_ioctl(struct dev_ioctl_args *ap)
 {
index 9175a14..f5179ba 100644 (file)
@@ -61,6 +61,7 @@
 #include <sys/select.h>
 #include <sys/proc.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
@@ -255,16 +256,18 @@ d_close_t uscannerclose;
 d_read_t  uscannerread;
 d_write_t uscannerwrite;
 d_poll_t  uscannerpoll;
+d_kqfilter_t uscannerkqfilter;
 
 #define USCANNER_CDEV_MAJOR    156
 
 static struct dev_ops uscanner_ops = {
-       { "uscanner", USCANNER_CDEV_MAJOR, 0 },
+       { "uscanner", USCANNER_CDEV_MAJOR, D_KQFILTER },
        .d_open =       uscanneropen,
        .d_close =      uscannerclose,
        .d_read =       uscannerread,
        .d_write =      uscannerwrite,
        .d_poll =       uscannerpoll,
+       .d_kqfilter =   uscannerkqfilter
 };
 
 static int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
@@ -669,5 +672,38 @@ uscannerpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static void
+uscannerfilt_detach(struct knote *kn) {}
+
+static int
+uscannerfilt(struct knote *kn, long hint)
+{
+       /*
+        * We have no easy way of determining if a read will
+        * yield any data or a write will happen.
+        * Pretend they will.
+        */
+       return (1);
+}
+
+static struct filterops uscannerfiltops =
+       { 1, NULL, uscannerfilt_detach, uscannerfilt };
+
+int
+uscannerkqfilter(struct dev_kqfilter_args *ap)
+{
+/* XXX
+       cdev_t dev = ap->a_head.a_dev;
+       struct uscanner_softc *sc = devclass_get_softc(uscanner_devclass, USCANNERUNIT(dev));
+
+       if (sc->sc_dying)
+               return (EIO);
+*/
+
+       ap->a_result = 0;
+       ap->a_kn->kn_fop = &uscannerfiltops;
+       return (0);
+}
+
 DRIVER_MODULE(uscanner, uhub, uscanner_driver, uscanner_devclass, usbd_driver_load, 0);
 
index 5247f4e..97e99bd 100644 (file)
@@ -62,6 +62,7 @@
 #include <sys/mman.h>
 #include <sys/poll.h>
 #include <sys/select.h>
+#include <sys/event.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
 #include <sys/thread2.h>
@@ -164,6 +165,10 @@ static     d_write_t       bktr_write;
 static d_ioctl_t       bktr_ioctl;
 static d_mmap_t        bktr_mmap;
 static d_poll_t        bktr_poll;
+static d_kqfilter_t    bktr_kqfilter;
+
+static void bktr_filter_detach(struct knote *);
+static int bktr_filter(struct knote *, long);
 
 #define CDEV_MAJOR 92 
 static struct dev_ops bktr_ops = {
@@ -174,6 +179,7 @@ static struct dev_ops bktr_ops = {
        .d_write =      bktr_write,
        .d_ioctl =      bktr_ioctl,
        .d_poll =       bktr_poll,
+       .d_kqfilter =   bktr_kqfilter,
        .d_mmap =       bktr_mmap,
 };
 
@@ -756,3 +762,75 @@ bktr_poll(struct dev_poll_args *ap)
        ap->a_events = revents;
        return (0);
 }
+
+static struct filterops bktr_filterops =
+       { 1, NULL, bktr_filter_detach, bktr_filter };
+
+static int
+bktr_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+       bktr_ptr_t bktr;
+       int unit;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               if (FUNCTION(minor(dev)) == VBI_DEV) {
+                       unit = UNIT(minor(dev));
+                       /* Get the device data */
+                       bktr = (struct bktr_softc *)
+                           devclass_get_softc(bktr_devclass, unit);
+                       kn->kn_fop = &bktr_filterops;
+                       kn->kn_hook = (caddr_t)bktr;
+                       break;
+               }
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &bktr->vbi_select.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+bktr_filter_detach(struct knote *kn)
+{
+       bktr_ptr_t bktr = (bktr_ptr_t)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &bktr->vbi_select.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+bktr_filter(struct knote *kn, long hint)
+{
+       bktr_ptr_t bktr = (bktr_ptr_t)kn->kn_hook;
+       int ready = 0;
+
+       if (bktr == NULL) {
+               /* the device is no longer valid/functioning */
+               kn->kn_flags |= EV_EOF;
+               return (1);
+       }
+
+       LOCK_VBI(bktr);
+       crit_enter();
+       if (bktr->vbisize != 0)
+               ready = 1;
+       crit_exit();
+       UNLOCK_VBI(bktr);
+
+       return (ready);
+}
index c70009f..5f88d6f 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/mman.h>
 #include <sys/module.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/proc.h>
 #include <sys/signalvar.h>
 #include <sys/thread2.h>
@@ -122,16 +123,21 @@ static    d_close_t       cxm_close;
 static d_read_t        cxm_read;
 static d_ioctl_t       cxm_ioctl;
 static d_poll_t        cxm_poll;
+static d_kqfilter_t    cxm_kqfilter;
+
+static void cxm_filter_detach(struct knote *);
+static int cxm_filter(struct knote *, long);
 
 #define CDEV_MAJOR 93
 
 static struct dev_ops cxm_ops = {
-       { "cxm", CDEV_MAJOR, 0 },
+       { "cxm", CDEV_MAJOR, D_KQFILTER },
        .d_open =       cxm_open,
        .d_close =      cxm_close,
        .d_read =       cxm_read,
        .d_ioctl =      cxm_ioctl,
-       .d_poll =       cxm_poll
+       .d_poll =       cxm_poll,
+       .d_kqfilter =   cxm_kqfilter
 };
 
 MODULE_DEPEND(cxm, cxm_iic, 1, 1, 1);
@@ -2935,3 +2941,70 @@ cxm_poll(struct dev_poll_args *ap)
 
        return revents;
 }
+
+static struct filterops cxm_filterops =
+       { 1, NULL, cxm_filter_detach, cxm_filter };
+
+static int
+cxm_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct cxm_softc *sc;
+       struct klist *klist;
+       int unit;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               unit = UNIT(minor(dev));
+               /* Get the device data */
+               sc = (struct cxm_softc *)devclass_get_softc(cxm_devclass, unit);
+               kn->kn_fop = &cxm_filterops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->enc_sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+cxm_filter_detach(struct knote *kn)
+{
+       struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->enc_sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+cxm_filter(struct knote *kn, long hint)
+{
+       struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
+       int ready = 0;
+
+       if (sc == NULL) {
+               /* the device is no longer valid/functioning */
+               kn->kn_flags |= EV_EOF;
+               return (1);
+       }
+
+       crit_enter();
+       if (sc->enc_pool.read != sc->enc_pool.write)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
index 9e8cd74..c19ca36 100644 (file)
@@ -38,6 +38,7 @@
 #include <sys/signalvar.h>
 #include <sys/sysent.h>
 #include <sys/sysproto.h>
+#include <sys/file.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -122,7 +123,7 @@ linux_kevent_to_epoll(struct kevent *kevent, struct linux_epoll_event *event)
  * of the filter.
  */
 static int
-linux_kev_copyout(void *arg, struct kevent *kevp, int count)
+linux_kev_copyout(void *arg, struct kevent *kevp, int count, int *res)
 {
         struct kevent_args *uap;
         struct linux_epoll_event *eep;
@@ -137,11 +138,13 @@ linux_kev_copyout(void *arg, struct kevent *kevp, int count)
         }
 
         error = copyout(eep, uap->eventlist, count * sizeof(*eep));
-        if (error)
+        if (error == 0) {
                 uap->eventlist = (struct kevent *)((char *)uap->eventlist + count * sizeof(*eep));
+               *res += count;
+       }
 
         kfree(eep, M_TEMP);
-        return (0);
+        return (error);
 }
 
 /*
@@ -149,15 +152,16 @@ linux_kev_copyout(void *arg, struct kevent *kevp, int count)
  * converted filters to the kevent internal memory.
  */
 static int
-linux_kev_copyin(void *arg, struct kevent *kevp, int count)
+linux_kev_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
 {
         struct kevent_args *uap;
 
         uap = (struct kevent_args*) arg;
 
-        memcpy(kevp, uap->changelist, count * sizeof(*kevp));
+        memcpy(kevp, uap->changelist, maxevents * sizeof(*kevp));
 
-        uap->changelist += count;
+        uap->changelist += maxevents;
+       *events = maxevents;
 
         return (0);
 }
@@ -169,9 +173,13 @@ linux_kev_copyin(void *arg, struct kevent *kevp, int count)
 int
 sys_linux_epoll_ctl(struct linux_epoll_ctl_args *args)
 {
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
         struct kevent_args k_args;
         struct kevent kev;
+       struct kqueue *kq;
         struct linux_epoll_event le;
+       struct file *fp = NULL;
         int error;
 
         error = copyin(args->event, &le, sizeof(le));
@@ -204,14 +212,25 @@ sys_linux_epoll_ctl(struct linux_epoll_ctl_args *args)
         }
         linux_epoll_to_kevent(args->fd, &le, &kev);
 
-       error = kern_kevent(args->epfd, 1, 0, &k_args, linux_kev_copyin,
-           linux_kev_copyout, NULL);
+       fp = holdfp(p->p_fd, args->epfd, -1);
+       if (fp == NULL)
+               return (EBADF);
+       if (fp->f_type != DTYPE_KQUEUE) {
+               fdrop(fp);
+               return (EBADF);
+       }
+
+       kq = (struct kqueue *)fp->f_data;
+
+       error = kern_kevent(kq, 0, &k_args.sysmsg_result, &k_args,
+           linux_kev_copyin, linux_kev_copyout, NULL);
         /* Check if there was an error during registration. */
         if (error == 0 && k_args.sysmsg_result != 0) {
                 /* The copyout callback stored the error there. */
                 error = le.data;
         }
 
+       fdrop(fp);
         return (error);
 }
 
@@ -220,13 +239,17 @@ sys_linux_epoll_ctl(struct linux_epoll_ctl_args *args)
 int
 sys_linux_epoll_wait(struct linux_epoll_wait_args *args)
 {
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
         struct timespec ts;
+       struct kqueue *kq;
+       struct file *fp = NULL;
         struct kevent_args k_args;
         int error;
 
-        /* Convert from miliseconds to timespec. */
-        ts.tv_sec = args->timeout / 1000000;
-        ts.tv_nsec = (args->timeout % 1000000) * 1000;
+        /* Convert from milliseconds to timespec. */
+        ts.tv_sec = args->timeout / 1000;
+        ts.tv_nsec = (args->timeout % 1000) * 1000 * 1000;
 
         k_args.fd = args->epfd;
         k_args.changelist = NULL;
@@ -240,9 +263,20 @@ sys_linux_epoll_wait(struct linux_epoll_wait_args *args)
         k_args.nevents = args->maxevents;
         k_args.timeout = &ts;
 
-       error = kern_kevent(args->epfd, 0, args->maxevents, &k_args,
-           linux_kev_copyin, linux_kev_copyout, &ts);
+       fp = holdfp(p->p_fd, args->epfd, -1);
+       if (fp == NULL)
+               return (EBADF);
+       if (fp->f_type != DTYPE_KQUEUE) {
+               fdrop(fp);
+               return (EBADF);
+       }
+
+       kq = (struct kqueue *)fp->f_data;
+
+       error = kern_kevent(kq, args->maxevents, &args->sysmsg_result,
+           &k_args, linux_kev_copyin, linux_kev_copyout, &ts);
 
+       fdrop(fp);
         /* translation? */
         return (error);
 }
index defe052..a91428f 100644 (file)
@@ -50,6 +50,7 @@
 #include <sys/uio.h>
 #include <sys/signalvar.h>
 #include <sys/filio.h>
+#include <sys/ktr.h>
 
 #include <sys/thread2.h>
 #include <sys/file2.h>
 
 MALLOC_DEFINE(M_KQUEUE, "kqueue", "memory for kqueue system");
 
+struct kevent_copyin_args {
+       struct kevent_args      *ka;
+       int                     pchanges;
+};
+
+static int     kqueue_sleep(struct kqueue *kq, struct timespec *tsp);
 static int     kqueue_scan(struct kqueue *kq, struct kevent *kevp, int count,
-                   struct timespec *tsp, int *errorp);
+                   struct knote *marker);
 static int     kqueue_read(struct file *fp, struct uio *uio,
                    struct ucred *cred, int flags);
 static int     kqueue_write(struct file *fp, struct uio *uio,
@@ -72,7 +79,6 @@ static int    kqueue_kqfilter(struct file *fp, struct knote *kn);
 static int     kqueue_stat(struct file *fp, struct stat *st,
                    struct ucred *cred);
 static int     kqueue_close(struct file *fp);
-static void    kqueue_wakeup(struct kqueue *kq);
 
 /*
  * MPSAFE
@@ -145,6 +151,7 @@ static struct filterops *sysfilt_ops[] = {
        &proc_filtops,                  /* EVFILT_PROC */
        &sig_filtops,                   /* EVFILT_SIGNAL */
        &timer_filtops,                 /* EVFILT_TIMER */
+       &file_filtops,                  /* EVFILT_EXCEPT */
 };
 
 static int
@@ -468,33 +475,44 @@ sys_kqueue(struct kqueue_args *uap)
  * Copy 'count' items into the destination list pointed to by uap->eventlist.
  */
 static int
-kevent_copyout(void *arg, struct kevent *kevp, int count)
+kevent_copyout(void *arg, struct kevent *kevp, int count, int *res)
 {
-       struct kevent_args *uap;
+       struct kevent_copyin_args *kap;
        int error;
 
-       uap = (struct kevent_args *)arg;
+       kap = (struct kevent_copyin_args *)arg;
+
+       error = copyout(kevp, kap->ka->eventlist, count * sizeof(*kevp));
+       if (error == 0) {
+               kap->ka->eventlist += count;
+               *res += count;
+       } else {
+               *res = -1;
+       }
 
-       error = copyout(kevp, uap->eventlist, count * sizeof *kevp);
-       if (error == 0)
-               uap->eventlist += count;
        return (error);
 }
 
 /*
- * Copy 'count' items from the list pointed to by uap->changelist.
+ * Copy at most 'max' items from the list pointed to by kap->changelist,
+ * return number of items in 'events'.
  */
 static int
-kevent_copyin(void *arg, struct kevent *kevp, int count)
+kevent_copyin(void *arg, struct kevent *kevp, int max, int *events)
 {
-       struct kevent_args *uap;
-       int error;
+       struct kevent_copyin_args *kap;
+       int error, count;
+
+       kap = (struct kevent_copyin_args *)arg;
 
-       uap = (struct kevent_args *)arg;
+       count = min(kap->ka->nchanges - kap->pchanges, max);
+       error = copyin(kap->ka->changelist, kevp, count * sizeof *kevp);
+       if (error == 0) {
+               kap->ka->changelist += count;
+               kap->pchanges += count;
+               *events = count;
+       }
 
-       error = copyin(uap->changelist, kevp, count * sizeof *kevp);
-       if (error == 0)
-               uap->changelist += count;
        return (error);
 }
 
@@ -502,39 +520,27 @@ kevent_copyin(void *arg, struct kevent *kevp, int count)
  * MPALMOSTSAFE
  */
 int
-kern_kevent(int fd, int nchanges, int nevents, struct kevent_args *uap,
-    k_copyin_fn kevent_copyinfn, k_copyout_fn kevent_copyoutfn,
-    struct timespec *tsp_in)
+kern_kevent(struct kqueue *kq, int nevents, int *res, void *uap,
+           k_copyin_fn kevent_copyinfn, k_copyout_fn kevent_copyoutfn,
+           struct timespec *tsp_in)
 {
-       struct thread *td = curthread;
-       struct proc *p = td->td_proc;
        struct kevent *kevp;
-       struct kqueue *kq;
-       struct file *fp = NULL;
-       struct timespec ts;
        struct timespec *tsp;
-       int i, n, total, nerrors, error;
+       int i, n, total, error, nerrors = 0;
        struct kevent kev[KQ_NEVENTS];
+       struct knote marker;
 
        tsp = tsp_in;
-
-       fp = holdfp(p->p_fd, fd, -1);
-       if (fp == NULL)
-               return (EBADF);
-       if (fp->f_type != DTYPE_KQUEUE) {
-               fdrop(fp);
-               return (EBADF);
-       }
-
-       kq = (struct kqueue *)fp->f_data;
-       nerrors = 0;
+       *res = 0;
 
        get_mplock();
-       while (nchanges > 0) {
-               n = nchanges > KQ_NEVENTS ? KQ_NEVENTS : nchanges;
-               error = kevent_copyinfn(uap, kev, n);
+       for ( ;; ) {
+               n = 0;
+               error = kevent_copyinfn(uap, kev, KQ_NEVENTS, &n);
                if (error)
                        goto done;
+               if (n == 0)
+                       break;
                for (i = 0; i < n; i++) {
                        kevp = &kev[i];
                        kevp->flags &= ~EV_SYSFLAGS;
@@ -543,7 +549,7 @@ kern_kevent(int fd, int nchanges, int nevents, struct kevent_args *uap,
                                if (nevents != 0) {
                                        kevp->flags = EV_ERROR;
                                        kevp->data = error;
-                                       kevent_copyoutfn(uap, kevp, 1);
+                                       kevent_copyoutfn(uap, kevp, 1, res);
                                        nevents--;
                                        nerrors++;
                                } else {
@@ -551,10 +557,8 @@ kern_kevent(int fd, int nchanges, int nevents, struct kevent_args *uap,
                                }
                        }
                }
-               nchanges -= n;
        }
        if (nerrors) {
-               uap->sysmsg_result = nerrors;
                error = 0;
                goto done;
        }
@@ -574,30 +578,71 @@ kern_kevent(int fd, int nchanges, int nevents, struct kevent_args *uap,
        /*
         * Loop as required.
         *
-        * Collect as many events as we can.  The timeout on successive
-        * loops is disabled (kqueue_scan() becomes non-blocking).
+        * Collect as many events as we can. Sleeping on successive
+        * loops is disabled if copyoutfn has incremented (*res).
+        *
+        * The loop stops if an error occurs, all events have been
+        * scanned (the marker has been reached), or fewer than the
+        * maximum number of events is found.
+        *
+        * The copyoutfn function does not have to increment (*res) in
+        * order for the loop to continue.
+        *
+        * NOTE: doselect() usually passes 0x7FFFFFFF for nevents.
         */
        total = 0;
        error = 0;
+       marker.kn_filter = EVFILT_MARKER;
+       crit_enter();
+       TAILQ_INSERT_TAIL(&kq->kq_knpend, &marker, kn_tqe);
+       crit_exit();
        while ((n = nevents - total) > 0) {
                if (n > KQ_NEVENTS)
                        n = KQ_NEVENTS;
-               i = kqueue_scan(kq, kev, n, tsp, &error);
-               if (i == 0)
-                       break;
-               error = kevent_copyoutfn(uap, kev, i);
-               total += i;
-               if (error || i != n)
+
+               if (kq->kq_count == 0 && *res == 0) {
+                       error = kqueue_sleep(kq, tsp);
+
+                       if (error)
+                               break;
+
+                       /*
+                        * Move the marker to the end of the list
+                        * after a sleep.
+                        */
+                       crit_enter();
+                       TAILQ_REMOVE(&kq->kq_knpend, &marker, kn_tqe);
+                       TAILQ_INSERT_TAIL(&kq->kq_knpend, &marker, kn_tqe);
+                       crit_exit();
+               }
+
+               i = kqueue_scan(kq, kev, n, &marker);
+               if (i) {
+                       error = kevent_copyoutfn(uap, kev, i, res);
+                       total += i;
+                       if (error)
+                               break;
+               }
+
+               /*
+                * Normally when fewer events are returned than requested
+                * we can stop.  However, if only spurious events were
+                * collected the copyout will not bump (*res) and we have
+                * to continue.
+                */
+               if (i < n && *res)
                        break;
-               tsp = &ts;              /* successive loops non-blocking */
-               tsp->tv_sec = 0;
-               tsp->tv_nsec = 0;
        }
-       uap->sysmsg_result = total;
+       crit_enter();
+       TAILQ_REMOVE(&kq->kq_knpend, &marker, kn_tqe);
+       crit_exit();
+
+       /* Timeouts do not return EWOULDBLOCK. */
+       if (error == EWOULDBLOCK)
+               error = 0;
+
 done:
        rel_mplock();
-       if (fp != NULL)
-               fdrop(fp);
        return (error);
 }
 
@@ -607,7 +652,12 @@ done:
 int
 sys_kevent(struct kevent_args *uap)
 {
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
        struct timespec ts, *tsp;
+       struct kqueue *kq;
+       struct file *fp = NULL;
+       struct kevent_copyin_args *kap, ka;
        int error;
 
        if (uap->timeout) {
@@ -619,8 +669,24 @@ sys_kevent(struct kevent_args *uap)
                tsp = NULL;
        }
 
-       error = kern_kevent(uap->fd, uap->nchanges, uap->nevents,
-           uap, kevent_copyin, kevent_copyout, tsp);
+       fp = holdfp(p->p_fd, uap->fd, -1);
+       if (fp == NULL)
+               return (EBADF);
+       if (fp->f_type != DTYPE_KQUEUE) {
+               fdrop(fp);
+               return (EBADF);
+       }
+
+       kq = (struct kqueue *)fp->f_data;
+
+       kap = &ka;
+       kap->ka = uap;
+       kap->pchanges = 0;
+
+       error = kern_kevent(kq, uap->nevents, &uap->sysmsg_result, kap,
+                           kevent_copyin, kevent_copyout, tsp);
+
+       fdrop(fp);
 
        return (error);
 }
@@ -755,63 +821,82 @@ done:
 }
 
 /*
- * Scan the kqueue, blocking if necessary until the target time is reached.
+ * Block as necessary until the target time is reached.
  * If tsp is NULL we block indefinitely.  If tsp->ts_secs/nsecs are both
  * 0 we do not block at all.
  */
 static int
-kqueue_scan(struct kqueue *kq, struct kevent *kevp, int count,
-           struct timespec *tsp, int *errorp)
+kqueue_sleep(struct kqueue *kq, struct timespec *tsp)
 {
-       struct knote *kn, marker;
-       int total;
+       int error = 0;
 
-       total = 0;
-again:
        crit_enter();
-       if (kq->kq_count == 0) {
-               if (tsp == NULL) {
-                       kq->kq_state |= KQ_SLEEP;
-                       *errorp = tsleep(kq, PCATCH, "kqread", 0);
-               } else if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) {
-                       *errorp = EWOULDBLOCK;
-               } else {
-                       struct timespec ats;
-                       struct timespec atx = *tsp;
-                       int timeout;
+       if (tsp == NULL) {
+               kq->kq_state |= KQ_SLEEP;
+               error = tsleep(kq, PCATCH, "kqread", 0);
+       } else if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) {
+               error = EWOULDBLOCK;
+       } else {
+               struct timespec ats;
+               struct timespec atx = *tsp;
+               int timeout;
 
-                       nanouptime(&ats);
-                       timespecsub(&atx, &ats);
-                       if (ats.tv_sec < 0) {
-                               *errorp = EWOULDBLOCK;
-                       } else {
-                               timeout = atx.tv_sec > 24 * 60 * 60 ?
-                                       24 * 60 * 60 * hz : tstohz_high(&atx);
-                               kq->kq_state |= KQ_SLEEP;
-                               *errorp = tsleep(kq, PCATCH, "kqread", timeout);
-                       }
+               nanouptime(&ats);
+               timespecsub(&atx, &ats);
+               if (ats.tv_sec < 0) {
+                       error = EWOULDBLOCK;
+               } else {
+                       timeout = atx.tv_sec > 24 * 60 * 60 ?
+                               24 * 60 * 60 * hz : tstohz_high(&atx);
+                       kq->kq_state |= KQ_SLEEP;
+                       error = tsleep(kq, PCATCH, "kqread", timeout);
                }
-               crit_exit();
-               if (*errorp == 0)
-                       goto again;
-               /* don't restart after signals... */
-               if (*errorp == ERESTART)
-                       *errorp = EINTR;
-               else if (*errorp == EWOULDBLOCK)
-                       *errorp = 0;
-               goto done;
        }
+       crit_exit();
+
+       /* don't restart after signals... */
+       if (error == ERESTART)
+               return (EINTR);
+
+       return (error);
+}
+
+/*
+ * Scan the kqueue, return the number of active events placed in kevp up
+ * to count.
+ *
+ * Continuous mode events may get recycled, do not continue scanning past
+ * marker unless no events have been collected.
+ */
+static int
+kqueue_scan(struct kqueue *kq, struct kevent *kevp, int count,
+            struct knote *marker)
+{
+        struct knote *kn, local_marker;
+        int total;
+
+        total = 0;
+       local_marker.kn_filter = EVFILT_MARKER;
+        crit_enter();
 
        /*
-        * Collect events.  Continuous mode events may get recycled
-        * past the marker so we stop when we hit it unless no events
-        * have been collected.
+        * Collect events.
         */
-       TAILQ_INSERT_TAIL(&kq->kq_knpend, &marker, kn_tqe);
+       TAILQ_INSERT_HEAD(&kq->kq_knpend, &local_marker, kn_tqe);
        while (count) {
-               kn = TAILQ_FIRST(&kq->kq_knpend);
-               if (kn == &marker)
-                       break;
+               kn = TAILQ_NEXT(&local_marker, kn_tqe);
+               if (kn->kn_filter == EVFILT_MARKER) {
+                       /* Marker reached, we are done */
+                       if (kn == marker)
+                               break;
+
+                       /* Move local marker past some other threads marker */
+                       kn = TAILQ_NEXT(kn, kn_tqe);
+                       TAILQ_REMOVE(&kq->kq_knpend, &local_marker, kn_tqe);
+                       TAILQ_INSERT_BEFORE(kn, &local_marker, kn_tqe);
+                       continue;
+               }
+
                TAILQ_REMOVE(&kq->kq_knpend, kn, kn_tqe);
                if (kn->kn_status & KN_DISABLED) {
                        kn->kn_status &= ~KN_QUEUED;
@@ -847,11 +932,9 @@ again:
                        TAILQ_INSERT_TAIL(&kq->kq_knpend, kn, kn_tqe);
                }
        }
-       TAILQ_REMOVE(&kq->kq_knpend, &marker, kn_tqe);
+       TAILQ_REMOVE(&kq->kq_knpend, &local_marker, kn_tqe);
+
        crit_exit();
-       if (total == 0)
-               goto again;
-done:
        return (total);
 }
 
@@ -967,7 +1050,7 @@ kqueue_close(struct file *fp)
        return (0);
 }
 
-static void
+void
 kqueue_wakeup(struct kqueue *kq)
 {
        if (kq->kq_state & KQ_SLEEP) {
index 47e12fc..f50a7a7 100644 (file)
@@ -75,16 +75,18 @@ static      d_write_t       mmwrite;
 static d_ioctl_t       mmioctl;
 static d_mmap_t        memmmap;
 static d_poll_t        mmpoll;
+static d_kqfilter_t    mmkqfilter;
 
 #define CDEV_MAJOR 2
 static struct dev_ops mem_ops = {
-       { "mem", CDEV_MAJOR, D_MEM | D_MPSAFE_READ | D_MPSAFE_WRITE },
+       { "mem", CDEV_MAJOR, D_MEM | D_MPSAFE_READ | D_MPSAFE_WRITE | D_KQFILTER },
        .d_open =       mmopen,
        .d_close =      mmclose,
        .d_read =       mmread,
        .d_write =      mmwrite,
        .d_ioctl =      mmioctl,
        .d_poll =       mmpoll,
+       .d_kqfilter =   mmkqfilter,
        .d_mmap =       memmmap,
 };
 
@@ -546,6 +548,47 @@ mmpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static int
+mm_filter_read(struct knote *kn, long hint)
+{
+       return (1);
+}
+
+static void
+dummy_filter_detach(struct knote *kn) {}
+
+static struct filterops random_read_filtops =
+        { 1, NULL, dummy_filter_detach, random_filter_read };
+
+static struct filterops mm_read_filtops =
+        { 1, NULL, dummy_filter_detach, mm_filter_read };
+
+int
+mmkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       cdev_t dev = ap->a_head.a_dev;
+
+       ap->a_result = 0;
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               switch (minor(dev)) {
+               case 3:
+                       kn->kn_fop = &random_read_filtops;
+                       break;
+               default:
+                       kn->kn_fop = &mm_read_filtops;
+                       break;
+               }
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       return (0);
+}
+
 int
 iszerodev(cdev_t dev)
 {
index 60205a4..5ad67d6 100644 (file)
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/random.h>
 #include <sys/systimer.h>
 #include <sys/time.h>
@@ -521,6 +522,15 @@ random_poll(cdev_t dev, int events)
        return (revents);
 }
 
+/*
+ * Kqueue filter (always succeeds)
+ */
+int
+random_filter_read(struct knote *kn, long hint)
+{
+       return (1);
+}
+
 /*
  * Heavy weight random number generator.  May return less then the
  * requested number of bytes.
index 6f1cca7..661be89 100644 (file)
@@ -38,6 +38,7 @@
 #include <sys/buf.h>
 #include <sys/conf.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/ioccom.h>
 #include <sys/malloc.h>
 #include <sys/ctype.h>
@@ -46,6 +47,8 @@
 #include <sys/devfs.h>
 #include <libprop/proplib.h>
 
+#include <sys/thread2.h>
+
 MALLOC_DEFINE(M_UDEV, "udev", "udev allocs");
 
 /* XXX: use UUIDs for identification; would need help from devfs */
@@ -55,6 +58,7 @@ static d_open_t               udev_dev_open;
 static d_close_t       udev_dev_close;
 static d_read_t                udev_dev_read;
 static d_poll_t                udev_dev_poll;
+static d_kqfilter_t    udev_dev_kqfilter;
 static d_ioctl_t       udev_dev_ioctl;
 
 static int _udev_dict_set_cstr(prop_dictionary_t, const char *, char *);
@@ -70,6 +74,8 @@ static void udev_event_free(struct udev_event_kernel *);
 static char *udev_event_externalize(struct udev_event_kernel *);
 static void udev_getdevs_scan_callback(cdev_t, void *);
 static int udev_getdevs_ioctl(struct plistref *, u_long, prop_dictionary_t);
+static void udev_dev_filter_detach(struct knote *);
+static int udev_dev_filter_read(struct knote *, long);
 
 struct cmd_function {
        const char *cmd;
@@ -98,11 +104,12 @@ struct udev_softc {
 } udevctx;
 
 static struct dev_ops udev_dev_ops = {
-       { "udev", 0, 0 },
+       { "udev", 0, D_KQFILTER },
        .d_open = udev_dev_open,
        .d_close = udev_dev_close,
        .d_read = udev_dev_read,
        .d_poll = udev_dev_poll,
+       .d_kqfilter = udev_dev_kqfilter,
        .d_ioctl = udev_dev_ioctl
 };
 
@@ -550,6 +557,64 @@ udev_dev_poll(struct dev_poll_args *ap)
         return 0;
 }
 
+static struct filterops udev_dev_read_filtops =
+       { 1, NULL, udev_dev_filter_detach, udev_dev_filter_read };
+
+static int
+udev_dev_kqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+       lockmgr(&udevctx.lock, LK_EXCLUSIVE);
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &udev_dev_read_filtops;
+               break;
+       default:
+               ap->a_result = 1;
+               lockmgr(&udevctx.lock, LK_RELEASE);
+               return (0);
+       }
+
+       crit_enter();
+       klist = &udevctx.sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+        lockmgr(&udevctx.lock, LK_RELEASE);
+
+       return (0);
+}
+
+static void
+udev_dev_filter_detach(struct knote *kn)
+{
+       struct klist *klist;
+
+       lockmgr(&udevctx.lock, LK_EXCLUSIVE);
+       crit_enter();
+       klist = &udevctx.sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+       lockmgr(&udevctx.lock, LK_RELEASE);
+}
+
+static int
+udev_dev_filter_read(struct knote *kn, long hint)
+{
+       int ready = 0;
+
+       lockmgr(&udevctx.lock, LK_EXCLUSIVE);
+       if (!TAILQ_EMPTY(&udevctx.ev_queue))
+               ready = 1;
+       lockmgr(&udevctx.lock, LK_RELEASE);
+
+       return (ready);
+}
+
 static int
 udev_dev_read(struct dev_read_args *ap)
 {
index 4c21db9..9776f8f 100644 (file)
@@ -47,6 +47,7 @@
 #include <sys/uio.h>
 #include <sys/filio.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/signalvar.h>
 
 #include <machine/stdarg.h>    /* for device_printf() */
@@ -143,6 +144,7 @@ static d_close_t    devclose;
 static d_read_t                devread;
 static d_ioctl_t       devioctl;
 static d_poll_t                devpoll;
+static d_kqfilter_t    devkqfilter;
 
 static struct dev_ops devctl_ops = {
        { "devctl", CDEV_MAJOR, 0 },
@@ -151,6 +153,7 @@ static struct dev_ops devctl_ops = {
        .d_read =       devread,
        .d_ioctl =      devioctl,
        .d_poll =       devpoll,
+       .d_kqfilter =   devkqfilter
 };
 
 struct dev_event_info
@@ -292,6 +295,68 @@ devpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static void dev_filter_detach(struct knote *);
+static int dev_filter_read(struct knote *, long);
+
+static struct filterops dev_filtops =
+       { 1, NULL, dev_filter_detach, dev_filter_read };
+
+static int
+devkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+       lockmgr(&devsoftc.lock, LK_EXCLUSIVE);
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &dev_filtops;
+               break;
+       default:
+               ap->a_result = 1;
+               lockmgr(&devsoftc.lock, LK_RELEASE);
+               return (0);
+       }
+
+       crit_enter();
+       klist = &devsoftc.sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       lockmgr(&devsoftc.lock, LK_RELEASE);
+
+       return (0);
+}
+
+static void
+dev_filter_detach(struct knote *kn)
+{
+       struct klist *klist;
+
+       lockmgr(&devsoftc.lock, LK_EXCLUSIVE);
+       crit_enter();
+       klist = &devsoftc.sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+       lockmgr(&devsoftc.lock, LK_RELEASE);
+}
+
+static int
+dev_filter_read(struct knote *kn, long hint)
+{
+       int ready = 0;
+
+       lockmgr(&devsoftc.lock, LK_EXCLUSIVE);
+       if (!TAILQ_EMPTY(&devsoftc.devq))
+               ready = 1;
+       lockmgr(&devsoftc.lock, LK_RELEASE);
+
+       return (ready);
+}
+
+
 /**
  * @brief Return whether the userland process is running
  */
index e6b4fa5..d5ab5b5 100644 (file)
@@ -51,6 +51,7 @@
 #include <sys/signalvar.h>
 #include <sys/kernel.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/filedesc.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
@@ -63,17 +64,21 @@ static      d_close_t       logclose;
 static d_read_t        logread;
 static d_ioctl_t       logioctl;
 static d_poll_t        logpoll;
+static d_kqfilter_t    logkqfilter;
 
 static void logtimeout(void *arg);
+static void logfiltdetach(struct knote *kn);
+static int  logfiltread(struct knote *kn, long hint);
 
 #define CDEV_MAJOR 7
 static struct dev_ops log_ops = {
-       { "log", CDEV_MAJOR, 0 },
+       { "log", CDEV_MAJOR, D_KQFILTER },
        .d_open =       logopen,
        .d_close =      logclose,
        .d_read =       logread,
        .d_ioctl =      logioctl,
        .d_poll =       logpoll,
+       .d_kqfilter =   logkqfilter
 };
 
 static struct logsoftc {
@@ -178,6 +183,55 @@ logpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops logread_filtops =
+       { 1, NULL, logfiltdetach, logfiltread };
+
+static int
+logkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+       struct klist *klist = &logsoftc.sc_selp.si_note;
+
+       ap->a_result = 0;
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &logread_filtops;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+logfiltdetach(struct knote *kn)
+{
+       struct klist *klist = &logsoftc.sc_selp.si_note;
+
+       crit_enter();
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+logfiltread(struct knote *kn, long hint)
+{
+       int ret = 0;
+
+       crit_enter();
+       if (msgbufp->msg_bufr != msgbufp->msg_bufx)
+               ret = 1;
+       crit_exit();
+
+       return (ret);
+}
+
 static void
 logtimeout(void *arg)
 {
index 5403dec..a05f24f 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sysproto.h>
+#include <sys/event.h>
 #include <sys/filedesc.h>
 #include <sys/filio.h>
 #include <sys/fcntl.h>
@@ -79,11 +80,36 @@ static MALLOC_DEFINE(M_IOCTLMAP, "ioctlmap", "mapped ioctl handler buffer");
 static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
 MALLOC_DEFINE(M_IOV, "iov", "large iov's");
 
+typedef struct kfd_set {
+        fd_mask        fds_bits[2];
+} kfd_set;
+
+enum select_copyin_states {
+    COPYIN_READ, COPYIN_WRITE, COPYIN_EXCEPT, COPYIN_DONE };
+
+struct select_kevent_copyin_args {
+       kfd_set         *read_set;
+       kfd_set         *write_set;
+       kfd_set         *except_set;
+       int             active_set;     /* One of select_copyin_states */
+       struct lwp      *lwp;           /* Pointer to our lwp */
+       int             num_fds;        /* Number of file descriptors (syscall arg) */
+       int             proc_fds;       /* Processed fd's (wraps) */
+       int             error;          /* Returned to userland */
+};
+
+struct poll_kevent_copyin_args {
+       struct lwp      *lwp;
+       struct pollfd   *fds;
+       int             nfds;
+       int             pfds;
+       int             error;
+};
+
 static int     doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex,
-                       struct timeval *tv, int *res);
-static int     pollscan (struct proc *, struct pollfd *, u_int, int *);
-static int     selscan (struct proc *, fd_mask **, fd_mask **,
-                       int, int *);
+                        struct timespec *ts, int *res);
+static int     dopoll(int nfds, struct pollfd *fds, struct timespec *ts,
+                      int *res);
 static int     dofileread(int, struct file *, struct uio *, int, size_t *);
 static int     dofilewrite(int, struct file *, struct uio *, int, size_t *);
 
@@ -760,13 +786,13 @@ SYSCTL_INT(_kern, OID_AUTO, nselcoll, CTLFLAG_RD, &nselcoll, 0, "");
 /*
  * Select system call.
  *
- * MPALMOSTSAFE
+ * MPSAFE
  */
 int
 sys_select(struct select_args *uap)
 {
        struct timeval ktv;
-       struct timeval *ktvp;
+       struct timespec *ktsp, kts;
        int error;
 
        /*
@@ -776,21 +802,17 @@ sys_select(struct select_args *uap)
                error = copyin(uap->tv, &ktv, sizeof (ktv));
                if (error)
                        return (error);
-               error = itimerfix(&ktv);
-               if (error)
-                       return (error);
-               ktvp = &ktv;
+               TIMEVAL_TO_TIMESPEC(&ktv, &kts);
+               ktsp = &kts;
        } else {
-               ktvp = NULL;
+               ktsp = NULL;
        }
 
        /*
         * Do real work.
         */
-       get_mplock();
-       error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
-                       &uap->sysmsg_result);
-       rel_mplock();
+       error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktsp,
+                        &uap->sysmsg_result);
 
        return (error);
 }
@@ -806,28 +828,20 @@ sys_pselect(struct pselect_args *uap)
 {
        struct thread *td = curthread;
        struct lwp *lp = td->td_lwp;
-       struct timespec kts;
-       struct timeval ktv;
-       struct timeval *ktvp;
+       struct timespec *ktsp, kts;
        sigset_t sigmask;
        int error;
 
        /*
-        * Get timeout if any and convert it.
-        * Round up during conversion to avoid timeout going off early.
+        * Get timeout if any.
         */
        if (uap->ts != NULL) {
                error = copyin(uap->ts, &kts, sizeof (kts));
                if (error)
                        return (error);
-               ktv.tv_sec = kts.tv_sec;
-               ktv.tv_usec = (kts.tv_nsec + 999) / 1000;
-               error = itimerfix(&ktv);
-               if (error)
-                       return (error);
-               ktvp = &ktv;
+               ktsp = &kts;
        } else {
-               ktvp = NULL;
+               ktsp = NULL;
        }
 
        /*
@@ -848,8 +862,8 @@ sys_pselect(struct pselect_args *uap)
        /*
         * Do real job.
         */
-       error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
-                       &uap->sysmsg_result);
+       error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktsp,
+                        &uap->sysmsg_result);
 
        if (uap->sigmask != NULL) {
                /* doselect() responsible for turning ERESTART into EINTR */
@@ -874,307 +888,425 @@ sys_pselect(struct pselect_args *uap)
        return (error);
 }
 
+static int
+select_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
+{
+       struct select_kevent_copyin_args *skap = NULL;
+       struct kevent *kev;
+       int fd;
+       kfd_set *fdp = NULL;
+       short filter = 0;
+       u_int fflags = 0;
+
+       skap = (struct select_kevent_copyin_args *)arg;
+
+       if (*events == maxevents)
+               return (0);
+
+       while (skap->active_set < COPYIN_DONE) {
+               switch (skap->active_set) {
+               case COPYIN_READ:
+                       /*
+                        * Register descriptors for the read filter
+                        */
+                       fdp = skap->read_set;
+                       filter = EVFILT_READ;
+                       fflags = 0;
+                       if (fdp)
+                               break;
+                       ++skap->active_set;
+                       skap->proc_fds = 0;
+                       /* fall through */
+               case COPYIN_WRITE:
+                       /*
+                        * Register descriptors for the write filter
+                        */
+                       fdp = skap->write_set;
+                       filter = EVFILT_WRITE;
+                       fflags = 0;
+                       if (fdp)
+                               break;
+                       ++skap->active_set;
+                       skap->proc_fds = 0;
+                       /* fall through */
+               case COPYIN_EXCEPT:
+                       /*
+                        * Register descriptors for the exception filter
+                        */
+                       fdp = skap->except_set;
+                       filter = EVFILT_EXCEPT;
+                       fflags = NOTE_OOB;
+                       if (fdp)
+                               break;
+                       ++skap->active_set;
+                       skap->proc_fds = 0;
+                       /* fall through */
+               case COPYIN_DONE:
+                       /*
+                        * Nothing left to register
+                        */
+                       return(0);
+                       /* NOT REACHED */
+               }
+
+               while (skap->proc_fds < skap->num_fds) {
+                       fd = skap->proc_fds;
+                       if (FD_ISSET(fd, fdp)) {
+                               kev = &kevp[*events];
+                               EV_SET(kev, fd, filter,
+                                      EV_ADD|EV_ENABLE,
+                                      fflags, 0,
+                                      (void *)skap->lwp->lwp_kqueue_serial);
+                               FD_CLR(fd, fdp);
+                               ++*events;
+                       }
+                       ++skap->proc_fds;
+                       if (*events == maxevents)
+                               return (0);
+               }
+               skap->active_set++;
+               skap->proc_fds = 0;
+       }
+
+       return (0);
+}
+
+static int
+select_copyout(void *arg, struct kevent *kevp, int count, int *res)
+{
+       struct select_kevent_copyin_args *skap;
+       struct kevent kev;
+       int i = 0;
+
+       skap = (struct select_kevent_copyin_args *)arg;
+
+       if (kevp[0].flags & EV_ERROR) {
+               skap->error = kevp[0].data;
+               return (0);
+       }
+
+       for (i = 0; i < count; ++i) {
+               if ((u_int)kevp[i].udata != skap->lwp->lwp_kqueue_serial) {
+                       kev = kevp[i];
+                       kev.flags = EV_DISABLE|EV_DELETE;
+                       kqueue_register(&skap->lwp->lwp_kqueue, &kev);
+                       continue;
+               }
+
+               switch (kevp[i].filter) {
+               case EVFILT_READ:
+                       FD_SET(kevp[i].ident, skap->read_set);
+                       break;
+               case EVFILT_WRITE:
+                       FD_SET(kevp[i].ident, skap->write_set);
+                       break;
+               case EVFILT_EXCEPT:
+                       FD_SET(kevp[i].ident, skap->except_set);
+                       break;
+               }
+
+               ++*res;
+       }
+
+       return (0);
+}
+
+/*
+ * Copy select bits in from userland.  Allocate kernel memory if the
+ * set is large.
+ */
+static int
+getbits(int bytes, fd_set *in_set, kfd_set **out_set, kfd_set *tmp_set)
+{
+       int error;
+
+       if (in_set) {
+               if (bytes < sizeof(*tmp_set))
+                       *out_set = tmp_set;
+               else
+                       *out_set = kmalloc(bytes, M_SELECT, M_WAITOK);
+               error = copyin(in_set, *out_set, bytes);
+       } else {
+               *out_set = NULL;
+               error = 0;
+       }
+       return (error);
+}
+
+/*
+ * Copy returned select bits back out to userland.
+ */
+static int
+putbits(int bytes, kfd_set *in_set, fd_set *out_set)
+{
+       int error;
+
+       if (in_set) {
+               error = copyout(in_set, out_set, bytes);
+       } else {
+               error = 0;
+       }
+       return (error);
+}
+
 /*
  * Common code for sys_select() and sys_pselect().
  *
- * in, out and ex are userland pointers.  tv must point to validated
+ * in, out and ex are userland pointers.  ts must point to validated
  * kernel-side timeout value or NULL for infinite timeout.  res must
  * point to syscall return value.
  */
 static int
-doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv,
-               int *res)
+doselect(int nd, fd_set *read, fd_set *write, fd_set *except,
+        struct timespec *ts, int *res)
 {
-       struct lwp *lp = curthread->td_lwp;
        struct proc *p = curproc;
+       struct select_kevent_copyin_args *kap, ka;
+       int bytes, error;
+       kfd_set read_tmp;
+       kfd_set write_tmp;
+       kfd_set except_tmp;
+
+       *res = 0;
+       if (nd < 0)
+               return (EINVAL);
+       if (nd > p->p_fd->fd_nfiles)            /* limit kmalloc */
+               nd = p->p_fd->fd_nfiles;
+
+       kap = &ka;
+       kap->lwp = curthread->td_lwp;
+       kap->num_fds = nd;
+       kap->proc_fds = 0;
+       kap->error = 0;
+       kap->active_set = COPYIN_READ;
 
        /*
-        * The magic 2048 here is chosen to be just enough for FD_SETSIZE
-        * infds with the new FD_SETSIZE of 1024, and more than enough for
-        * FD_SETSIZE infds, outfds and exceptfds with the old FD_SETSIZE
-        * of 256.
+        * Calculate bytes based on the number of __fd_mask[] array entries
+        * multiplied by the size of __fd_mask.
         */
-       fd_mask s_selbits[howmany(2048, NFDBITS)];
-       fd_mask *ibits[3], *obits[3], *selbits, *sbp;
-       struct timeval atv, rtv, ttv;
-       int ncoll, error, timo;
-       u_int nbufbytes, ncpbytes, nfdbits;
+       bytes = howmany(nd, __NFDBITS) * sizeof(__fd_mask);
 
-       if (nd < 0)
-               return (EINVAL);
-       if (nd > p->p_fd->fd_nfiles)
-               nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
+       error = getbits(bytes, read, &kap->read_set, &read_tmp);
+       if (error == 0)
+               error = getbits(bytes, write, &kap->write_set, &write_tmp);
+       if (error == 0)
+               error = getbits(bytes, except, &kap->except_set, &except_tmp);
+       if (error)
+               goto done;
 
        /*
-        * Allocate just enough bits for the non-null fd_sets.  Use the
-        * preallocated auto buffer if possible.
+        * NOTE: Make sure the max events passed to kern_kevent() is
+        *       effectively unlimited.  (nd * 3) accomplishes this.
+        *
+        *       (*res) continues to increment as returned events are
+        *       loaded in.
         */
-       nfdbits = roundup(nd, NFDBITS);
-       ncpbytes = nfdbits / NBBY;
-       nbufbytes = 0;
-       if (in != NULL)
-               nbufbytes += 2 * ncpbytes;
-       if (ou != NULL)
-               nbufbytes += 2 * ncpbytes;
-       if (ex != NULL)
-               nbufbytes += 2 * ncpbytes;
-       if (nbufbytes <= sizeof s_selbits)
-               selbits = &s_selbits[0];
-       else
-               selbits = kmalloc(nbufbytes, M_SELECT, M_WAITOK);
+       error = kern_kevent(&kap->lwp->lwp_kqueue, 0x7FFFFFFF, res, kap,
+                           select_copyin, select_copyout, ts);
+       if (error == 0)
+               error = putbits(bytes, kap->read_set, read);
+       if (error == 0)
+               error = putbits(bytes, kap->write_set, write);
+       if (error == 0)
+               error = putbits(bytes, kap->except_set, except);
 
        /*
-        * Assign pointers into the bit buffers and fetch the input bits.
-        * Put the output buffers together so that they can be bzeroed
-        * together.
+        * Cumulative error from individual events (EBADFD?)
         */
-       sbp = selbits;
-#define        getbits(name, x) \
-       do {                                                            \
-               if (name == NULL)                                       \
-                       ibits[x] = NULL;                                \
-               else {                                                  \
-                       ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp;   \
-                       obits[x] = sbp;                                 \
-                       sbp += ncpbytes / sizeof *sbp;                  \
-                       error = copyin(name, ibits[x], ncpbytes);       \
-                       if (error != 0)                                 \
-                               goto done;                              \
-               }                                                       \
-       } while (0)
-       getbits(in, 0);
-       getbits(ou, 1);
-       getbits(ex, 2);
-#undef getbits
-       if (nbufbytes != 0)
-               bzero(selbits, nbufbytes / 2);
-
-       if (tv != NULL) {
-               atv = *tv;
-               getmicrouptime(&rtv);
-               timevaladd(&atv, &rtv);
-       } else {
-               atv.tv_sec = 0;
-               atv.tv_usec = 0;
-       }
-       timo = 0;
-retry:
-       ncoll = nselcoll;
-       lp->lwp_flag |= LWP_SELECT;
-       error = selscan(p, ibits, obits, nd, res);
-       if (error || *res)
-               goto done;
-       if (atv.tv_sec || atv.tv_usec) {
-               getmicrouptime(&rtv);
-               if (timevalcmp(&rtv, &atv, >=))
-                       goto done;
-               ttv = atv;
-               timevalsub(&ttv, &rtv);
-               timo = ttv.tv_sec > 24 * 60 * 60 ?
-                   24 * 60 * 60 * hz : tvtohz_high(&ttv);
-       }
-       crit_enter();
-       tsleep_interlock(&selwait, PCATCH);
-       if ((lp->lwp_flag & LWP_SELECT) == 0 || nselcoll != ncoll) {
-               crit_exit();
-               goto retry;
-       }
-       lp->lwp_flag &= ~LWP_SELECT;
-       error = tsleep(&selwait, PCATCH | PINTERLOCKED, "select", timo);
-       crit_exit();
+       if (kap->error)
+               error = kap->error;
 
-       if (error == 0)
-               goto retry;
+       /*
+        * Clean up.
+        */
 done:
-       lp->lwp_flag &= ~LWP_SELECT;
-       /* select is not restarted after signals... */
-       if (error == ERESTART)
-               error = EINTR;
-       if (error == EWOULDBLOCK)
-               error = 0;
-#define        putbits(name, x) \
-       if (name && (error2 = copyout(obits[x], name, ncpbytes))) \
-               error = error2;
-       if (error == 0) {
-               int error2;
-
-               putbits(in, 0);
-               putbits(ou, 1);
-               putbits(ex, 2);
-#undef putbits
-       }
-       if (selbits != &s_selbits[0])
-               kfree(selbits, M_SELECT);
-       return (error);
-}
+       if (kap->read_set && kap->read_set != &read_tmp)
+               kfree(kap->read_set, M_SELECT);
+       if (kap->write_set && kap->write_set != &write_tmp)
+               kfree(kap->write_set, M_SELECT);
+       if (kap->except_set && kap->except_set != &except_tmp)
+               kfree(kap->except_set, M_SELECT);
 
-static int
-selscan(struct proc *p, fd_mask **ibits, fd_mask **obits, int nfd, int *res)
-{
-       int msk, i, fd;
-       fd_mask bits;
-       struct file *fp;
-       int n = 0;
-       /* Note: backend also returns POLLHUP/POLLERR if appropriate. */
-       static int flag[3] = { POLLRDNORM, POLLWRNORM, POLLRDBAND };
+       kap->lwp->lwp_kqueue_serial++;
 
-       for (msk = 0; msk < 3; msk++) {
-               if (ibits[msk] == NULL)
-                       continue;
-               for (i = 0; i < nfd; i += NFDBITS) {
-                       bits = ibits[msk][i/NFDBITS];
-                       /* ffs(int mask) not portable, fd_mask is long */
-                       for (fd = i; bits && fd < nfd; fd++, bits >>= 1) {
-                               if (!(bits & 1))
-                                       continue;
-                               fp = holdfp(p->p_fd, fd, -1);
-                               if (fp == NULL)
-                                       return (EBADF);
-                               if (fo_poll(fp, flag[msk], fp->f_cred)) {
-                                       obits[msk][(fd)/NFDBITS] |=
-                                           ((fd_mask)1 << ((fd) % NFDBITS));
-                                       n++;
-                               }
-                               fdrop(fp);
-                       }
-               }
-       }
-       *res = n;
-       return (0);
+       return (error);
 }
 
 /*
  * Poll system call.
  *
- * MPALMOSTSAFE
+ * MPSAFE
  */
 int
 sys_poll(struct poll_args *uap)
 {
-       struct pollfd *bits;
-       struct pollfd smallbits[32];
-       struct timeval atv, rtv, ttv;
-       int ncoll, error = 0, timo;
-       u_int nfds;
-       size_t ni;
-       struct lwp *lp = curthread->td_lwp;
-       struct proc *p = curproc;
+       struct timespec ts, *tsp;
+       int error;
 
-       nfds = uap->nfds;
-       /*
-        * This is kinda bogus.  We have fd limits, but that is not
-        * really related to the size of the pollfd array.  Make sure
-        * we let the process use at least FD_SETSIZE entries and at
-        * least enough for the current limits.  We want to be reasonably
-        * safe, but not overly restrictive.
-        */
-       if (nfds > p->p_rlimit[RLIMIT_NOFILE].rlim_cur && nfds > FD_SETSIZE)
-               return (EINVAL);
-       ni = nfds * sizeof(struct pollfd);
-       if (ni > sizeof(smallbits))
-               bits = kmalloc(ni, M_TEMP, M_WAITOK);
-       else
-               bits = smallbits;
-       error = copyin(uap->fds, bits, ni);
-       if (error)
-               goto done2;
        if (uap->timeout != INFTIM) {
-               atv.tv_sec = uap->timeout / 1000;
-               atv.tv_usec = (uap->timeout % 1000) * 1000;
-               if (itimerfix(&atv)) {
-                       error = EINVAL;
-                       goto done2;
-               }
-               getmicrouptime(&rtv);
-               timevaladd(&atv, &rtv);
+               ts.tv_sec = uap->timeout / 1000;
+               ts.tv_nsec = (uap->timeout % 1000) * 1000 * 1000;
+               tsp = &ts;
        } else {
-               atv.tv_sec = 0;
-               atv.tv_usec = 0;
-       }
-       timo = 0;
-       get_mplock();
-retry:
-       ncoll = nselcoll;
-       lp->lwp_flag |= LWP_SELECT;
-       error = pollscan(p, bits, nfds, &uap->sysmsg_result);
-       if (error || uap->sysmsg_result)
-               goto done1;
-       if (atv.tv_sec || atv.tv_usec) {
-               getmicrouptime(&rtv);
-               if (timevalcmp(&rtv, &atv, >=))
-                       goto done1;
-               ttv = atv;
-               timevalsub(&ttv, &rtv);
-               timo = ttv.tv_sec > 24 * 60 * 60 ?
-                   24 * 60 * 60 * hz : tvtohz_high(&ttv);
-       } 
-       crit_enter();
-       tsleep_interlock(&selwait, PCATCH);
-       if ((lp->lwp_flag & LWP_SELECT) == 0 || nselcoll != ncoll) {
-               crit_exit();
-               goto retry;
+               tsp = NULL;
        }
-       lp->lwp_flag &= ~LWP_SELECT;
-       error = tsleep(&selwait, PCATCH | PINTERLOCKED, "poll", timo);
-       crit_exit();
 
-       if (error == 0)
-               goto retry;
-done1:
-       rel_mplock();
-done2:
-       lp->lwp_flag &= ~LWP_SELECT;
-       /* poll is not restarted after signals... */
-       if (error == ERESTART)
-               error = EINTR;
-       if (error == EWOULDBLOCK)
-               error = 0;
-       if (error == 0) {
-               error = copyout(bits, uap->fds, ni);
-               if (error)
-                       goto out;
-       }
-out:
-       if (ni > sizeof(smallbits))
-               kfree(bits, M_TEMP);
+       error = dopoll(uap->nfds, uap->fds, tsp, &uap->sysmsg_result);
+
        return (error);
 }
 
 static int
-pollscan(struct proc *p, struct pollfd *fds, u_int nfd, int *res)
+poll_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
 {
+       struct poll_kevent_copyin_args *pkap;
+       struct pollfd *pfd;
+       struct kevent *kev;
+       int kev_count;
+
+       pkap = (struct poll_kevent_copyin_args *)arg;
+
+       while (pkap->pfds < pkap->nfds) {
+               pfd = &pkap->fds[pkap->pfds];
+
+               /* Clear return events */
+               pfd->revents = 0;
+
+               /* Do not check if fd is equal to -1 */
+               if (pfd->fd == -1) {
+                       ++pkap->pfds;
+                       continue;
+               }
+
+               kev_count = 0;
+               if (pfd->events & (POLLIN | POLLRDNORM))
+                       kev_count++;
+               if (pfd->events & (POLLOUT | POLLWRNORM))
+                       kev_count++;
+               if (pfd->events & (POLLPRI | POLLRDBAND))
+                       kev_count++;
+
+               if (*events + kev_count > maxevents)
+                       return (0);
+
+               kev = &kevp[*events];
+               if (pfd->events & (POLLIN | POLLRDNORM))
+                       EV_SET(kev++, pfd->fd, EVFILT_READ, EV_ADD|EV_ENABLE,
+                              0, 0, (void *)pkap->pfds);
+               if (pfd->events & (POLLOUT | POLLWRNORM))
+                       EV_SET(kev++, pfd->fd, EVFILT_WRITE, EV_ADD|EV_ENABLE,
+                              0, 0, (void *)pkap->pfds);
+               if (pfd->events & (POLLPRI | POLLRDBAND))
+                       EV_SET(kev++, pfd->fd, EVFILT_EXCEPT, EV_ADD|EV_ENABLE,
+                              NOTE_OOB, 0, (void *)pkap->pfds);
+
+               ++pkap->pfds;
+               (*events) += kev_count;
+       }
+
+       return (0);
+}
+
+static int
+poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
+{
+       struct poll_kevent_copyin_args *pkap;
+       struct pollfd *pfd;
+       struct kevent kev;
        int i;
-       struct file *fp;
-       int n = 0;
-
-       for (i = 0; i < nfd; i++, fds++) {
-               if (fds->fd >= p->p_fd->fd_nfiles) {
-                       fds->revents = POLLNVAL;
-                       n++;
-               } else if (fds->fd < 0) {
-                       fds->revents = 0;
-               } else {
-                       fp = holdfp(p->p_fd, fds->fd, -1);
-                       if (fp == NULL) {
-                               fds->revents = POLLNVAL;
-                               n++;
-                       } else {
-                               /*
-                                * Note: backend also returns POLLHUP and
-                                * POLLERR if appropriate.
-                                */
-                               fds->revents = fo_poll(fp, fds->events,
-                                                       fp->f_cred);
-                               if (fds->revents != 0)
-                                       n++;
-                               fdrop(fp);
+
+       pkap = (struct poll_kevent_copyin_args *)arg;
+
+       for (i = 0; i < count; ++i) {
+               if ((int)kevp[i].udata < pkap->nfds) {
+                       pfd = &pkap->fds[(int)kevp[i].udata];
+                       if (kevp[i].ident == pfd->fd) {
+                               if (kevp[i].flags & EV_ERROR) {
+                                       /* Bad file descriptor */
+                                       if (kevp[i].data == EBADF)
+                                               pfd->revents |= POLLNVAL;
+                                       else
+                                               pfd->revents |= POLLERR;
+
+                                       ++*res;
+                                       continue;
+                               }
+
+                               if (kevp[i].flags & EV_EOF) {
+                                       pfd->revents |= POLLHUP;
+                                       ++*res;
+                                       continue;
+                               }
+
+                               switch (kevp[i].filter) {
+                               case EVFILT_READ:
+                                       pfd->revents |= (POLLIN | POLLRDNORM);
+                                       break;
+                               case EVFILT_WRITE:
+                                       pfd->revents |= (POLLOUT | POLLWRNORM);
+                                       break;
+                               case EVFILT_EXCEPT:
+                                       pfd->revents |= (POLLPRI | POLLRDBAND);
+                                       break;
+                               }
+
+                               ++*res;
+                               continue;
                        }
                }
+
+               /* Remove descriptor not in pollfd set from kq */
+               kev = kevp[i];
+               kev.flags = EV_DISABLE|EV_DELETE;
+               kqueue_register(&pkap->lwp->lwp_kqueue, &kev);
        }
-       *res = n;
+
        return (0);
 }
 
+static int
+dopoll(int nfds, struct pollfd *fds, struct timespec *ts, int *res)
+{
+       struct poll_kevent_copyin_args ka;
+       struct pollfd sfds[64];
+       int bytes;
+       int error;
+
+        *res = 0;
+        if (nfds < 0)
+                return (EINVAL);
+
+       /*
+        * This is a bit arbitrary but we need to limit internal kmallocs.
+        */
+        if (nfds > maxfilesperproc * 2)
+                nfds = maxfilesperproc * 2;
+       bytes = sizeof(struct pollfd) * nfds;
+
+       ka.lwp = curthread->td_lwp;
+       ka.nfds = nfds;
+       ka.pfds = 0;
+       ka.error = 0;
+
+       if (ka.nfds < 64)
+               ka.fds = sfds;
+       else
+               ka.fds = kmalloc(bytes, M_SELECT, M_WAITOK);
+
+       error = copyin(fds, ka.fds, bytes);
+       if (error == 0)
+               error = kern_kevent(&ka.lwp->lwp_kqueue, ka.nfds, res, &ka,
+                                   poll_copyin, poll_copyout, ts);
+
+       if (error == 0)
+               error = copyout(ka.fds, fds, bytes);
+
+       if (ka.fds != sfds)
+               kfree(ka.fds, M_SELECT);
+
+       return (error);
+}
+
 /*
  * OpenBSD poll system call.
  * XXX this isn't quite a true representation..  OpenBSD uses select ops.
@@ -1264,5 +1396,7 @@ selwakeup(struct selinfo *sip)
                        setrunnable(lp);
        }
        crit_exit();
+
+       kqueue_wakeup(&lp->lwp_kqueue);
 }
 
index 189634b..fadff46 100644 (file)
@@ -1396,6 +1396,7 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
                }
                break;
        default:
+               rel_mplock();
                return (1);
        }
        kn->kn_hook = (caddr_t)cpipe;
index 2273304..224519a 100644 (file)
@@ -71,6 +71,10 @@ static void ptsstart (struct tty *tp);
 static void ptsstop (struct tty *tp, int rw);
 static void ptcwakeup (struct tty *tp, int flag);
 static void ptyinit (int n);
+static int  filt_ptcread (struct knote *kn, long hint);
+static void filt_ptcrdetach (struct knote *kn);
+static int  filt_ptcwrite (struct knote *kn, long hint);
+static void filt_ptcwdetach (struct knote *kn);
 
 static d_open_t        ptsopen;
 static d_close_t       ptsclose;
@@ -82,6 +86,7 @@ static        d_close_t       ptcclose;
 static d_read_t        ptcread;
 static d_write_t       ptcwrite;
 static d_poll_t        ptcpoll;
+static d_kqfilter_t    ptckqfilter;
 
 #ifdef UNIX98_PTYS
 DEVFS_DECLARE_CLONE_BITMAP(pty);
@@ -110,7 +115,7 @@ static struct dev_ops ptc98_ops = {
        .d_write =      ptcwrite,
        .d_ioctl =      ptyioctl,
        .d_poll =       ptcpoll,
-       .d_kqfilter =   ttykqfilter,
+       .d_kqfilter =   ptckqfilter,
        .d_revoke =     ttyrevoke
 };
 #endif
@@ -137,7 +142,7 @@ static struct dev_ops ptc_ops = {
        .d_write =      ptcwrite,
        .d_ioctl =      ptyioctl,
        .d_poll =       ptcpoll,
-       .d_kqfilter =   ttykqfilter,
+       .d_kqfilter =   ptckqfilter,
        .d_revoke =     ttyrevoke
 };
 
@@ -441,10 +446,12 @@ ptcwakeup(struct tty *tp, int flag)
        if (flag & FREAD) {
                selwakeup(&pti->pt_selr);
                wakeup(TSA_PTC_READ(tp));
+               KNOTE(&tp->t_rsel.si_note, 0);
        }
        if (flag & FWRITE) {
                selwakeup(&pti->pt_selw);
                wakeup(TSA_PTC_WRITE(tp));
+               KNOTE(&tp->t_wsel.si_note, 0);
        }
 }
 
@@ -698,6 +705,104 @@ ptcpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+/*
+ * kqueue ops for pseudo-terminals.
+ */
+static struct filterops ptcread_filtops =
+       { 1, NULL, filt_ptcrdetach, filt_ptcread };
+static struct filterops ptcwrite_filtops =
+       { 1, NULL, filt_ptcwdetach, filt_ptcwrite };
+
+static int
+ptckqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct tty *tp = dev->si_tty;
+       struct klist *klist;
+
+       ap->a_result = 0;
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               klist = &tp->t_rsel.si_note;
+               kn->kn_fop = &ptcread_filtops;
+               break;
+       case EVFILT_WRITE:
+               klist = &tp->t_wsel.si_note;
+               kn->kn_fop = &ptcwrite_filtops;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       kn->kn_hook = (caddr_t)dev;
+
+       crit_enter();
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static int
+filt_ptcread (struct knote *kn, long hint)
+{
+       struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
+       struct pt_ioctl *pti = ((cdev_t)kn->kn_hook)->si_drv1;
+
+       if ((tp->t_state & TS_ISOPEN) &&
+           ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
+            ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
+            ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) {
+               kn->kn_data = tp->t_outq.c_cc;
+               return(1);
+       } else {
+               return(0);
+       }
+}
+
+static int
+filt_ptcwrite (struct knote *kn, long hint)
+{
+       struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
+       struct pt_ioctl *pti = ((cdev_t)kn->kn_hook)->si_drv1;
+
+       if (tp->t_state & TS_ISOPEN &&
+           ((pti->pt_flags & PF_REMOTE) ?
+            (tp->t_canq.c_cc == 0) :
+            ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
+             (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) {
+               kn->kn_data = tp->t_canq.c_cc + tp->t_rawq.c_cc;
+               return(1);
+       } else {
+               return(0);
+       }
+}
+
+static void
+filt_ptcrdetach (struct knote *kn)
+{
+       struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
+
+       crit_enter();
+       SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static void
+filt_ptcwdetach (struct knote *kn)
+{
+       struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
+
+       crit_enter();
+       SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+/*
+ * I/O ops
+ */
 static int
 ptcwrite(struct dev_write_args *ap)
 {
index 031b679..afb140e 100644 (file)
@@ -49,6 +49,8 @@
 #include <sys/ttycom.h>
 #include <sys/vnode.h>
 #include <sys/kernel.h>
+#include <sys/event.h>
+#include <sys/poll.h>
 
 static d_open_t        cttyopen;
 static d_close_t       cttyclose;
@@ -56,17 +58,23 @@ static      d_read_t        cttyread;
 static d_write_t       cttywrite;
 static d_ioctl_t       cttyioctl;
 static d_poll_t        cttypoll;
+static d_kqfilter_t    cttykqfilter;
+
+static void cttyfilt_detach(struct knote *);
+static int cttyfilt_read(struct knote *, long);
+static int cttyfilt_write(struct knote *, long);
 
 #define        CDEV_MAJOR      1
 /* Don't make this static, since fdesc_vnops uses it. */
 struct dev_ops ctty_ops = {
-       { "ctty", CDEV_MAJOR, D_TTY },
+       { "ctty", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       cttyopen,
        .d_close =      cttyclose,
        .d_read =       cttyread,
        .d_write =      cttywrite,
        .d_ioctl =      cttyioctl,
        .d_poll =       cttypoll,
+       .d_kqfilter =   cttykqfilter
 };
 
 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
@@ -254,6 +262,69 @@ cttypoll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops cttyfiltops_read =
+       { 1, NULL, cttyfilt_detach, cttyfilt_read };
+static struct filterops cttyfiltops_write =
+       { 1, NULL, cttyfilt_detach, cttyfilt_write };
+
+static int
+cttykqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct proc *p = curproc;
+       struct knote *kn = ap->a_kn;
+       struct vnode *ttyvp;
+
+       KKASSERT(p);
+       ttyvp = cttyvp(p);
+
+       if (ttyvp != NULL)
+               return (VOP_KQFILTER(ttyvp, kn));
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &cttyfiltops_read;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &cttyfiltops_write;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       return (0);
+}
+
+static void
+cttyfilt_detach(struct knote *kn) {}
+
+static int
+cttyfilt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+
+       if (seltrue(dev, POLLIN | POLLRDNORM))
+               return (1);
+
+       return (0);
+}
+
+static int
+cttyfilt_write(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+
+       if (seltrue(dev, POLLOUT | POLLWRNORM))
+               return (1);
+
+       return (0);
+}
+
 static void
 ctty_drvinit(void *unused __unused)
 {
index 97ae97e..fd83603 100644 (file)
@@ -116,6 +116,8 @@ static struct filterops soread_filtops =
        { 1, NULL, filt_sordetach, filt_soread };
 static struct filterops sowrite_filtops = 
        { 1, NULL, filt_sowdetach, filt_sowrite };
+static struct filterops soexcept_filtops =
+       { 1, NULL, filt_sordetach, filt_soread };
 
 MALLOC_DEFINE(M_SOCKET, "socket", "socket struct");
 MALLOC_DEFINE(M_SONAME, "soname", "socket name");
@@ -1698,6 +1700,7 @@ sohasoutofband(struct socket *so)
        if (so->so_sigio != NULL)
                pgsigio(so->so_sigio, SIGURG, 0);
        selwakeup(&so->so_rcv.ssb_sel);
+       KNOTE(&so->so_rcv.ssb_sel.si_note, NOTE_OOB);
 }
 
 int
@@ -1760,6 +1763,10 @@ sokqfilter(struct file *fp, struct knote *kn)
                kn->kn_fop = &sowrite_filtops;
                ssb = &so->so_snd;
                break;
+       case EVFILT_EXCEPT:
+               kn->kn_fop = &soexcept_filtops;
+               ssb = &so->so_rcv;
+               break;
        default:
                return (1);
        }
@@ -1789,6 +1796,13 @@ filt_soread(struct knote *kn, long hint)
 {
        struct socket *so = (struct socket *)kn->kn_fp->f_data;
 
+       if (kn->kn_sfflags & NOTE_OOB) {
+               if ((so->so_oobmark || (so->so_state & SS_RCVATMARK))) {
+                       kn->kn_fflags |= NOTE_OOB;
+                       return (1);
+               }
+               return (0);
+       }
        kn->kn_data = so->so_rcv.ssb_cc;
        if (so->so_state & SS_CANTRCVMORE) {
                kn->kn_flags |= EV_EOF; 
@@ -1799,7 +1813,8 @@ filt_soread(struct knote *kn, long hint)
                return (1);
        if (kn->kn_sfflags & NOTE_LOWAT)
                return (kn->kn_data >= kn->kn_sdata);
-       return (kn->kn_data >= so->so_rcv.ssb_lowat);
+       return ((kn->kn_data >= so->so_rcv.ssb_lowat) ||
+           !TAILQ_EMPTY(&so->so_comp));
 }
 
 static void
index b7b2f1d..9780c99 100644 (file)
@@ -58,6 +58,7 @@
 #include <sys/filedesc.h>
 
 #include <sys/poll.h>
+#include <sys/event.h>
 
 #include <sys/socket.h>
 #include <sys/vnode.h>
@@ -128,6 +129,8 @@ static int  bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd);
 static int     bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
 static int     bpf_setdlt(struct bpf_d *, u_int);
 static void    bpf_drvinit(void *unused);
+static void    bpf_filter_detach(struct knote *kn);
+static int     bpf_filter_read(struct knote *kn, long hint);
 
 static d_open_t                bpfopen;
 static d_clone_t       bpfclone;
@@ -136,16 +139,18 @@ static d_read_t           bpfread;
 static d_write_t       bpfwrite;
 static d_ioctl_t       bpfioctl;
 static d_poll_t                bpfpoll;
+static d_kqfilter_t    bpfkqfilter;
 
 #define CDEV_MAJOR 23
 static struct dev_ops bpf_ops = {
-       { "bpf", CDEV_MAJOR, 0 },
+       { "bpf", CDEV_MAJOR, D_KQFILTER },
        .d_open =       bpfopen,
        .d_close =      bpfclose,
        .d_read =       bpfread,
        .d_write =      bpfwrite,
        .d_ioctl =      bpfioctl,
        .d_poll =       bpfpoll,
+       .d_kqfilter =   bpfkqfilter
 };
 
 
@@ -1111,6 +1116,81 @@ bpfpoll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops bpf_read_filtops =
+       { 1, NULL, bpf_filter_detach, bpf_filter_read };
+
+static int
+bpfkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+       struct bpf_d *d;
+
+       d = dev->si_drv1;
+       if (d->bd_bif == NULL) {
+               ap->a_result = 1;
+               return (0);
+       }
+
+       ap->a_result = 0;
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &bpf_read_filtops;
+               kn->kn_hook = (caddr_t)d;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &d->bd_sel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+bpf_filter_detach(struct knote *kn)
+{
+       struct klist *klist;
+       struct bpf_d *d;
+
+       crit_enter();
+       d = (struct bpf_d *)kn->kn_hook;
+       klist = &d->bd_sel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+bpf_filter_read(struct knote *kn, long hint)
+{
+       struct bpf_d *d;
+       int ready = 0;
+
+       crit_enter();
+       d = (struct bpf_d *)kn->kn_hook;
+       if (d->bd_hlen != 0 ||
+           ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
+           d->bd_slen != 0)) {
+               ready = 1;
+       } else {
+               /* Start the read timeout if necessary. */
+               if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
+                       callout_reset(&d->bd_callout, d->bd_rtout,
+                           bpf_timed_out, d);
+                       d->bd_state = BPF_WAITING;
+               }
+       }
+       crit_exit();
+
+       return (ready);
+}
+
+
 /*
  * Process the packet pkt of length pktlen.  The packet is parsed
  * by each listener's filter, and if accepted, stashed into the
index 3d038dd..c53cf6e 100644 (file)
@@ -61,6 +61,7 @@
 #include "../layer4/i4b_l4.h"
 
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/filio.h>
 
 static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
@@ -118,6 +119,11 @@ PDEVSTATIC d_close_t i4brbchclose;
 PDEVSTATIC d_read_t i4brbchread;
 PDEVSTATIC d_write_t i4brbchwrite;
 PDEVSTATIC d_ioctl_t i4brbchioctl;
+PDEVSTATIC d_kqfilter_t i4brbchkqfilter;
+
+PDEVSTATIC void i4brbchkfilt_detach(struct knote *);
+PDEVSTATIC int i4brbchkfilt_read(struct knote *, long);
+PDEVSTATIC int i4brbchkfilt_write(struct knote *, long);
 
 PDEVSTATIC d_poll_t i4brbchpoll;
 #define POLLFIELD      i4brbchpoll
@@ -125,13 +131,14 @@ PDEVSTATIC d_poll_t i4brbchpoll;
 #define CDEV_MAJOR 57
 
 static struct dev_ops i4brbch_ops = {
-       { "i4brbch", CDEV_MAJOR, 0 },
+       { "i4brbch", CDEV_MAJOR, D_KQFILTER },
        .d_open =       i4brbchopen,
        .d_close =      i4brbchclose,
        .d_read =       i4brbchread,
        .d_write =      i4brbchwrite,
        .d_ioctl =      i4brbchioctl,
        .d_poll =       POLLFIELD,
+       .d_kqfilter =   i4brbchkqfilter
 };
 
 static void i4brbchattach(void *);
@@ -582,6 +589,124 @@ i4brbchpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops i4brbchkfiltops_read =
+       { 1, NULL, i4brbchkfilt_detach, i4brbchkfilt_read };
+static struct filterops i4brbchkfiltops_write =
+       { 1, NULL, i4brbchkfilt_detach, i4brbchkfilt_write };
+
+PDEVSTATIC int
+i4brbchkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       int unit = minor(dev);
+       struct rbch_softc *sc = &rbch_softc[unit];
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &i4brbchkfiltops_read;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &i4brbchkfiltops_write;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->selp.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+PDEVSTATIC void
+i4brbchkfilt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = minor(dev);
+       struct rbch_softc *sc = &rbch_softc[unit];
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->selp.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+PDEVSTATIC int
+i4brbchkfilt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = minor(dev);
+       struct rbch_softc *sc = &rbch_softc[unit];
+       int ready = 0;
+
+       crit_enter();
+
+       if (!(sc->sc_devstate & ST_ISOPEN)) {
+               crit_exit();
+               kn->kn_flags |= EV_ERROR;
+               kn->kn_data = EBADF;
+               return (0);
+       }
+
+       if (sc->sc_devstate & ST_CONNECTED) {
+               struct ifqueue *iqp;
+
+               if(sc->sc_bprot == BPROT_RHDLC)
+                       iqp = &sc->sc_hdlcq;
+               else
+                       iqp = isdn_linktab[unit]->rx_queue;
+
+               if(!IF_QEMPTY(iqp))
+                       ready = 1;
+       }
+
+       crit_exit();
+
+       return (ready);
+}
+
+PDEVSTATIC int
+i4brbchkfilt_write(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = minor(dev);
+       struct rbch_softc *sc = &rbch_softc[unit];
+       int ready = 0;
+
+       crit_enter();
+
+       if (!(sc->sc_devstate & ST_ISOPEN)) {
+               crit_exit();
+               kn->kn_flags |= EV_ERROR;
+               kn->kn_data = EBADF;
+               return (0);
+       }
+
+       /*
+        * Writes are OK if we are connected and the
+        * transmit queue can take them
+        */
+       if ((sc->sc_devstate & ST_CONNECTED) &&
+          !IF_QFULL(isdn_linktab[unit]->tx_queue))
+       {
+               ready = 1;
+       }
+
+       crit_exit();
+
+       return (ready);
+}
+
 #if I4BRBCHACCT
 /*---------------------------------------------------------------------------*
  *     watchdog routine
index 6ac82d6..917acf8 100644 (file)
@@ -44,6 +44,7 @@
 #include <sys/systm.h>
 
 #include <sys/poll.h>
+#include <sys/event.h>
 
 #include <sys/conf.h>
 #include <sys/uio.h>
@@ -141,20 +142,26 @@ PDEVSTATIC d_close_t      i4btelclose;
 PDEVSTATIC d_read_t    i4btelread;
 PDEVSTATIC d_write_t   i4btelwrite;
 PDEVSTATIC d_ioctl_t   i4btelioctl;
+PDEVSTATIC d_kqfilter_t        i4btelkqfilter;
 
 PDEVSTATIC d_poll_t i4btelpoll;
 #define POLLFIELD i4btelpoll
 
+PDEVSTATIC void i4btelfilt_detach(struct knote *);
+PDEVSTATIC int i4btelfilt_read(struct knote *, long);
+PDEVSTATIC int i4btelfilt_write(struct knote *, long);
+
 #define CDEV_MAJOR 56
 
 static struct dev_ops i4btel_ops = {
-       { "i4btel", CDEV_MAJOR, 0 },
+       { "i4btel", CDEV_MAJOR, D_KQFILTER },
        .d_open =       i4btelopen,
        .d_close =      i4btelclose,
        .d_read =       i4btelread,
        .d_write =      i4btelwrite,
        .d_ioctl =      i4btelioctl,
        .d_poll =       POLLFIELD,
+       .d_kqfilter =   i4btelkqfilter
 };
 
 PDEVSTATIC void i4btelattach(void *);
@@ -762,6 +769,143 @@ i4btelpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+PDEVSTATIC struct filterops i4btelfiltops_read =
+       { 1, NULL, i4btelfilt_detach, i4btelfilt_read };
+PDEVSTATIC struct filterops i4btelfiltops_write =
+       { 1, NULL, i4btelfilt_detach, i4btelfilt_write };
+
+PDEVSTATIC int
+i4btelkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       int unit = UNIT(dev);
+       int func = FUNC(dev);
+       tel_sc_t *sc = &tel_sc[unit][func];
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &i4btelfiltops_read;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &i4btelfiltops_write;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->selp.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+PDEVSTATIC void
+i4btelfilt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = UNIT(dev);
+       int func = FUNC(dev);
+       tel_sc_t *sc = &tel_sc[unit][func];
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->selp.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+PDEVSTATIC int
+i4btelfilt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = UNIT(dev);
+       int func = FUNC(dev);
+       tel_sc_t *sc = &tel_sc[unit][func];
+       int ready = 0;
+
+       crit_enter();
+
+       if (!(sc->devstate & ST_ISOPEN)) {
+                NDBGL4(L4_TELDBG, "i4btel%d, !ST_ISOPEN", unit);
+                crit_exit();
+                return (0);
+        }
+
+       switch (func) {
+       case FUNCTEL:
+               /* reads are OK if we have any data */
+               if ((sc->devstate & ST_CONNECTED)   &&
+                  (sc->isdn_linktab != NULL)      &&
+                  (!IF_QEMPTY(sc->isdn_linktab->rx_queue)))
+               {
+                       NDBGL4(L4_TELDBG, "i4btel%d, filt readable", unit);
+                       ready = 1;
+               }
+
+               break;
+       case FUNCDIAL:
+               NDBGL4(L4_TELDBG, "i4bteld%d, filt readable, result = %d", unit, sc->result);
+               if(sc->result != 0)
+                       ready = 1;
+               break;
+       }
+
+       crit_exit();
+
+       return (ready);
+}
+
+PDEVSTATIC int
+i4btelfilt_write(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       int unit = UNIT(dev);
+       int func = FUNC(dev);
+       tel_sc_t *sc = &tel_sc[unit][func];
+       int ready = 0;
+
+       crit_enter();
+
+       if (!(sc->devstate & ST_ISOPEN)) {
+               NDBGL4(L4_TELDBG, "i4btel%d, !ST_ISOPEN", unit);
+               crit_exit();
+               return (0);
+       }
+
+       switch (func) {
+       case FUNCTEL:
+               /*
+                * Writes are OK if we are connected and the
+                * transmit queue can take them
+                */
+               if ((sc->devstate & ST_CONNECTED)   &&
+                  (sc->isdn_linktab != NULL)      &&
+                  (!IF_QFULL(sc->isdn_linktab->tx_queue)))
+               {
+                        NDBGL4(L4_TELDBG, "i4btel%d, filt writable", unit);
+                        ready = 1;
+               }
+               break;
+       case FUNCDIAL:
+               NDBGL4(L4_TELDBG, "i4bteld%d, filt writable", unit);
+               ready = 1;
+               break;
+       }
+
+       crit_exit();
+
+       return (ready);
+}
+
 /*===========================================================================*
  *                     ISDN INTERFACE ROUTINES
  *===========================================================================*/
index 8f0f468..433644f 100644 (file)
 #include "i4b_l4.h"
 
 #include <sys/poll.h>
+#include <sys/event.h>
 
 struct selinfo select_rd_info;
 
 static struct ifqueue i4b_rdqueue;
 static int openflag = 0;
-static int selflag = 0;
 static int readflag = 0;
 
 #define PDEVSTATIC     static
@@ -87,6 +87,11 @@ PDEVSTATIC   d_open_t        i4bopen;
 PDEVSTATIC     d_close_t       i4bclose;
 PDEVSTATIC     d_read_t        i4bread;
 PDEVSTATIC     d_ioctl_t       i4bioctl;
+PDEVSTATIC     d_kqfilter_t    i4bkqfilter;
+
+PDEVSTATIC void i4bkqfilt_detach(struct knote *);
+PDEVSTATIC int i4bkqfilt_read(struct knote *, long);
+PDEVSTATIC int i4bkqfilt_write(struct knote *, long);
 
 PDEVSTATIC     d_poll_t        i4bpoll;
 #define POLLFIELD              i4bpoll
@@ -94,12 +99,13 @@ PDEVSTATIC  d_poll_t        i4bpoll;
 #define CDEV_MAJOR 60
 
 static struct dev_ops i4b_ops = {
-       { "i4b", CDEV_MAJOR, 0 },
+       { "i4b", CDEV_MAJOR, D_KQFILTER },
        .d_open =       i4bopen,
        .d_close =      i4bclose,
        .d_read =       i4bread,
        .d_ioctl =      i4bioctl,
        .d_poll =       POLLFIELD,
+       .d_kqfilter =   i4bkqfilter
 };
 
 PDEVSTATIC void i4battach(void *);
@@ -746,7 +752,6 @@ i4bpoll(struct dev_poll_args *ap)
                        revents |= POLLIN | POLLRDNORM;
                } else {
                        selrecord(curthread, &select_rd_info);
-                       selflag = 1;
                }
                crit_exit();
                return(0);
@@ -758,6 +763,73 @@ i4bpoll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops i4bkqfiltops_read =
+       { 1, NULL, i4bkqfilt_detach, i4bkqfilt_read };
+static struct filterops i4bkqfiltops_write =
+       { 1, NULL, i4bkqfilt_detach, i4bkqfilt_write };
+
+PDEVSTATIC int
+i4bkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       if (minor(dev))
+               return (1);
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &i4bkqfiltops_read;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &i4bkqfiltops_write;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &select_rd_info.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+PDEVSTATIC void
+i4bkqfilt_detach(struct knote *kn)
+{
+       struct klist *klist;
+
+       crit_enter();
+       klist = &select_rd_info.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+PDEVSTATIC int
+i4bkqfilt_read(struct knote *kn, long hint)
+{
+       int ready = 0;
+
+       crit_enter();
+       if (!IF_QEMPTY(&i4b_rdqueue))
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
+PDEVSTATIC int
+i4bkqfilt_write(struct knote *kn, long hint)
+{
+       return (1);
+}
+
 /*---------------------------------------------------------------------------*
  *     i4bputqueue - put message into queue to userland
  *---------------------------------------------------------------------------*/
@@ -790,11 +862,7 @@ i4bputqueue(struct mbuf *m)
                wakeup((caddr_t) &i4b_rdqueue);
        }
 
-       if(selflag)
-       {
-               selflag = 0;
-               selwakeup(&select_rd_info);
-       }
+       selwakeup(&select_rd_info);
 }
 
 /*---------------------------------------------------------------------------*
@@ -829,11 +897,7 @@ i4bputqueue_hipri(struct mbuf *m)
                wakeup((caddr_t) &i4b_rdqueue);
        }
 
-       if(selflag)
-       {
-               selflag = 0;
-               selwakeup(&select_rd_info);
-       }
+       selwakeup(&select_rd_info);
 }
 
 #endif /* NI4B > 0 */
index 7a06e71..62a645c 100644 (file)
@@ -78,6 +78,8 @@ static int tunoutput (struct ifnet *, struct mbuf *, struct sockaddr *,
 static int tunifioctl (struct ifnet *, u_long, caddr_t, struct ucred *);
 static int tuninit (struct ifnet *);
 static void tunstart(struct ifnet *);
+static void tun_filter_detach(struct knote *);
+static int tun_filter_read(struct knote *, long);
 
 static d_open_t        tunopen;
 static d_close_t       tunclose;
@@ -85,6 +87,7 @@ static        d_read_t        tunread;
 static d_write_t       tunwrite;
 static d_ioctl_t       tunioctl;
 static d_poll_t        tunpoll;
+static d_kqfilter_t    tunkqfilter;
 
 static d_clone_t tunclone;
 DEVFS_DECLARE_CLONE_BITMAP(tun);
@@ -97,13 +100,14 @@ DEVFS_DECLARE_CLONE_BITMAP(tun);
 
 #define CDEV_MAJOR 52
 static struct dev_ops tun_ops = {
-       { "tun", CDEV_MAJOR, 0 },
+       { "tun", CDEV_MAJOR, D_KQFILTER },
        .d_open =       tunopen,
        .d_close =      tunclose,
        .d_read =       tunread,
        .d_write =      tunwrite,
        .d_ioctl =      tunioctl,
        .d_poll =       tunpoll,
+       .d_kqfilter =   tunkqfilter
 };
 
 static void
@@ -731,6 +735,67 @@ tunpoll(struct dev_poll_args *ap)
        return(0);
 }
 
+static struct filterops tun_read_filtops =
+       { 1, NULL, tun_filter_detach, tun_filter_read };
+
+static int
+tunkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct tun_softc *tp = dev->si_drv1;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+       ifnet_serialize_all(&tp->tun_if);
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &tun_read_filtops;
+               kn->kn_hook = (caddr_t)tp;
+               break;
+       default:
+               ap->a_result = 1;
+               ifnet_deserialize_all(&tp->tun_if);
+               return (0);
+       }
+
+       klist = &tp->tun_rsel.si_note;
+       crit_enter();
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       ifnet_deserialize_all(&tp->tun_if);
+
+       return (0);
+}
+
+static void
+tun_filter_detach(struct knote *kn)
+{
+       struct tun_softc *tp = (struct tun_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       klist = &tp->tun_rsel.si_note;
+       crit_enter();
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+tun_filter_read(struct knote *kn, long hint)
+{
+       struct tun_softc *tp = (struct tun_softc *)kn->kn_hook;
+       int ready = 0;
+
+       ifnet_serialize_all(&tp->tun_if);
+       if (!ifq_is_empty(&tp->tun_if.if_snd))
+               ready = 1;
+       ifnet_deserialize_all(&tp->tun_if);
+
+       return (ready);
+}
+
 /*
  * Start packet transmission on the interface.
  * when the interface queue is rate-limited by ALTQ,
index 36971cf..4387bb6 100644 (file)
@@ -47,6 +47,7 @@ static device_t       acpi_dev;
  */
 
 #include <sys/selinfo.h>
+#include <sys/event.h>
 
 #include <machine/apm_bios.h>
 #include <machine/pc/bios.h>
@@ -67,15 +68,17 @@ static d_close_t apmclose;
 static d_write_t apmwrite;
 static d_ioctl_t apmioctl;
 static d_poll_t apmpoll;
+static d_kqfilter_t apmkqfilter;
 
 #define CDEV_MAJOR 39
 static struct dev_ops apm_ops = {
-       { "apm", CDEV_MAJOR, 0 },
+       { "apm", CDEV_MAJOR, D_KQFILTER },
         .d_open = apmopen,
         .d_close = apmclose,
        .d_write = apmwrite,
         .d_ioctl = apmioctl,
-       .d_poll = apmpoll
+       .d_poll = apmpoll,
+       .d_kqfilter = apmkqfilter
 };
 
 static int
@@ -301,6 +304,31 @@ apmpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static void apmfilter_detach(struct knote *);
+static int apmfilter(struct knote *, long);
+
+static struct filterops apmfilterops =
+       { 1, NULL, apmfilter_detach, apmfilter };
+
+static int
+apmkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+
+       kn->kn_fop = &apmfilterops;
+       ap->a_result = 0;
+       return (0);
+}
+
+static void
+apmfilter_detach(struct knote *kn) {}
+
+static int
+apmfilter(struct knote *kn, long hint)
+{
+       return (0);
+}
+
 static void
 acpi_capm_init(struct acpi_softc *sc)
 {
index fc4d5ac..5a49e2c 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/bus.h>
 #include <sys/selinfo.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/fcntl.h>
 #include <sys/uio.h>
 #include <sys/signalvar.h>
@@ -83,15 +84,20 @@ static d_close_t apmclose;
 static d_write_t apmwrite;
 static d_ioctl_t apmioctl;
 static d_poll_t apmpoll;
+static d_kqfilter_t apmkqfilter;
+
+static void apmfilter_detach(struct knote *);
+static int apmfilter(struct knote *, long);
 
 #define CDEV_MAJOR 39
 static struct dev_ops apm_ops = {
-       { "apm", CDEV_MAJOR, 0 },
+       { "apm", CDEV_MAJOR, D_KQFILTER },
        .d_open =       apmopen,
        .d_close =      apmclose,
        .d_write =      apmwrite,
        .d_ioctl =      apmioctl,
        .d_poll =       apmpoll,
+       .d_kqfilter =   apmkqfilter
 };
 
 static int apm_suspend_delay = 1;
@@ -1353,6 +1359,60 @@ apmpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops apmfiltops =
+       { 1, NULL, apmfilter_detach, apmfilter };
+
+static int
+apmkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct apm_softc *sc = &apm_softc;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &apmfiltops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+apmfilter_detach(struct knote *kn)
+{
+       struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+apmfilter(struct knote *kn, long hint)
+{
+       struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
+       int ready = 0;
+
+       if (sc->event_count)
+               ready = 1;
+
+       return (ready);
+}
+
 /*
  * Because apm is a static device that always exists under any attached
  * isa device, and not scanned by the isa device, we need an identify
index 9b38135..dc48b88 100644 (file)
@@ -47,6 +47,7 @@
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/selinfo.h>
 #include <sys/uio.h>
 #include <sys/thread2.h>
@@ -186,16 +187,21 @@ static d_close_t  ascclose;
 static d_read_t                ascread;
 static d_ioctl_t       ascioctl;
 static d_poll_t                ascpoll;
+static d_kqfilter_t    asckqfilter;
+
+static void ascfilter_detach(struct knote *kn);
+static int ascfilter(struct knote *kn, long hint);
 
 #define CDEV_MAJOR 71
 
 static struct dev_ops asc_ops = {
-       { "asc", CDEV_MAJOR, 0 },
+       { "asc", CDEV_MAJOR, D_KQFILTER },
        .d_open =       ascopen,
        .d_close =      ascclose,
        .d_read =       ascread,
        .d_ioctl =      ascioctl,
        .d_poll =       ascpoll,
+       .d_kqfilter =   asckqfilter
 };
 
 #define STATIC static
@@ -870,3 +876,65 @@ ascpoll(struct dev_poll_args *ap)
     ap->a_events = revents;
     return (0);
 }
+
+static struct filterops ascfiltops =
+    { 1, NULL, ascfilter_detach, ascfilter };
+
+STATIC int
+asckqfilter(struct dev_kqfilter_args *ap)
+{
+    cdev_t dev = ap->a_head.a_dev;
+    int unit = UNIT(minor(dev));
+    struct asc_unit *scu = unittab + unit;
+    struct knote *kn = ap->a_kn;
+    struct klist *klist;
+
+    ap->a_result = 0;
+
+    switch (kn->kn_filter) {
+    case EVFILT_READ:
+        kn->kn_fop = &ascfiltops;
+        kn->kn_hook = (caddr_t)scu;
+        break;
+    default:
+        ap->a_result = 1;
+        return (0);
+    }
+
+    crit_enter();
+    klist = &scu->selp.si_note;
+    SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+    crit_exit();
+
+    return (0);
+}
+
+STATIC void
+ascfilter_detach(struct knote *kn)
+{
+    struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
+    struct klist *klist;
+
+    crit_enter();
+    klist = &scu->selp.si_note;
+    SLIST_REMOVE(klist, kn, knote, kn_selnext);
+    crit_exit();
+}
+
+STATIC int
+ascfilter(struct knote *kn, long hint)
+{
+    struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
+    int ready = 0;
+
+    crit_enter();
+    if (scu->sbuf.count >0)
+        ready = 1;
+    else {
+        if (!(scu->flags & DMA_ACTIVE))
+            dma_restart(scu);
+    }
+    crit_exit();
+
+    return (ready);
+}
index 49152f7..da44709 100644 (file)
@@ -47,6 +47,7 @@ static device_t       acpi_dev;
  */
 
 #include <sys/selinfo.h>
+#include <sys/event.h>
 
 #include <machine/apm_bios.h>
 #include <machine/pc/bios.h>
@@ -63,6 +64,7 @@ static d_close_t apmclose;
 static d_write_t apmwrite;
 static d_ioctl_t apmioctl;
 static d_poll_t apmpoll;
+static d_kqfilter_t apmkqfilter;
 
 #define CDEV_MAJOR 39
 static struct dev_ops apm_ops = {
@@ -71,7 +73,8 @@ static struct dev_ops apm_ops = {
         .d_close = apmclose,
        .d_write = apmwrite,
         .d_ioctl = apmioctl,
-       .d_poll = apmpoll
+       .d_poll = apmpoll,
+       .d_kqfilter = apmkqfilter
 };
 
 static int
@@ -297,6 +300,31 @@ apmpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static void apmfilter_detach(struct knote *);
+static int apmfilter(struct knote *, long);
+
+static struct filterops apmfilterops =
+       { 1, NULL, apmfilter_detach, apmfilter };
+
+static int
+apmkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct knote *kn = ap->a_kn;
+
+       kn->kn_fop = &apmfilterops;
+       ap->a_result = 0;
+       return (0);
+}
+
+static void
+apmfilter_detach(struct knote *kn) {}
+
+static int
+apmfilter(struct knote *kn, long hint)
+{
+       return (0);
+}
+
 static void
 acpi_capm_init(struct acpi_softc *sc)
 {
index a40ca54..6f4f4a7 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/bus.h>
 #include <sys/selinfo.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/fcntl.h>
 #include <sys/uio.h>
 #include <sys/signalvar.h>
@@ -83,15 +84,20 @@ static d_close_t apmclose;
 static d_write_t apmwrite;
 static d_ioctl_t apmioctl;
 static d_poll_t apmpoll;
+static d_kqfilter_t apmkqfilter;
+
+static void apmfilter_detach(struct knote *);
+static int apmfilter(struct knote *, long);
 
 #define CDEV_MAJOR 39
 static struct dev_ops apm_ops = {
-       { "apm", CDEV_MAJOR, 0 },
+       { "apm", CDEV_MAJOR, D_KQFILTER },
        .d_open =       apmopen,
        .d_close =      apmclose,
        .d_write =      apmwrite,
        .d_ioctl =      apmioctl,
        .d_poll =       apmpoll,
+       .d_kqfilter =   apmkqfilter
 };
 
 static int apm_suspend_delay = 1;
@@ -1353,6 +1359,60 @@ apmpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops apmfiltops =
+       { 1, NULL, apmfilter_detach, apmfilter };
+
+static int
+apmkqfilter(struct dev_kqfilter_args *ap)
+{
+       struct apm_softc *sc = &apm_softc;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &apmfiltops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+apmfilter_detach(struct knote *kn)
+{
+       struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+apmfilter(struct knote *kn, long hint)
+{
+       struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
+       int ready = 0;
+
+       if (sc->event_count)
+               ready = 1;
+
+       return (ready);
+}
+
 /*
  * Because apm is a static device that always exists under any attached
  * isa device, and not scanned by the isa device, we need an identify
index b53c78d..c4f58de 100644 (file)
@@ -48,6 +48,7 @@
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/selinfo.h>
 #include <sys/uio.h>
 #include <sys/thread2.h>
@@ -185,16 +186,21 @@ static d_close_t  ascclose;
 static d_read_t                ascread;
 static d_ioctl_t       ascioctl;
 static d_poll_t                ascpoll;
+static d_kqfilter_t    asckqfilter;
+
+static void ascfilter_detach(struct knote *kn);
+static int ascfilter(struct knote *kn, long hint);
 
 #define CDEV_MAJOR 71
 
 static struct dev_ops asc_ops = {
-       { "asc", CDEV_MAJOR, 0 },
+       { "asc", CDEV_MAJOR, D_KQFILTER },
        .d_open =       ascopen,
        .d_close =      ascclose,
        .d_read =       ascread,
        .d_ioctl =      ascioctl,
        .d_poll =       ascpoll,
+       .d_kqfilter =   asckqfilter
 };
 
 #define STATIC static
@@ -869,3 +875,65 @@ ascpoll(struct dev_poll_args *ap)
     ap->a_events = revents;
     return (0);
 }
+
+static struct filterops ascfiltops =
+    { 1, NULL, ascfilter_detach, ascfilter };
+
+STATIC int
+asckqfilter(struct dev_kqfilter_args *ap)
+{
+    cdev_t dev = ap->a_head.a_dev;
+    int unit = UNIT(minor(dev));
+    struct asc_unit *scu = unittab + unit;
+    struct knote *kn = ap->a_kn;
+    struct klist *klist;
+
+    ap->a_result = 0;
+
+    switch (kn->kn_filter) {
+    case EVFILT_READ:
+        kn->kn_fop = &ascfiltops;
+        kn->kn_hook = (caddr_t)scu;
+        break;
+    default:
+        ap->a_result = 1;
+        return (0);
+    }
+
+    crit_enter();
+    klist = &scu->selp.si_note;
+    SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+    crit_exit();
+
+    return (0);
+}
+
+STATIC void
+ascfilter_detach(struct knote *kn)
+{
+    struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
+    struct klist *klist;
+
+    crit_enter();
+    klist = &scu->selp.si_note;
+    SLIST_REMOVE(klist, kn, knote, kn_selnext);
+    crit_exit();
+}
+
+STATIC int
+ascfilter(struct knote *kn, long hint)
+{
+    struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
+    int ready = 0;
+
+    crit_enter();
+    if (scu->sbuf.count >0)
+        ready = 1;
+    else {
+        if (!(scu->flags & DMA_ACTIVE))
+            dma_restart(scu);
+    }
+    crit_exit();
+
+    return (ready);
+}
index 288cb10..c942d0c 100644 (file)
@@ -82,13 +82,14 @@ static d_close_t        vcons_close;
 static d_ioctl_t        vcons_ioctl;
 
 static struct dev_ops vcons_ops = {
-       { "vcons", CDEV_MAJOR, D_TTY },
+       { "vcons", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       vcons_open,
        .d_close =      vcons_close,
        .d_read =       ttyread,
        .d_write =      ttywrite,
        .d_ioctl =      vcons_ioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter,
 };
 
 static int
index db99c5a..f07834a 100644 (file)
@@ -82,13 +82,14 @@ static d_close_t        vcons_close;
 static d_ioctl_t        vcons_ioctl;
 
 static struct dev_ops vcons_ops = {
-       { "vcons", CDEV_MAJOR, D_TTY },
+       { "vcons", CDEV_MAJOR, D_TTY | D_KQFILTER },
        .d_open =       vcons_open,
        .d_close =      vcons_close,
        .d_read =       ttyread,
        .d_write =      ttywrite,
        .d_ioctl =      vcons_ioctl,
        .d_poll =       ttypoll,
+       .d_kqfilter =   ttykqfilter
 };
 
 static int
index a2922fe..28aed8c 100644 (file)
 #define EVFILT_PROC            (-5)    /* attached to struct proc */
 #define EVFILT_SIGNAL          (-6)    /* attached to struct proc */
 #define EVFILT_TIMER           (-7)    /* timers */
+#define EVFILT_EXCEPT          (-8)    /* exceptional conditions */
 
-#define EVFILT_SYSCOUNT                7
+#define EVFILT_MARKER          0xF     /* placemarker for tailq */
+
+#define EVFILT_SYSCOUNT                8
 
 #define EV_SET(kevp_, a, b, c, d, e, f) do {   \
        struct kevent *kevp = (kevp_);          \
@@ -85,6 +88,11 @@ struct kevent {
  */
 #define NOTE_LOWAT     0x0001                  /* low water mark */
 
+/*
+ * data/hint flags for EVFILT_EXCEPT, shared with userspace
+ */
+#define NOTE_OOB       0x0002                  /* OOB data on a socket */
+
 /*
  * data/hint flags for EVFILT_VNODE, shared with userspace
  */
@@ -134,8 +142,12 @@ MALLOC_DECLARE(M_KQUEUE);
 
 struct filterops {
        int     f_isfd;         /* true if ident == filedescriptor */
+
+       /* f_attach returns 0 on success or valid error code on failure */
        int     (*f_attach)     (struct knote *kn);
        void    (*f_detach)     (struct knote *kn);
+
+        /* f_event returns boolean truth */
        int     (*f_event)      (struct knote *kn, long hint);
 };
 
@@ -173,9 +185,11 @@ struct thread;
 struct filedesc;
 struct kevent_args;
 
-typedef int    (*k_copyout_fn)(void *arg, struct kevent *kevp, int count);
-typedef int    (*k_copyin_fn)(void *arg, struct kevent *kevp, int count);
-int kern_kevent(int fd, int nchanges, int nevents, struct kevent_args *uap,
+typedef int    (*k_copyout_fn)(void *arg, struct kevent *kevp, int count,
+    int *res);
+typedef int    (*k_copyin_fn)(void *arg, struct kevent *kevp, int max,
+    int *events);
+int kern_kevent(struct kqueue *kq, int nevents, int *res, void *uap,
     k_copyin_fn kevent_copyin, k_copyout_fn kevent_copyout,
     struct timespec *tsp);
 
@@ -185,6 +199,7 @@ extern void knote_fdclose(struct file *fp, struct filedesc *fdp, int fd);
 extern void    kqueue_init(struct kqueue *kq, struct filedesc *fdp);
 extern void    kqueue_terminate(struct kqueue *kq);
 extern int     kqueue_register(struct kqueue *kq, struct kevent *kev);
+extern void    kqueue_wakeup(struct kqueue *kq);
 
 #endif         /* _KERNEL */
 
index 8d50470..19d8f13 100644 (file)
@@ -218,6 +218,7 @@ struct lwp {
        struct thread   *lwp_thread;    /* backpointer to proc's thread */
        struct upcall   *lwp_upcall;    /* REGISTERED USERLAND POINTER! */
        struct kqueue   lwp_kqueue;     /* for select/poll */
+       u_int           lwp_kqueue_serial;
 };
 
 struct proc {
index c53817d..f19d562 100644 (file)
@@ -95,7 +95,9 @@ u_int read_random_unlimited(void *buf, u_int size);
 u_int write_random(const char *buf, u_int nbytes);
 #endif
 struct thread;
+struct knote;
 int random_poll(cdev_t dev, int events);
+int random_filter_read(struct knote *kn, long hint);
 
 #endif /* _KERNEL */
 
index 2108c10..3b2799d 100644 (file)
@@ -60,6 +60,7 @@
 #include <sys/sysctl.h>
 #include <sys/devfs.h>
 #include <sys/pioctl.h>
+#include <vfs/fifofs/fifo.h>
 
 #include <machine/limits.h>
 
@@ -1390,7 +1391,10 @@ devfs_specf_kqfilter(struct file *fp, struct knote *kn)
 
 done:
        rel_mplock();
-       return (error);
+       if (error)
+               return (-1);
+
+       return (0);
 }
 
 
@@ -1685,7 +1689,7 @@ devfs_spec_kqfilter(struct vop_kqfilter_args *ap)
        cdev_t dev;
 
        if ((dev = vp->v_rdev) == NULL)
-               return (EBADF);         /* device was revoked */
+               return (1);             /* device was revoked (EBADF) */
        node = DEVFS_NODE(vp);
 
 #if 0
@@ -1693,7 +1697,7 @@ devfs_spec_kqfilter(struct vop_kqfilter_args *ap)
                nanotime(&node->atime);
 #endif
 
-       return (dev_dkqfilter(dev, ap->a_kn));
+       return (!dev_dkqfilter(dev, ap->a_kn));
 }
 
 /*
diff --git a/tools/test/kqueue/Makefile b/tools/test/kqueue/Makefile
new file mode 100644 (file)
index 0000000..c03a456
--- /dev/null
@@ -0,0 +1,8 @@
+PROG=   kqueue_oob
+SRCS=   kqueue_oob.c
+NOMAN=  sorry
+
+test:  kqueue_oob
+       @csh -x -c "./kqueue_oob"
+
+.include <bsd.prog.mk>
diff --git a/tools/test/kqueue/kqueue_oob.c b/tools/test/kqueue/kqueue_oob.c
new file mode 100644 (file)
index 0000000..47bdbcd
--- /dev/null
@@ -0,0 +1,62 @@
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <netinet/in.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+    struct sockaddr_in sa_local, sa_remote;
+    socklen_t sin_size = sizeof(struct sockaddr_in);
+    struct timespec timeout;
+    struct kevent eventlist[1], changelist[1];
+    int kq, fd_l, fd_c, fd_n, i;
+
+    if ((fd_l = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        err(EX_OSERR, "socket(2) failure");
+
+    if ((fd_c = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        err(EX_OSERR, "socket(2) failure");
+
+    sa_local.sin_family = AF_INET;
+    sa_local.sin_port = 0;
+    sa_local.sin_addr.s_addr = htonl(INADDR_ANY);
+    memset(&(sa_local.sin_zero), 0, sizeof(sa_local.sin_zero));
+
+    if (bind(fd_l, (struct sockaddr *)&sa_local, sizeof(struct sockaddr)) == -1)
+        err(EX_OSERR, "bind(2) failure");
+
+    if (getsockname(fd_l, (struct sockaddr *)&sa_local, &sin_size) == -1)
+        err(EX_OSERR, "getsockname(2) failure");
+
+    if (listen(fd_l, 1) == -1)
+        err(EX_OSERR, "listen(2) failure");
+
+    if (connect(fd_c, (struct sockaddr *)&sa_local, sizeof(struct sockaddr)) == -1)
+        err(EX_OSERR, "connect(2) failure");
+
+    fd_n = accept(fd_l, (struct sockaddr *)&sa_remote, &sin_size);
+
+    if ((kq = kqueue()) == -1)
+        err(EX_OSERR, "kqueue(2) failure");
+
+    if (send(fd_c, "x", 1, MSG_OOB) == -1)
+        err(EX_OSERR, "send(2) failure");
+
+    EV_SET(&changelist[0], fd_n, EVFILT_EXCEPT, EV_ADD|EV_ENABLE, NOTE_OOB, 0, NULL);
+
+    memset(&timeout, 0, sizeof(timeout));
+    if ((i = kevent(kq, &changelist[0], 1, &eventlist[0], 1, &timeout)) == -1)
+        err(EX_OSERR, "kevent(2) failure");
+
+    if (i == 1 && eventlist[0].fflags & NOTE_OOB) {
+        printf("ok\n");
+    }
+
+    return (0);
+}
diff --git a/tools/test/select/Makefile b/tools/test/select/Makefile
new file mode 100644 (file)
index 0000000..fd5ce46
--- /dev/null
@@ -0,0 +1,8 @@
+PROG=   select_oob
+SRCS=   select_oob.c
+NOMAN=  sorry
+
+test:  select_oob
+       @csh -x -c "./select_oob"
+
+.include <bsd.prog.mk>
diff --git a/tools/test/select/select_many_write.c b/tools/test/select/select_many_write.c
new file mode 100644 (file)
index 0000000..779a5f2
--- /dev/null
@@ -0,0 +1,33 @@
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#define MANY 80
+
+int
+main(int argc, char *argv[])
+{
+    fd_set write_fds;
+    int fd[MANY+3], i, maxfd;
+
+    FD_ZERO(&write_fds);
+    for (i = 0; i < MANY; ++i) {
+        if ((fd[i] = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+            err(EX_OSERR, "socket(2) failure");
+
+        FD_SET(fd[i], &write_fds);
+        maxfd = fd[i];
+    }
+
+    i = select(maxfd+1, NULL, &write_fds, NULL, NULL);
+
+    if (i == MANY)
+        printf("ok\n");
+
+    return (0);
+}
diff --git a/tools/test/select/select_oob.c b/tools/test/select/select_oob.c
new file mode 100644 (file)
index 0000000..3e48277
--- /dev/null
@@ -0,0 +1,57 @@
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+    struct sockaddr_in sa_local, sa_remote;
+    socklen_t sin_size = sizeof(struct sockaddr_in);
+    fd_set exceptfds;
+    struct timeval timeout;
+    int fd_l, fd_c, fd_n, i;
+
+    if ((fd_l = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        err(EX_OSERR, "socket(2) failure");
+
+    if ((fd_c = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+        err(EX_OSERR, "socket(2) failure");
+
+    sa_local.sin_family = AF_INET;
+    sa_local.sin_port = 0;
+    sa_local.sin_addr.s_addr = htonl(INADDR_ANY);
+    memset(&(sa_local.sin_zero), 0, sizeof(sa_local.sin_zero));
+
+    if (bind(fd_l, (struct sockaddr *)&sa_local, sizeof(struct sockaddr)) == -1)
+        err(EX_OSERR, "bind(2) failure");
+
+    if (getsockname(fd_l, (struct sockaddr *)&sa_local, &sin_size) == -1)
+        err(EX_OSERR, "getsockname(2) failure");
+
+    if (listen(fd_l, 1) == -1)
+        err(EX_OSERR, "listen(2) failure");
+
+    if (connect(fd_c, (struct sockaddr *)&sa_local, sizeof(struct sockaddr)) == -1)
+        err(EX_OSERR, "connect(2) failure");
+
+    fd_n = accept(fd_l, (struct sockaddr *)&sa_remote, &sin_size);
+
+    FD_ZERO(&exceptfds);
+    FD_SET(fd_n, &exceptfds);
+
+    if (send(fd_c, "x", 1, MSG_OOB) == -1)
+        err(EX_OSERR, "send(2) failure");
+
+    memset(&timeout, 0, sizeof(timeout));
+    i = select(fd_n+1, NULL, NULL, &exceptfds, &timeout);
+
+    if (i == 1)
+        printf("ok\n");
+
+    return (0);
+}