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