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