Adjust pty and tty event filters
authorvisa <visa@openbsd.org>
Wed, 15 Dec 2021 15:30:47 +0000 (15:30 +0000)
committervisa <visa@openbsd.org>
Wed, 15 Dec 2021 15:30:47 +0000 (15:30 +0000)
* Implement EVFILT_EXCEPT for ttys for HUP condition detection.
  This filter is used when pollfd.events has no read/write events.

* Add HUP condition detection to filt_ptcwrite() and filt_ttywrite()
  to reflect ptcpoll() and ttpoll(). Only poll(2) and select(2) can
  utilize the code; kevent(2) should behave as before with EVFILT_WRITE.

* Clear EV_EOF and __EV_HUP if the EOF/HUP condition ends.

OK mpi@

sys/kern/tty.c
sys/kern/tty_pty.c

index 37e9ab5..ae6cffb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tty.c,v 1.172 2021/12/14 15:32:20 visa Exp $  */
+/*     $OpenBSD: tty.c,v 1.173 2021/12/15 15:30:47 visa Exp $  */
 /*     $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $     */
 
 /*-
@@ -78,6 +78,7 @@ int   filt_ttyread(struct knote *kn, long hint);
 void   filt_ttyrdetach(struct knote *kn);
 int    filt_ttywrite(struct knote *kn, long hint);
 void   filt_ttywdetach(struct knote *kn);
+int    filt_ttyexcept(struct knote *kn, long hint);
 void   ttystats_init(struct itty **, int *, size_t *);
 int    ttywait_nsec(struct tty *, uint64_t);
 int    ttysleep_nsec(struct tty *, void *, int, char *, uint64_t);
@@ -1110,6 +1111,13 @@ const struct filterops ttywrite_filtops = {
        .f_event        = filt_ttywrite,
 };
 
+const struct filterops ttyexcept_filtops = {
+       .f_flags        = FILTEROP_ISFD,
+       .f_attach       = NULL,
+       .f_detach       = filt_ttyrdetach,
+       .f_event        = filt_ttyexcept,
+};
+
 int
 ttkqfilter(dev_t dev, struct knote *kn)
 {
@@ -1126,6 +1134,18 @@ ttkqfilter(dev_t dev, struct knote *kn)
                klist = &tp->t_wsel.si_note;
                kn->kn_fop = &ttywrite_filtops;
                break;
+       case EVFILT_EXCEPT:
+               if (kn->kn_flags & __EV_SELECT) {
+                       /* Prevent triggering exceptfds. */
+                       return (EPERM);
+               }
+               if ((kn->kn_flags & __EV_POLL) == 0) {
+                       /* Disallow usage through kevent(2). */
+                       return (EINVAL);
+               }
+               klist = &tp->t_rsel.si_note;
+               kn->kn_fop = &ttyexcept_filtops;
+               break;
        default:
                return (EINVAL);
        }
@@ -1164,6 +1184,8 @@ filt_ttyread(struct knote *kn, long hint)
                if (kn->kn_flags & __EV_POLL)
                        kn->kn_flags |= __EV_HUP;
                active = 1;
+       } else {
+               kn->kn_flags &= ~(EV_EOF | __EV_HUP);
        }
        splx(s);
        return (active);
@@ -1184,13 +1206,45 @@ int
 filt_ttywrite(struct knote *kn, long hint)
 {
        struct tty *tp = kn->kn_hook;
-       int canwrite, s;
+       int active, s;
 
        s = spltty();
        kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc;
-       canwrite = (tp->t_outq.c_cc <= tp->t_lowat);
+       active = (tp->t_outq.c_cc <= tp->t_lowat);
+
+       /* Write-side HUP condition is only for poll(2) and select(2). */
+       if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
+               if (!ISSET(tp->t_cflag, CLOCAL) &&
+                   !ISSET(tp->t_state, TS_CARR_ON)) {
+                       kn->kn_flags |= __EV_HUP;
+                       active = 1;
+               } else {
+                       kn->kn_flags &= ~__EV_HUP;
+               }
+       }
+       splx(s);
+       return (active);
+}
+
+int
+filt_ttyexcept(struct knote *kn, long hint)
+{
+       struct tty *tp = kn->kn_hook;
+       int active = 0;
+       int s;
+
+       s = spltty();
+       if (kn->kn_flags & __EV_POLL) {
+               if (!ISSET(tp->t_cflag, CLOCAL) &&
+                   !ISSET(tp->t_state, TS_CARR_ON)) {
+                       kn->kn_flags |= __EV_HUP;
+                       active = 1;
+               } else {
+                       kn->kn_flags &= ~__EV_HUP;
+               }
+       }
        splx(s);
-       return (canwrite);
+       return (active);
 }
 
 static int
index f719155..684b540 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tty_pty.c,v 1.111 2021/12/13 14:56:55 visa Exp $      */
+/*     $OpenBSD: tty_pty.c,v 1.112 2021/12/15 15:30:47 visa Exp $      */
 /*     $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $     */
 
 /*
@@ -667,6 +667,7 @@ filt_ptcread(struct knote *kn, long hint)
 {
        struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
        struct tty *tp;
+       int active;
 
        tp = pti->pt_tty;
        kn->kn_data = 0;
@@ -678,15 +679,18 @@ filt_ptcread(struct knote *kn, long hint)
                    ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
                        kn->kn_data++;
        }
+       active = (kn->kn_data > 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);
+               active = 1;
+       } else {
+               kn->kn_flags &= ~(EV_EOF | __EV_HUP);
        }
 
-       return (kn->kn_data > 0);
+       return (active);
 }
 
 void
@@ -705,6 +709,7 @@ filt_ptcwrite(struct knote *kn, long hint)
 {
        struct pt_softc *pti = (struct pt_softc *)kn->kn_hook;
        struct tty *tp;
+       int active;
 
        tp = pti->pt_tty;
        kn->kn_data = 0;
@@ -718,8 +723,19 @@ filt_ptcwrite(struct knote *kn, long hint)
                        kn->kn_data = tp->t_canq.c_cn -
                            (tp->t_rawq.c_cc + tp->t_canq.c_cc);
        }
+       active = (kn->kn_data > 0);
 
-       return (kn->kn_data > 0);
+       /* Write-side HUP condition is only for poll(2) and select(2). */
+       if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
+               if (!ISSET(tp->t_state, TS_CARR_ON)) {
+                       kn->kn_flags |= __EV_HUP;
+                       active = 1;
+               } else {
+                       kn->kn_flags &= ~__EV_HUP;
+               }
+       }
+
+       return (active);
 }
 
 int
@@ -745,6 +761,8 @@ filt_ptcexcept(struct knote *kn, long hint)
                if (!ISSET(tp->t_state, TS_CARR_ON)) {
                        kn->kn_flags |= __EV_HUP;
                        active = 1;
+               } else {
+                       kn->kn_flags &= ~__EV_HUP;
                }
        }