Use per 'wseventvar' structure `mtx' mutex(9) to protect `put' and `get'
circular buffer indexes together with klist data. Not a big deal, but
Xorg will not kernel lock while polling keyboard and mouse events. Also
removed obsolete selinfo. 

Feedback, objections, oks?

Not related to this diff, but since 'wseventvar' members are not private
to wscons/wsevent.c, does it make sense to add ws_ or wse_ prefix to
them?

Index: sys/dev/wscons/wsevent.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsevent.c,v
retrieving revision 1.27
diff -u -p -r1.27 wsevent.c
--- sys/dev/wscons/wsevent.c    6 Jul 2023 10:16:58 -0000       1.27
+++ sys/dev/wscons/wsevent.c    11 Jul 2023 13:36:26 -0000
@@ -85,12 +85,16 @@
 
 void   filt_wseventdetach(struct knote *);
 int    filt_wseventread(struct knote *, long);
+int    filt_wseventmodify(struct kevent *, struct knote *);
+int    filt_wseventprocess(struct knote *, struct kevent *);
 
 const struct filterops wsevent_filtops = {
-       .f_flags        = FILTEROP_ISFD,
+       .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_wseventdetach,
        .f_event        = filt_wseventread,
+       .f_modify       = filt_wseventmodify,
+       .f_process      = filt_wseventprocess,
 };
 
 /*
@@ -114,6 +118,8 @@ wsevent_init(struct wseventvar *ev)
        ev->q = queue;
        ev->get = ev->put = 0;
 
+       mtx_init_flags(&ev->mtx, IPL_MPFLOOR, "wsevmtx", 0);
+       klist_init_mutex(&ev->klist, &ev->mtx);
        sigio_init(&ev->sigio);
 
        return (0);
@@ -134,7 +140,7 @@ wsevent_fini(struct wseventvar *ev)
        free(ev->q, M_DEVBUF, WSEVENT_QSIZE * sizeof(struct wscons_event));
        ev->q = NULL;
 
-       klist_invalidate(&ev->sel.si_note);
+       klist_invalidate(&ev->klist);
 
        sigio_free(&ev->sigio);
 }
@@ -146,8 +152,8 @@ wsevent_fini(struct wseventvar *ev)
 int
 wsevent_read(struct wseventvar *ev, struct uio *uio, int flags)
 {
-       int s, error;
-       u_int cnt;
+       int error, notwrap = 0;
+       u_int cnt, tcnt, get;
        size_t n;
 
        /*
@@ -155,17 +161,19 @@ wsevent_read(struct wseventvar *ev, stru
         */
        if (uio->uio_resid < sizeof(struct wscons_event))
                return (EMSGSIZE);      /* ??? */
