From: Visa Hankala Subject: kqueue: EVFILT_USER fixes To: tech@openbsd.org Date: Sun, 18 May 2025 17:21:14 +0000 The EVFILT_USER implementation does not quite align with FreeBSD. One difference is that FreeBSD updates the `data' and `udata' fields when a user event is triggered. FreeBSD also preserves `fflags' when the event is "untriggered". The diff below fixes these. In addition, use kn_sfflags and kn_sdata instead of kn_fflags and kn_data to make the implementation a bit more similar to FreeBSD. OK? Index: sys/kern/kern_event.c =================================================================== RCS file: src/sys/kern/kern_event.c,v retrieving revision 1.204 diff -u -p -r1.204 kern_event.c --- sys/kern/kern_event.c 15 May 2025 19:56:08 -0000 1.204 +++ sys/kern/kern_event.c 18 May 2025 17:17:04 -0000 @@ -809,8 +809,6 @@ filt_userattach(struct knote *kn) } kn->kn_ptr.p_useract = ((kn->kn_sfflags & NOTE_TRIGGER) != 0); - kn->kn_fflags = kn->kn_sfflags & NOTE_FFLAGSMASK; - kn->kn_data = kn->kn_sdata; return (0); } @@ -837,29 +835,25 @@ filt_usermodify(struct kevent *kev, stru case NOTE_FFNOP: break; case NOTE_FFAND: - kn->kn_fflags &= fflags; + kn->kn_sfflags &= fflags; break; case NOTE_FFOR: - kn->kn_fflags |= fflags; + kn->kn_sfflags |= fflags; break; case NOTE_FFCOPY: - kn->kn_fflags = fflags; + kn->kn_sfflags = fflags; break; default: /* ignored, should not happen */ break; } - if (kev->flags & EV_ADD) { - kn->kn_data = kev->data; - kn->kn_udata = kev->udata; - } + kn->kn_sdata = kev->data; + kn->kn_udata = kev->udata; /* Allow clearing of an activated event. */ - if (kev->flags & EV_CLEAR) { + if (kev->flags & EV_CLEAR) kn->kn_ptr.p_useract = 0; - kn->kn_data = 0; - } return (kn->kn_ptr.p_useract); } @@ -872,11 +866,10 @@ filt_userprocess(struct knote *kn, struc active = kn->kn_ptr.p_useract; if (active && kev != NULL) { *kev = kn->kn_kevent; - if (kn->kn_flags & EV_CLEAR) { + kev->fflags = kn->kn_sfflags & NOTE_FFLAGSMASK; + kev->data = kn->kn_sdata; + if (kn->kn_flags & EV_CLEAR) kn->kn_ptr.p_useract = 0; - kn->kn_fflags = 0; - kn->kn_data = 0; - } } return (active); Index: regress/sys/kern/kqueue/kqueue-user.c =================================================================== RCS file: src/regress/sys/kern/kqueue/kqueue-user.c,v retrieving revision 1.1 diff -u -p -r1.1 kqueue-user.c --- regress/sys/kern/kqueue/kqueue-user.c 10 May 2025 09:44:39 -0000 1.1 +++ regress/sys/kern/kqueue/kqueue-user.c 18 May 2025 17:17:04 -0000 @@ -44,10 +44,7 @@ do_user(void) n = kevent(kq, NULL, 0, kev, 2, &ts); ASSX(n == 0); - /* - * Activate the event. - * Fields `data' and `udata' do not get updated without EV_ADD. - */ + /* Activate the event. This updates `data' and `udata'. */ EV_SET(&kev[0], 1, EVFILT_USER, 0, NOTE_TRIGGER | NOTE_FFNOP, 123, &dummy); n = kevent(kq, kev, 1, NULL, 0, NULL); @@ -58,20 +55,6 @@ do_user(void) ASSX(n == 1); ASSX(kev[0].ident == 1); ASSX(kev[0].fflags == NOTE_FFLAGSMASK); - ASSX(kev[0].data == 0); - ASSX(kev[0].udata == NULL); - - /* Activate the event. Update `data' and `udata'. */ - EV_SET(&kev[0], 1, EVFILT_USER, EV_ADD, NOTE_TRIGGER | NOTE_FFNOP, - 123, &dummy); - n = kevent(kq, kev, 1, NULL, 0, NULL); - ASSX(n == 0); - - /* Check active events. */ - n = kevent(kq, NULL, 0, kev, 2, &ts); - ASSX(n == 1); - ASSX(kev[0].ident == 1); - ASSX(kev[0].fflags == NOTE_FFLAGSMASK); ASSX(kev[0].data == 123); ASSX(kev[0].udata == &dummy); @@ -122,8 +105,8 @@ do_user(void) ASSX(n == 1); ASSX(kev[0].ident == 2); ASSX(kev[0].fflags == 0x11); - ASSX(kev[0].data == 42); - ASSX(kev[0].udata == &dummy); + ASSX(kev[0].data == 24); + ASSX(kev[0].udata == &dummy2); n = kevent(kq, NULL, 0, kev, 2, &ts); ASSX(n == 0); @@ -132,9 +115,9 @@ do_user(void) n = kevent(kq, kev, 1, kev, 2, &ts); ASSX(n == 1); ASSX(kev[0].ident == 2); - ASSX(kev[0].fflags == 0); - ASSX(kev[0].data == 0); - ASSX(kev[0].udata == &dummy); + ASSX(kev[0].fflags == 0x11); + ASSX(kev[0].data == 9); + ASSX(kev[0].udata == &dummy2); EV_SET(&kev[0], 2, EVFILT_USER, EV_DELETE, 0, 0, NULL); n = kevent(kq, kev, 1, kev, 2, &ts); @@ -154,7 +137,7 @@ do_user(void) ASSX(kev[0].ident == 1); ASSX(kev[0].fflags == 0x0faaf0); ASSX(kev[0].data == 0); - ASSX(kev[0].udata == &dummy); + ASSX(kev[0].udata == NULL); /* Test event limit. */ for (i = 0;; i++) {