On 2023 Jul 11 (Tue) at 16:40:32 +0300 (+0300), Vitaliy Makkoveev wrote:
: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?
:

Brief testing on amd64 laptop, with some games and some network and
compiles happening.  Seems fine so far.


: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);
:

-- 
Mosher's Law of Software Engineering:
        Don't worry if it doesn't work right.
        If everything did, you'd be out of a job.

Reply via email to