Make EVFILT_EXCEPT handling separate from the read filter.
authormpi <mpi@openbsd.org>
Fri, 22 Oct 2021 15:11:32 +0000 (15:11 +0000)
committermpi <mpi@openbsd.org>
Fri, 22 Oct 2021 15:11:32 +0000 (15:11 +0000)
This is a change of behavior and events wont be generated if there
is something to read on the fd.  Only EV_EOF or NOTE_OOB will now
be reported.

While here a new filter for FIFOs supporting EV_EOF and __EV_HUP.

ok visa@

sys/kern/tty_pty.c
sys/kern/uipc_socket.c
sys/miscfs/fifofs/fifo_vnops.c

index 660a2e8..42eb39e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tty_pty.c,v 1.108 2021/02/08 09:18:30 claudio Exp $   */
+/*     $OpenBSD: tty_pty.c,v 1.109 2021/10/22 15:11:32 mpi Exp $       */
 /*     $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $     */
 
 /*
@@ -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);
@@ -670,16 +671,6 @@ filt_ptcread(struct knote *kn, long hint)
        tp = pti->pt_tty;
        kn->kn_data = 0;
 
-       if (kn->kn_sfflags & NOTE_OOB) {
-               /* 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_fflags |= NOTE_OOB;
-                       kn->kn_data = 1;
-                       return (1);
-               }
-               return (0);
-       }
        if (ISSET(tp->t_state, TS_ISOPEN)) {
                if (!ISSET(tp->t_state, TS_TTSTOP))
                        kn->kn_data = tp->t_outq.c_cc;
@@ -731,6 +722,34 @@ filt_ptcwrite(struct knote *kn, long hint)
        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;
+
+       if (kn->kn_sfflags & NOTE_OOB) {
+               /* 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_fflags |= NOTE_OOB;
+                       kn->kn_data = 1;
+                       return (1);
+               }
+               return (0);
+       }
+       if (!ISSET(tp->t_state, TS_CARR_ON)) {
+               kn->kn_flags |= EV_EOF;
+               if (kn->kn_flags & __EV_POLL)
+                       kn->kn_flags |= __EV_HUP;
+               return (1);
+       }
+
+       return (0);
+}
+
 const struct filterops ptcread_filtops = {
        .f_flags        = FILTEROP_ISFD,
        .f_attach       = NULL,
@@ -749,7 +768,7 @@ const struct filterops ptcexcept_filtops = {
        .f_flags        = FILTEROP_ISFD,
        .f_attach       = NULL,
        .f_detach       = filt_ptcrdetach,
-       .f_event        = filt_ptcread,
+       .f_event        = filt_ptcexcept,
 };
 
 int
index 7b855ad..afab85d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_socket.c,v 1.265 2021/10/14 23:05:10 mvs Exp $   */
+/*     $OpenBSD: uipc_socket.c,v 1.266 2021/10/22 15:11:32 mpi Exp $   */
 /*     $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $        */
 
 /*
@@ -78,6 +78,10 @@ int  filt_sowrite(struct knote *kn, long hint);
 int    filt_sowritemodify(struct kevent *kev, struct knote *kn);
 int    filt_sowriteprocess(struct knote *kn, struct kevent *kev);
 int    filt_sowrite_common(struct knote *kn, struct socket *so);
+int    filt_soexcept(struct knote *kn, long hint);
+int    filt_soexceptmodify(struct kevent *kev, struct knote *kn);
+int    filt_soexceptprocess(struct knote *kn, struct kevent *kev);
+int    filt_soexcept_common(struct knote *kn, struct socket *so);
 int    filt_solisten(struct knote *kn, long hint);
 int    filt_solistenmodify(struct kevent *kev, struct knote *kn);
 int    filt_solistenprocess(struct knote *kn, struct kevent *kev);
@@ -114,9 +118,9 @@ const struct filterops soexcept_filtops = {
        .f_flags        = FILTEROP_ISFD,
        .f_attach       = NULL,
        .f_detach       = filt_sordetach,
-       .f_event        = filt_soread,
-       .f_modify       = filt_soreadmodify,
-       .f_process      = filt_soreadprocess,
+       .f_event        = filt_soexcept,
+       .f_modify       = filt_soexceptmodify,
+       .f_process      = filt_soexceptprocess,
 };
 
 #ifndef SOMINCONN
@@ -2089,13 +2093,7 @@ filt_soread_common(struct knote *kn, struct socket *so)
                rv = 0;
        } else
 #endif /* SOCKET_SPLICE */
