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.