The kqueue subsystem has no mechanism to indicate "exceptional conditions",
that is the equivalent of poll(2)'s POLLPRI & POLLRDBAND and select(2)'s
`exceptfds'.

The diff below implements DragonFly's approach of adding a new kind of
filter, EVFILT_EXCEPT, to report such conditions.  This extends the
existing kqueue interface which is questionable.  On the one hand this
allows userland programs to use kevent(2) to check for this conditions.
One the other hand this is not supported by any other BSD and thus non
standard.

In the tree there's two poll handlers that set the POLLPRI & POLLRDBAND
bits as illustrated by the diff below.

Do we see value in this new type of filter?  Should I document it and
put it in?  Or should I restrict it to the __EV_POLL for now?  In the
latter case should we pick a different name and/or prefix it?

Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.139
diff -u -p -r1.139 kern_event.c
--- kern/kern_event.c   15 Jun 2020 15:42:11 -0000      1.139
+++ kern/kern_event.c   16 Jun 2020 10:32:45 -0000
@@ -158,6 +158,7 @@ const struct filterops *const sysfilt_op
        &sig_filtops,                   /* EVFILT_SIGNAL */
        &timer_filtops,                 /* EVFILT_TIMER */
        &file_filtops,                  /* EVFILT_DEVICE */
+       &file_filtops,                  /* EVFILT_EXCEPT */
 };
 
 void
Index: kern/tty_pty.c
===================================================================
RCS file: /cvs/src/sys/kern/tty_pty.c,v
retrieving revision 1.100
diff -u -p -r1.100 tty_pty.c
--- kern/tty_pty.c      15 Jun 2020 15:29:40 -0000      1.100
+++ kern/tty_pty.c      16 Jun 2020 10:32:45 -0000
@@ -107,6 +107,7 @@ void        filt_ptcrdetach(struct knote *);
 int    filt_ptcread(struct knote *, long);
 void   filt_ptcwdetach(struct knote *);
 int    filt_ptcwrite(struct knote *, long);
+int    filt_ptcexcept(struct knote *, long);
 
 static struct pt_softc **ptyarralloc(int);
 static int check_pty(int);
@@ -719,6 +720,23 @@ filt_ptcwrite(struct knote *kn, long hin
        return (kn->kn_data > 0);
 }
 
+int
+filt_ptcexcept(struct knote *kn, long hint)
+{
+       struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
+       struct tty *tp;
+
+       tp = pti->pt_tty;
+       kn->kn_data = 0;
+
+       /* If in packet or user control mode, check for data. */
+       if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
+           ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
+               kn->kn_data = 1;
+
+       return (kn->kn_data > 0);
+}
+
 const struct filterops ptcread_filtops = {
        .f_flags        = FILTEROP_ISFD,
        .f_attach       = NULL,
@@ -733,6 +751,13 @@ const struct filterops ptcwrite_filtops 
        .f_event        = filt_ptcwrite,
 };
 
+const struct filterops ptcexcept_filtops = {
+       .f_flags        = FILTEROP_ISFD,
+       .f_attach       = NULL,
+       .f_detach       = filt_ptcrdetach,
+       .f_event        = filt_ptcexcept,
+};
+
 int
 ptckqfilter(dev_t dev, struct knote *kn)
 {
@@ -749,6 +774,9 @@ ptckqfilter(dev_t dev, struct knote *kn)
                klist = &pti->pt_selw.si_note;
                kn->kn_fop = &ptcwrite_filtops;
                break;
+       case EVFILT_EXCEPT:
+               klist = &pti->pt_selr.si_note;
+               kn->kn_fop = &ptcexcept_filtops;
        default:
                return (EINVAL);
        }
Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.245
diff -u -p -r1.245 uipc_socket.c
--- kern/uipc_socket.c  15 Jun 2020 15:29:40 -0000      1.245
+++ kern/uipc_socket.c  16 Jun 2020 10:32:45 -0000
@@ -71,6 +71,7 @@ int   filt_soread(struct knote *kn, long h
 void   filt_sowdetach(struct knote *kn);
 int    filt_sowrite(struct knote *kn, long hint);
 int    filt_solisten(struct knote *kn, long hint);
+int    filt_soexcept(struct knote *kn, long hint);
 
 const struct filterops solisten_filtops = {
        .f_flags        = FILTEROP_ISFD,
@@ -93,6 +94,12 @@ const struct filterops sowrite_filtops =
        .f_event        = filt_sowrite,
 };
 
+const struct filterops soexcept_filtops = {
+       .f_flags        = FILTEROP_ISFD,
+       .f_attach       = NULL,
+       .f_detach       = filt_sordetach,
+       .f_event        = filt_soexcept,
+};
 
 #ifndef SOMINCONN
 #define SOMINCONN 80
@@ -2026,6 +2033,10 @@ soo_kqfilter(struct file *fp, struct kno
                kn->kn_fop = &sowrite_filtops;
                sb = &so->so_snd;
                break;
+       case EVFILT_EXCEPT:
+               kn->kn_fop = &soexcept_filtops;
+               sb = &so->so_rcv;
+               break;
        default:
                return (EINVAL);
        }
@@ -2137,6 +2148,21 @@ filt_solisten(struct knote *kn, long hin
        if ((hint & NOTE_SUBMIT) == 0)
                s = solock(so);
        kn->kn_data = so->so_qlen;
+       if ((hint & NOTE_SUBMIT) == 0)
+               sounlock(so, s);
+
+       return (kn->kn_data != 0);
+}
+
+int
+filt_soexcept(struct knote *kn, long hint)
+{
+       struct socket *so = kn->kn_fp->f_data;
+       int s;
+
+       if ((hint & NOTE_SUBMIT) == 0)
+               s = solock(so);
+       kn->kn_data = (so->so_oobmark || (so->so_state & SS_RCVATMARK));
        if ((hint & NOTE_SUBMIT) == 0)
                sounlock(so, s);
 
Index: sys/event.h
===================================================================
RCS file: /cvs/src/sys/sys/event.h,v
retrieving revision 1.43
diff -u -p -r1.43 event.h
--- sys/event.h 15 Jun 2020 15:42:11 -0000      1.43
+++ sys/event.h 16 Jun 2020 10:32:45 -0000
@@ -39,6 +39,7 @@
 #define EVFILT_SIGNAL          (-6)    /* attached to struct process */
 #define EVFILT_TIMER           (-7)    /* timers */
 #define EVFILT_DEVICE          (-8)    /* devices */
+#define EVFILT_EXCEPT          (-9)    /* exceptional conditions */
 
 #define EVFILT_SYSCOUNT                8
 

Reply via email to