-       s = splwsevent();
+
+       mtx_enter(&ev->mtx);
+
        while (ev->get == ev->put) {
                if (flags & IO_NDELAY) {
-                       splx(s);
+                       mtx_leave(&ev->mtx);
                        return (EWOULDBLOCK);
                }
                ev->wanted = 1;
-               error = tsleep_nsec(ev, PWSEVENT | PCATCH,
+               error = msleep_nsec(ev, &ev->mtx, PWSEVENT | PCATCH,
                    "wsevent_read", INFSLP);
                if (error) {
-                       splx(s);
+                       mtx_leave(&ev->mtx);
                        return (error);
                }
        }
@@ -177,37 +185,43 @@ wsevent_read(struct wseventvar *ev, stru
                cnt = WSEVENT_QSIZE - ev->get;  /* events in [get..QSIZE) */
        else
                cnt = ev->put - ev->get;        /* events in [get..put) */
-       splx(s);
+
        n = howmany(uio->uio_resid, sizeof(struct wscons_event));
        if (cnt > n)
                cnt = n;
-       error = uiomove((caddr_t)&ev->q[ev->get],
-           cnt * sizeof(struct wscons_event), uio);
+
+       get = ev->get;
+       tcnt = ev->put;
        n -= cnt;
+
+       if ((ev->get = (ev->get + cnt) % WSEVENT_QSIZE) != 0 || n == 0 ||
+           tcnt == 0) {
+               notwrap = 1;
+       } else {
+               if (tcnt > n)
+                       tcnt = n;
+               ev->get = tcnt;
+       }
+
+       mtx_leave(&ev->mtx);
+
+       error = uiomove((caddr_t)&ev->q[get],
+           cnt * sizeof(struct wscons_event), uio);
        /*
         * If we do not wrap to 0, used up all our space, or had an error,
         * stop.  Otherwise move from front of queue to put index, if there
         * is anything there to move.
         */
-       if ((ev->get = (ev->get + cnt) % WSEVENT_QSIZE) != 0 ||
-           n == 0 || error || (cnt = ev->put) == 0)
+       if (notwrap || error)
                return (error);
-       if (cnt > n)
-               cnt = n;
        error = uiomove((caddr_t)&ev->q[0],
-           cnt * sizeof(struct wscons_event), uio);
-       ev->get = cnt;
+           tcnt * sizeof(struct wscons_event), uio);
        return (error);
 }
 
 int
 wsevent_kqfilter(struct wseventvar *ev, struct knote *kn)
 {
-       struct klist *klist;
-       int s;
-
-       klist = &ev->sel.si_note;
-
        switch (kn->kn_filter) {
        case EVFILT_READ:
                kn->kn_fop = &wsevent_filtops;
@@ -217,10 +231,7 @@ wsevent_kqfilter(struct wseventvar *ev, 
        }
 
        kn->kn_hook = ev;
-
-       s = splwsevent();
-       klist_insert_locked(klist, kn);
-       splx(s);
+       klist_insert(&ev->klist, kn);
 
        return (0);
 }
@@ -229,12 +240,8 @@ void
 filt_wseventdetach(struct knote *kn)
 {
        struct wseventvar *ev = kn->kn_hook;
-       struct klist *klist = &ev->sel.si_note;
-       int s;
 
-       s = splwsevent();
-       klist_remove_locked(klist, kn);
-       splx(s);
+       klist_remove(&ev->klist, kn);
 }
 
 int
@@ -242,6 +249,8 @@ filt_wseventread(struct knote *kn, long 
 {
        struct wseventvar *ev = kn->kn_hook;
 
+       MUTEX_ASSERT_LOCKED(&ev->mtx);
+
        if (ev->get == ev->put)
                return (0);
 
@@ -251,4 +260,30 @@ filt_wseventread(struct knote *kn, long 
                kn->kn_data = (WSEVENT_QSIZE - ev->get) + ev->put;
 
        return (1);
+}
+
+int
+filt_wseventmodify(struct kevent *kev, struct knote *kn)
+{
+       struct wseventvar *ev = kn->kn_hook;
+       int active;
+
+       mtx_enter(&ev->mtx);
+       active = knote_modify(kev, kn);
+       mtx_leave(&ev->mtx);
+
+       return (active);
+}
+
+int
+filt_wseventprocess(struct knote *kn, struct kevent *kev)
+{
+       struct wseventvar *ev = kn->kn_hook;
+       int active;
+
+       mtx_enter(&ev->mtx);
+       active = knote_process(kn, kev);
+       mtx_leave(&ev->mtx);
+
+       return (active);
 }
Index: sys/dev/wscons/wseventvar.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wseventvar.h,v
retrieving revision 1.11
diff -u -p -r1.11 wseventvar.h
--- sys/dev/wscons/wseventvar.h 2 Jul 2022 08:50:42 -0000       1.11
+++ sys/dev/wscons/wseventvar.h 11 Jul 2023 13:36:26 -0000
@@ -71,7 +71,9 @@
  *     @(#)event_var.h 8.1 (Berkeley) 6/11/93
  */
 
+#include <sys/mutex.h>
 #include <sys/sigio.h>
+#include <sys/signalvar.h>
 
 /*
  * Internal "wscons_event" queue interface for the keyboard and mouse drivers.
@@ -83,25 +85,29 @@
 #define        WSEVENT_QSIZE   256     /* may need tuning; this uses 2k */
 
 struct wseventvar {
+       struct mutex mtx;
        u_int   get;            /* get (read) index (modified synchronously) */
        volatile u_int put;     /* put (write) index (modified by interrupt) */
-       struct selinfo sel;     /* process selecting */
+       struct klist klist;     /* process selecting */
        struct sigio_ref sigio; /* async I/O registration */
        int     wanted;         /* wake up on input ready */
        int     async;          /* send SIGIO on input ready */
        struct wscons_event *q; /* circular buffer (queue) of events */
 };
 
-#define        splwsevent()    spltty()
+static inline void
+wsevent_wakeup(struct wseventvar *ev)
+{
+       MUTEX_ASSERT_LOCKED(&ev->mtx);
 
-#define        WSEVENT_WAKEUP(ev) { \
-       selwakeup(&(ev)->sel); \
-       if ((ev)->wanted) { \
-               (ev)->wanted = 0; \
-               wakeup((caddr_t)(ev)); \
-       } \
-       if ((ev)->async) \
-               pgsigio(&(ev)->sigio, SIGIO, 0); \
+       knote_locked(&ev->klist, 0);
+
+       if (ev->wanted) {
+               ev->wanted = 0;
+               wakeup((caddr_t)ev);
+       }
+       if (ev->async)
+               pgsigio(&ev->sigio, SIGIO, 0);
 }
 
 int    wsevent_init(struct wseventvar *);
Index: sys/dev/wscons/wskbd.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wskbd.c,v
retrieving revision 1.115
diff -u -p -r1.115 wskbd.c
--- sys/dev/wscons/wskbd.c      9 Jul 2023 08:02:14 -0000       1.115
+++ sys/dev/wscons/wskbd.c      11 Jul 2023 13:36:26 -0000
@@ -637,10 +637,12 @@ wskbd_detach(struct device  *self, int f
        if (evar != NULL) {
                s = spltty();
                if (--sc->sc_refcnt >= 0) {
+                       mtx_enter(&evar->mtx);
                        /* Wake everyone by generating a dummy event. */
                        if (++evar->put >= WSEVENT_QSIZE)
                                evar->put = 0;
-                       WSEVENT_WAKEUP(evar);
+                       wsevent_wakeup(evar);
+                       mtx_leave(&evar->mtx);
                        /* Wait for processes to go away. */
                        if (tsleep_nsec(sc, PZERO, "wskdet", SEC_TO_NSEC(60)))
                                printf("wskbd_detach: %s didn't detach\n",
@@ -751,10 +753,12 @@ wskbd_deliver_event(struct wskbd_softc *
        }
 #endif
 
+       mtx_enter(&evar->mtx);
        put = evar->put;
        ev = &evar->q[put];
        put = (put + 1) % WSEVENT_QSIZE;
        if (put == evar->get) {
+               mtx_leave(&evar->mtx);
                log(LOG_WARNING, "%s: event queue overflow\n",
                    sc->sc_base.me_dv.dv_xname);
                return;
@@ -763,7 +767,8 @@ wskbd_deliver_event(struct wskbd_softc *
        ev->value = value;
        nanotime(&ev->time);
        evar->put = put;
-       WSEVENT_WAKEUP(evar);
+       wsevent_wakeup(evar);
+       mtx_leave(&evar->mtx);
 }
 
 #ifdef WSDISPLAY_COMPAT_RAWKBD
Index: sys/dev/wscons/wsmouse.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.70
diff -u -p -r1.70 wsmouse.c
--- sys/dev/wscons/wsmouse.c    16 Oct 2022 18:23:44 -0000      1.70
+++ sys/dev/wscons/wsmouse.c    11 Jul 2023 13:36:26 -0000
@@ -264,10 +264,12 @@ wsmouse_detach(struct device *self, int 
        if (evar != NULL) {
                s = spltty();
                if (--sc->sc_refcnt >= 0) {
+                       mtx_enter(&evar->mtx);
                        /* Wake everyone by generating a dummy event. */
                        if (++evar->put >= WSEVENT_QSIZE)
                                evar->put = 0;
-                       WSEVENT_WAKEUP(evar);
+                       wsevent_wakeup(evar);
+                       mtx_leave(&evar->mtx);
                        /* Wait for processes to go away. */
                        if (tsleep_nsec(sc, PZERO, "wsmdet", SEC_TO_NSEC(60)))
                                printf("wsmouse_detach: %s didn't detach\n",
@@ -953,7 +955,7 @@ wsmouse_mt_convert(struct device *sc)
 }
 
 void
-wsmouse_evq_put(struct evq_access *evq, int ev_type, int ev_value)
+wsmouse_evq_put_locked(struct evq_access *evq, int ev_type, int ev_value)
 {
        struct wscons_event *ev;
        int space;
@@ -971,6 +973,13 @@ wsmouse_evq_put(struct evq_access *evq, 
        }
 }
 
+void
+wsmouse_evq_put(struct evq_access *evq, int ev_type, int ev_value)
+{
+       mtx_enter(&evq->evar->mtx);
+       wsmouse_evq_put_locked(evq, ev_type, ev_value);
+       mtx_leave(&evq->evar->mtx);
+}
 
 void
 wsmouse_btn_sync(struct btn_state *btn, struct evq_access *evq)
@@ -1141,7 +1150,9 @@ wsmouse_input_sync(struct device *sc)
        evq.evar = *input->evar;
        if (evq.evar == NULL)
                return;
+       mtx_enter(&evq.evar->mtx);
        evq.put = evq.evar->put;
+       mtx_leave(&evq.evar->mtx);
        evq.result = EVQ_RESULT_NONE;
        getnanotime(&evq.ts);
 
@@ -1179,14 +1190,16 @@ wsmouse_input_sync(struct device *sc)
        /* No MT events are generated yet. */
 
        if (evq.result == EVQ_RESULT_SUCCESS) {
-               wsmouse_evq_put(&evq, WSCONS_EVENT_SYNC, 0);
+               mtx_enter(&evq.evar->mtx);
+               wsmouse_evq_put_locked(&evq, WSCONS_EVENT_SYNC, 0);
                if (evq.result == EVQ_RESULT_SUCCESS) {
                        if (input->flags & LOG_EVENTS) {
                                wsmouse_log_events(input, &evq);
                        }
                        evq.evar->put = evq.put;
-                       WSEVENT_WAKEUP(evq.evar);
+                       wsevent_wakeup(evq.evar);
                }
+               mtx_leave(&evq.evar->mtx);
        }
 
        if (evq.result != EVQ_RESULT_OVERFLOW)
Index: sys/dev/wscons/wsmouseinput.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouseinput.h,v
retrieving revision 1.15
diff -u -p -r1.15 wsmouseinput.h
--- sys/dev/wscons/wsmouseinput.h       21 Mar 2021 16:20:49 -0000      1.15
+++ sys/dev/wscons/wsmouseinput.h       11 Jul 2023 13:36:26 -0000
@@ -184,6 +184,7 @@ struct evq_access {
 
 
 void wsmouse_evq_put(struct evq_access *, int, int);
+void wsmouse_evq_put_locked(struct evq_access *, int, int);
 void wsmouse_log_events(struct wsmouseinput *, struct evq_access *);
 int wsmouse_hysteresis(struct wsmouseinput *, struct position *);
 void wsmouse_input_reset(struct wsmouseinput *);
Index: sys/dev/wscons/wsmux.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmux.c,v
retrieving revision 1.56
diff -u -p -r1.56 wsmux.c
--- sys/dev/wscons/wsmux.c      2 Jul 2022 08:50:42 -0000       1.56
+++ sys/dev/wscons/wsmux.c      11 Jul 2023 13:36:26 -0000
@@ -385,7 +385,7 @@ wsmux_do_ioctl(struct device *dv, u_long
        struct wsmux_softc *sc = (struct wsmux_softc *)dv;
        struct wsevsrc *me;
        int error, ok;
-       int s, put, get, n;
+       int put, get, n;
        struct wseventvar *evar;
        struct wscons_event *ev;
        struct wsmux_device_list *l;
@@ -415,13 +415,12 @@ wsmux_do_ioctl(struct device *dv, u_long
                        return (0);
                }
 
-               s = spltty();
+               mtx_enter(&evar->mtx);
                get = evar->get;
                put = evar->put;
                ev = &evar->q[put];
                if (++put % WSEVENT_QSIZE == get) {
-                       put--;
-                       splx(s);
+                       mtx_leave(&evar->mtx);
                        return (ENOSPC);
                }
                if (put >= WSEVENT_QSIZE)
@@ -429,8 +428,9 @@ wsmux_do_ioctl(struct device *dv, u_long
                *ev = *(struct wscons_event *)data;
                nanotime(&ev->time);
                evar->put = put;
-               WSEVENT_WAKEUP(evar);
-               splx(s);
+               wsevent_wakeup(evar);
+               mtx_leave(&evar->mtx);
+
                return (0);
        case WSMUXIO_ADD_DEVICE:
 #define d ((struct wsmux_device *)data)
Index: sys/dev/wscons/wstpad.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v
retrieving revision 1.32
diff -u -p -r1.32 wstpad.c
--- sys/dev/wscons/wstpad.c     2 Jul 2023 21:44:04 -0000       1.32
+++ sys/dev/wscons/wstpad.c     11 Jul 2023 13:36:26 -0000
@@ -931,20 +931,22 @@ wstpad_tap_timeout(void *p)
                        tp->tap.state = TAP_DETECT;
                }
                if (ev) {
+                       mtx_enter(&evq.evar->mtx);
                        evq.put = evq.evar->put;
                        evq.result = EVQ_RESULT_NONE;
                        getnanotime(&evq.ts);
-                       wsmouse_evq_put(&evq, ev, btn);
-                       wsmouse_evq_put(&evq, SYNC_EV, 0);
+                       wsmouse_evq_put_locked(&evq, ev, btn);
+                       wsmouse_evq_put_locked(&evq, SYNC_EV, 0);
                        if (evq.result == EVQ_RESULT_SUCCESS) {
                                if (input->flags & LOG_EVENTS) {
                                        wsmouse_log_events(input, &evq);
                                }
                                evq.evar->put = evq.put;
-                               WSEVENT_WAKEUP(evq.evar);
+                               wsevent_wakeup(evq.evar);
                        } else {
                                input->sbtn.sync |= tp->tap.button;
                        }
+                       mtx_leave(&evq.evar->mtx);
                }
        }
        splx(s);

Reply via email to