-       if (kn->kn_sfflags & NOTE_OOB) {
-               if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
-                       kn->kn_fflags |= NOTE_OOB;
-                       kn->kn_data -= so->so_oobmark;
-                       rv = 1;
-               }
-       } else if (so->so_state & SS_CANTRCVMORE) {
+       if (so->so_state & SS_CANTRCVMORE) {
                kn->kn_flags |= EV_EOF;
                if (kn->kn_flags & __EV_POLL) {
                        if (so->so_state & SS_ISDISCONNECTED)
@@ -2234,6 +2232,77 @@ filt_sowriteprocess(struct knote *kn, struct kevent *kev)
        return (rv);
 }
 
+int
+filt_soexcept_common(struct knote *kn, struct socket *so)
+{
+       int rv = 0;
+
+       soassertlocked(so);
+
+#ifdef SOCKET_SPLICE
+       if (isspliced(so)) {
+               rv = 0;
+       } else
+#endif /* SOCKET_SPLICE */
+       if (kn->kn_sfflags & NOTE_OOB) {
+               if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
+                       kn->kn_fflags |= NOTE_OOB;
+                       kn->kn_data -= so->so_oobmark;
+                       rv = 1;
+               }
+       } else if (so->so_state & SS_CANTRCVMORE) {
+               kn->kn_flags |= EV_EOF;
+               if (kn->kn_flags & __EV_POLL) {
+                       if (so->so_state & SS_ISDISCONNECTED)
+                               kn->kn_flags |= __EV_HUP;
+               }
+               kn->kn_fflags = so->so_error;
+               rv = 1;
+       }
+
+       return rv;
+}
+
+int
+filt_soexcept(struct knote *kn, long hint)
+{
+       struct socket *so = kn->kn_fp->f_data;
+
+       return (filt_soexcept_common(kn, so));
+}
+
+int
+filt_soexceptmodify(struct kevent *kev, struct knote *kn)
+{
+       struct socket *so = kn->kn_fp->f_data;
+       int rv, s;
+
+       s = solock(so);
+       knote_modify(kev, kn);
+       rv = filt_soexcept_common(kn, so);
+       sounlock(so, s);
+
+       return (rv);
+}
+
+int
+filt_soexceptprocess(struct knote *kn, struct kevent *kev)
+{
+       struct socket *so = kn->kn_fp->f_data;
+       int rv, s;
+
+       s = solock(so);
+       if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
+               rv = 1;
+       else
+               rv = filt_soexcept_common(kn, so);
+       if (rv != 0)
+               knote_submit(kn, kev);
+       sounlock(so, s);
+
+       return (rv);
+}
+
 int
 filt_solisten_common(struct knote *kn, struct socket *so)
 {
index 072187f..6aa0c32 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fifo_vnops.c,v 1.82 2021/10/15 06:30:06 semarie Exp $ */
+/*     $OpenBSD: fifo_vnops.c,v 1.83 2021/10/22 15:11:32 mpi Exp $     */
 /*     $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */
 
 /*
@@ -112,6 +112,10 @@ int        filt_fifowrite(struct knote *kn, long hint);
 int    filt_fifowritemodify(struct kevent *kev, struct knote *kn);
 int    filt_fifowriteprocess(struct knote *kn, struct kevent *kev);
 int    filt_fifowrite_common(struct knote *kn, struct socket *so);
+int    filt_fifoexcept(struct knote *kn, long hint);
+int    filt_fifoexceptmodify(struct kevent *kev, struct knote *kn);
+int    filt_fifoexceptprocess(struct knote *kn, struct kevent *kev);
+int    filt_fifoexcept_common(struct knote *kn, struct socket *so);
 
 const struct filterops fiforead_filtops = {
        .f_flags        = FILTEROP_ISFD,
@@ -131,6 +135,15 @@ const struct filterops fifowrite_filtops = {
        .f_process      = filt_fifowriteprocess,
 };
 
+const struct filterops fifoexcept_filtops = {
+       .f_flags        = FILTEROP_ISFD,
+       .f_attach       = NULL,
+       .f_detach       = filt_fifordetach,
+       .f_event        = filt_fifoexcept,
+       .f_modify       = filt_fifoexceptmodify,
+       .f_process      = filt_fifoexceptprocess,
+};
+
 /*
  * Open called to set up a new instance of a fifo or
  * to find an active instance of a fifo.
@@ -522,6 +535,11 @@ fifo_kqfilter(void *v)
                so = fip->fi_writesock;
                sb = &so->so_snd;
                break;
+       case EVFILT_EXCEPT:
+               ap->a_kn->kn_fop = &fifoexcept_filtops;
+               so = fip->fi_readsock;
+               sb = &so->so_rcv;
+               break;
        default:
                return (EINVAL);
        }
@@ -670,3 +688,62 @@ filt_fifowriteprocess(struct knote *kn, struct kevent *kev)
 
        return (rv);
 }
+
+int
+filt_fifoexcept_common(struct knote *kn, struct socket *so)
+{
+       int rv = 0;
+
+       soassertlocked(so);
+
+       if (so->so_state & SS_CANTRCVMORE) {
+               kn->kn_flags |= EV_EOF;
+               if (kn->kn_flags & __EV_POLL) {
+                       if (so->so_state & SS_ISDISCONNECTED)
+                               kn->kn_flags |= __EV_HUP;
+               }
+               rv = 1;
+       }
+
+       return (rv);
+}
+
+int
+filt_fifoexcept(struct knote *kn, long hint)
+{
+       struct socket *so = kn->kn_hook;
+
+       return (filt_fifoexcept_common(kn, so));
+}
+
+int
+filt_fifoexceptmodify(struct kevent *kev, struct knote *kn)
+{
+       struct socket *so = kn->kn_hook;
+       int rv, s;
+
+       s = solock(so);
+       knote_modify(kev, kn);
+       rv = filt_fifoexcept_common(kn, so);
+       sounlock(so, s);
+
+       return (rv);
+}
+
+int
+filt_fifoexceptprocess(struct knote *kn, struct kevent *kev)
+{
+       struct socket *so = kn->kn_hook;
+       int rv, s;
+
+       s = solock(so);
+       if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
+               rv = 1;
+       else
+               rv = filt_fifoexcept_common(kn, so);
+       if (rv != 0)
+               knote_submit(kn, kev);
+       sounlock(so, s);
+
+       return (rv);
+}