Download raw body.
EVFILT_USER and kevent(2)
On Sat, Apr 30, 2022 at 01:51:16PM +0000, Visa Hankala wrote:
> It has been asked in the past if OpenBSD's kevent(2) should implement
> user event filters, also known as EVFILT_USER. This filter type
> originates from FreeBSD but is now available also on DragonFly BSD,
> NetBSD, and macOS.
>
> Below is an implementation of EVFILT_USER. The logic should be fairly
> straightforward. However, the filter type needs a special case in
> kqueue_register() to allow triggering a previously registered user
> event without using EV_ADD.
>
> The code limits the number of user events. Otherwise the user could
> allocate copious amounts of kernel memory. The limit is per process
> so that programs will not interfere with each other. The current limit
> is arbitrary and might need adjusting later. Hopefully a sysctl knob
> will not be necessary.
>
> I am in two minds about EVFILT_USER. On the one hand, having it on
> OpenBSD might help with ports. On the other hand, it makes the kernel
> perform a task that userspace can already handle using existing
> interfaces.
I wonder if there is more interest in EVFILT_USER now.
Here is a refreshed version of the patch:
Index: lib/libc/sys/kqueue.2
===================================================================
RCS file: src/lib/libc/sys/kqueue.2,v
retrieving revision 1.51
diff -u -p -r1.51 kqueue.2
--- lib/libc/sys/kqueue.2 20 Aug 2023 19:52:40 -0000 1.51
+++ lib/libc/sys/kqueue.2 6 May 2025 03:20:39 -0000
@@ -561,6 +561,44 @@ e.g. an HDMI cable has been plugged in t
On return,
.Fa fflags
contains the events which triggered the filter.
+.It Dv EVFILT_USER
+Establishes a user event identified by
+.Va ident
+which is not associated with any kernel mechanism but is triggered by
+user level code.
+The lower 24 bits of the
+.Va fflags
+may be used for user defined flags and manipulated using the following:
+.Bl -tag -width XXNOTE_FFLAGSMASK
+.It Dv NOTE_FFNOP
+Ignore the input
+.Va fflags .
+.It Dv NOTE_FFAND
+Bitwise AND
+.Va fflags .
+.It Dv NOTE_FFOR
+Bitwise OR
+.Va fflags .
+.It Dv NOTE_FFCOPY
+Copy
+.Va fflags .
+.It Dv NOTE_FFCTRLMASK
+Control mask for
+.Va fflags .
+.It Dv NOTE_FFLAGSMASK
+User defined flag mask for
+.Va fflags .
+.El
+.Pp
+A user event is triggered for output with the following:
+.Bl -tag -width XXNOTE_FFLAGSMASK
+.It Dv NOTE_TRIGGER
+Cause the event to be triggered.
+.El
+.Pp
+On return,
+.Va fflags
+contains the users defined flags in the lower 24 bits.
.El
.Sh RETURN VALUES
.Fn kqueue
Index: regress/sys/kern/kqueue/Makefile
===================================================================
RCS file: src/regress/sys/kern/kqueue/Makefile,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile
--- regress/sys/kern/kqueue/Makefile 20 Aug 2023 15:19:34 -0000 1.32
+++ regress/sys/kern/kqueue/Makefile 6 May 2025 03:20:40 -0000
@@ -4,7 +4,8 @@ PROG= kqueue-test
CFLAGS+=-Wall
SRCS= kqueue-pipe.c kqueue-fork.c main.c kqueue-process.c kqueue-random.c \
kqueue-pty.c kqueue-tun.c kqueue-signal.c kqueue-fdpass.c \
- kqueue-exec.c kqueue-flock.c kqueue-timer.c kqueue-regress.c
+ kqueue-exec.c kqueue-flock.c kqueue-timer.c kqueue-regress.c \
+ kqueue-user.c
LDADD= -levent -lutil
DPADD= ${LIBEVENT} ${LIBUTIL}
@@ -52,6 +53,8 @@ kq-regress-5: ${PROG}
./${PROG} -R5
kq-regress-6: ${PROG}
./${PROG} -R6
+kq-user: ${PROG}
+ ./${PROG} -u
TESTS+= kq-exec
TESTS+= kq-fdpass
@@ -73,6 +76,7 @@ TESTS+= kq-reset-timer
TESTS+= kq-signal
TESTS+= kq-timer
TESTS+= kq-tun
+TESTS+= kq-user
REGRESS_TARGETS=${TESTS}
REGRESS_ROOT_TARGETS=kq-pty-1
Index: regress/sys/kern/kqueue/kqueue-user.c
===================================================================
RCS file: regress/sys/kern/kqueue/kqueue-user.c
diff -N regress/sys/kern/kqueue/kqueue-user.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ regress/sys/kern/kqueue/kqueue-user.c 6 May 2025 03:20:40 -0000
@@ -0,0 +1,189 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "main.h"
+
+int
+do_user(void)
+{
+ const struct timespec ts = { 0, 10000 };
+ struct kevent kev[2];
+ int dummy, dummy2, i, kq, n;
+
+ ASS((kq = kqueue()) >= 0,
+ warn("kqueue"));
+
+ /* Set up an event. */
+ EV_SET(&kev[0], 1, EVFILT_USER, EV_ADD, ~0U & ~NOTE_TRIGGER, 0, NULL);
+ ASS(kevent(kq, kev, 1, NULL, 0, NULL) == 0,
+ warn("kevent"));
+
+ 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.
+ */
+ EV_SET(&kev[0], 1, EVFILT_USER, 0, 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 == 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);
+
+ /* Set up another event. */
+ EV_SET(&kev[0], 2, EVFILT_USER, EV_ADD, NOTE_TRIGGER, 654, &dummy2);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == 0);
+
+ /* Check active events. This assumes a specific output order. */
+ n = kevent(kq, NULL, 0, kev, 2, &ts);
+ ASSX(n == 2);
+ ASSX(kev[0].ident == 1);
+ ASSX(kev[0].fflags == NOTE_FFLAGSMASK);
+ ASSX(kev[0].data == 123);
+ ASSX(kev[0].udata == &dummy);
+ ASSX(kev[1].ident == 2);
+ ASSX(kev[1].fflags == 0);
+ ASSX(kev[1].data == 654);
+ ASSX(kev[1].udata == &dummy2);
+
+ /* Clear the first event. */
+ EV_SET(&kev[0], 1, EVFILT_USER, EV_CLEAR, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == 0);
+
+ n = kevent(kq, NULL, 0, kev, 2, &ts);
+ ASSX(n == 1);
+ ASSX(kev[0].ident == 2);
+ ASSX(kev[0].fflags == 0);
+ ASSX(kev[0].data == 654);
+ ASSX(kev[0].udata == &dummy2);
+
+ /* Delete the second event. */
+ EV_SET(&kev[0], 2, EVFILT_USER, EV_DELETE, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == 0);
+
+ n = kevent(kq, NULL, 0, kev, 2, &ts);
+ ASSX(n == 0);
+
+ /* Test self-clearing event. */
+ EV_SET(&kev[0], 2, EVFILT_USER, EV_ADD | EV_CLEAR, 0x11, 42, &dummy);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 0);
+
+ EV_SET(&kev[0], 2, EVFILT_USER, 0, NOTE_TRIGGER | 0x3, 24, &dummy2);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 1);
+ ASSX(kev[0].ident == 2);
+ ASSX(kev[0].fflags == 0x11);
+ ASSX(kev[0].data == 42);
+ ASSX(kev[0].udata == &dummy);
+
+ n = kevent(kq, NULL, 0, kev, 2, &ts);
+ ASSX(n == 0);
+
+ EV_SET(&kev[0], 2, EVFILT_USER, 0, NOTE_TRIGGER | 0x3, 9, &dummy2);
+ 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);
+
+ EV_SET(&kev[0], 2, EVFILT_USER, EV_DELETE, 0, 0, NULL);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 0);
+
+ /* Change fflags. */
+ EV_SET(&kev[0], 1, EVFILT_USER, 0, NOTE_FFCOPY | 0x00aa00, 0, NULL);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 0);
+ EV_SET(&kev[0], 1, EVFILT_USER, 0, NOTE_FFOR | 0xff00ff, 0, NULL);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 0);
+ EV_SET(&kev[0], 1, EVFILT_USER, 0, NOTE_TRIGGER | NOTE_FFAND | 0x0ffff0,
+ 0, NULL);
+ n = kevent(kq, kev, 1, kev, 2, &ts);
+ ASSX(n == 1);
+ ASSX(kev[0].ident == 1);
+ ASSX(kev[0].fflags == 0x0faaf0);
+ ASSX(kev[0].data == 0);
+ ASSX(kev[0].udata == &dummy);
+
+ /* Test event limit. */
+ for (i = 0;; i++) {
+ EV_SET(&kev[0], i, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ if (n == -1) {
+ ASSX(errno == ENOMEM);
+ break;
+ }
+ ASSX(n == 0);
+ }
+ ASSX(i < 1000000);
+
+ /* Delete one event, ... */
+ EV_SET(&kev[0], 0, EVFILT_USER, EV_DELETE, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == 0);
+
+ /* ... after which adding should succeed. */
+ EV_SET(&kev[0], 0, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == 0);
+
+ EV_SET(&kev[0], i, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ n = kevent(kq, kev, 1, NULL, 0, NULL);
+ ASSX(n == -1);
+ ASSX(errno == ENOMEM);
+
+ close(kq);
+
+ return (0);
+}
Index: regress/sys/kern/kqueue/main.c
===================================================================
RCS file: src/regress/sys/kern/kqueue/main.c,v
retrieving revision 1.16
diff -u -p -r1.16 main.c
--- regress/sys/kern/kqueue/main.c 20 Aug 2023 15:19:34 -0000 1.16
+++ regress/sys/kern/kqueue/main.c 6 May 2025 03:20:40 -0000
@@ -17,7 +17,7 @@ main(int argc, char **argv)
int n, ret, c;
ret = 0;
- while ((c = getopt(argc, argv, "efFiIjlpPrR:stT:")) != -1) {
+ while ((c = getopt(argc, argv, "efFiIjlpPrR:stT:u")) != -1) {
switch (c) {
case 'e':
ret |= do_exec(argv[0]);
@@ -63,8 +63,11 @@ main(int argc, char **argv)
n = strtonum(optarg, 1, INT_MAX, NULL);
ret |= do_pty(n);
break;
+ case 'u':
+ ret |= do_user();
+ break;
default:
- fprintf(stderr, "usage: %s -[fFiIlpPrstT] [-R n]\n",
+ fprintf(stderr, "usage: %s -[fFiIlpPrstTu] [-R n]\n",
__progname);
exit(1);
}
Index: regress/sys/kern/kqueue/main.h
===================================================================
RCS file: src/regress/sys/kern/kqueue/main.h,v
retrieving revision 1.7
diff -u -p -r1.7 main.h
--- regress/sys/kern/kqueue/main.h 20 Aug 2023 15:19:34 -0000 1.7
+++ regress/sys/kern/kqueue/main.h 6 May 2025 03:20:40 -0000
@@ -29,3 +29,4 @@ int do_reset_timer(void);
int do_signal(void);
int do_timer(void);
int do_tun(void);
+int do_user(void);
Index: sys/kern/kern_descrip.c
===================================================================
RCS file: src/sys/kern/kern_descrip.c,v
retrieving revision 1.210
diff -u -p -r1.210 kern_descrip.c
--- sys/kern/kern_descrip.c 30 Dec 2024 02:46:00 -0000 1.210
+++ sys/kern/kern_descrip.c 6 May 2025 03:20:41 -0000
@@ -39,6 +39,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/atomic.h>
#include <sys/filedesc.h>
#include <sys/vnode.h>
#include <sys/proc.h>
@@ -1201,6 +1202,7 @@ fdfree(struct proc *p)
vrele(fdp->fd_cdir);
if (fdp->fd_rdir)
vrele(fdp->fd_rdir);
+ KASSERT(atomic_load_int(&fdp->fd_nuserevents) == 0);
pool_put(&fdesc_pool, fdp);
}
Index: sys/kern/kern_event.c
===================================================================
RCS file: src/sys/kern/kern_event.c,v
retrieving revision 1.201
diff -u -p -r1.201 kern_event.c
--- sys/kern/kern_event.c 10 Feb 2025 16:45:46 -0000 1.201
+++ sys/kern/kern_event.c 6 May 2025 03:20:41 -0000
@@ -30,6 +30,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/atomic.h>
#include <sys/proc.h>
#include <sys/pledge.h>
#include <sys/malloc.h>
@@ -135,6 +136,10 @@ int filt_timerattach(struct knote *kn);
void filt_timerdetach(struct knote *kn);
int filt_timermodify(struct kevent *kev, struct knote *kn);
int filt_timerprocess(struct knote *kn, struct kevent *kev);
+int filt_userattach(struct knote *kn);
+void filt_userdetach(struct knote *kn);
+int filt_usermodify(struct kevent *kev, struct knote *kn);
+int filt_userprocess(struct knote *kn, struct kevent *kev);
void filt_seltruedetach(struct knote *kn);
const struct filterops kqread_filtops = {
@@ -180,12 +185,22 @@ const struct filterops timer_filtops = {
.f_process = filt_timerprocess,
};
+const struct filterops user_filtops = {
+ .f_flags = FILTEROP_MPSAFE,
+ .f_attach = filt_userattach,
+ .f_detach = filt_userdetach,
+ .f_event = NULL,
+ .f_modify = filt_usermodify,
+ .f_process = filt_userprocess,
+};
+
struct pool knote_pool;
struct pool kqueue_pool;
struct mutex kqueue_klist_lock = MUTEX_INITIALIZER(IPL_MPFLOOR);
struct rwlock kqueue_ps_list_lock = RWLOCK_INITIALIZER("kqpsl");
int kq_ntimeouts = 0;
int kq_timeoutmax = (4 * 1024);
+unsigned int kq_usereventsmax = 1024; /* per process */
#define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask))
@@ -202,6 +217,7 @@ const struct filterops *const sysfilt_op
&timer_filtops, /* EVFILT_TIMER */
&file_filtops, /* EVFILT_DEVICE */
&file_filtops, /* EVFILT_EXCEPT */
+ &user_filtops, /* EVFILT_USER */
};
void
@@ -731,6 +747,91 @@ filt_timerprocess(struct knote *kn, stru
return (active);
}
+int
+filt_userattach(struct knote *kn)
+{
+ struct filedesc *fdp = kn->kn_kq->kq_fdp;
+ u_int nuserevents;
+
+ nuserevents = atomic_inc_int_nv(&fdp->fd_nuserevents);
+ if (nuserevents > atomic_load_int(&kq_usereventsmax)) {
+ atomic_dec_int(&fdp->fd_nuserevents);
+ return (ENOMEM);
+ }
+
+ 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);
+}
+
+void
+filt_userdetach(struct knote *kn)
+{
+ struct filedesc *fdp = kn->kn_kq->kq_fdp;
+
+ atomic_dec_int(&fdp->fd_nuserevents);
+}
+
+int
+filt_usermodify(struct kevent *kev, struct knote *kn)
+{
+ unsigned int ffctrl, fflags;
+
+ if (kev->fflags & NOTE_TRIGGER)
+ kn->kn_ptr.p_useract = 1;
+
+ ffctrl = kev->fflags & NOTE_FFCTRLMASK;
+ fflags = kev->fflags & NOTE_FFLAGSMASK;
+ switch (ffctrl) {
+ case NOTE_FFNOP:
+ break;
+ case NOTE_FFAND:
+ kn->kn_fflags &= fflags;
+ break;
+ case NOTE_FFOR:
+ kn->kn_fflags |= fflags;
+ break;
+ case NOTE_FFCOPY:
+ kn->kn_fflags = fflags;
+ break;
+ default:
+ /* ignored, should not happen */
+ break;
+ }
+
+ if (kev->flags & EV_ADD) {
+ kn->kn_data = kev->data;
+ kn->kn_udata = kev->udata;
+ }
+
+ /* Allow clearing of an activated event. */
+ if (kev->flags & EV_CLEAR) {
+ kn->kn_ptr.p_useract = 0;
+ kn->kn_data = 0;
+ }
+
+ return (kn->kn_ptr.p_useract);
+}
+
+int
+filt_userprocess(struct knote *kn, struct kevent *kev)
+{
+ int active;
+
+ active = kn->kn_ptr.p_useract;
+ if (active && kev != NULL) {
+ *kev = kn->kn_kevent;
+ if (kn->kn_flags & EV_CLEAR) {
+ kn->kn_ptr.p_useract = 0;
+ kn->kn_fflags = 0;
+ kn->kn_data = 0;
+ }
+ }
+
+ return (active);
+}
/*
* filt_seltrue:
@@ -1411,6 +1512,17 @@ again:
filter_detach(kn);
knote_drop(kn, p);
goto done;
+ } else if (kn->kn_fop == &user_filtops) {
+ /* Call f_modify to allow NOTE_TRIGGER without EV_ADD. */
+ mtx_leave(&kq->kq_lock);
+ active = filter_modify(kev, kn);
+ mtx_enter(&kq->kq_lock);
+ if (active)
+ knote_activate(kn);
+ if (kev->flags & EV_ERROR) {
+ error = kev->data;
+ goto release;
+ }
}
if ((kev->flags & EV_DISABLE) && ((kn->kn_status & KN_DISABLED) == 0))
Index: sys/sys/event.h
===================================================================
RCS file: src/sys/sys/event.h,v
retrieving revision 1.73
diff -u -p -r1.73 event.h
--- sys/sys/event.h 6 Aug 2024 08:44:54 -0000 1.73
+++ sys/sys/event.h 6 May 2025 03:20:41 -0000
@@ -40,8 +40,9 @@
#define EVFILT_TIMER (-7) /* timers */
#define EVFILT_DEVICE (-8) /* devices */
#define EVFILT_EXCEPT (-9) /* exceptional conditions */
+#define EVFILT_USER (-10) /* user event */
-#define EVFILT_SYSCOUNT 9
+#define EVFILT_SYSCOUNT 10
#define EV_SET(kevp, a, b, c, d, e, f) do { \
struct kevent *__kevp = (kevp); \
@@ -130,6 +131,19 @@ struct kevent {
#define NOTE_ABSTIME 0x00000010 /* timeout is absolute */
/*
+ * data/hint flags for EVFILT_USER, shared with userspace
+ */
+#define NOTE_FFNOP 0x00000000 /* ignore input fflags */
+#define NOTE_FFAND 0x40000000 /* AND fflags */
+#define NOTE_FFOR 0x80000000 /* OR fflags */
+#define NOTE_FFCOPY 0xc0000000 /* copy fflags */
+
+#define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */
+#define NOTE_FFLAGSMASK 0x00ffffff
+
+#define NOTE_TRIGGER 0x01000000 /* trigger the event */
+
+/*
* This is currently visible to userland to work around broken
* programs which pull in <sys/proc.h> or <sys/selinfo.h>.
*/
@@ -244,6 +258,7 @@ struct knote {
union {
struct file *p_fp; /* file data pointer */
struct process *p_process; /* process pointer */
+ int p_useract; /* user event active */
} kn_ptr;
const struct filterops *kn_fop;
void *kn_hook; /* [o] */
Index: sys/sys/filedesc.h
===================================================================
RCS file: src/sys/sys/filedesc.h,v
retrieving revision 1.46
diff -u -p -r1.46 filedesc.h
--- sys/sys/filedesc.h 12 May 2022 13:33:09 -0000 1.46
+++ sys/sys/filedesc.h 6 May 2025 03:20:41 -0000
@@ -87,6 +87,7 @@ struct filedesc {
LIST_HEAD(, kqueue) fd_kqlist; /* [f] kqueues attached to this
* filedesc */
int fd_flags; /* [a] flags on this filedesc */
+ u_int fd_nuserevents; /* [a] number of kqueue user events */
};
/*
Index: usr.bin/kdump/mksubr
===================================================================
RCS file: src/usr.bin/kdump/mksubr,v
retrieving revision 1.40
diff -u -p -r1.40 mksubr
--- usr.bin/kdump/mksubr 13 Aug 2023 08:29:28 -0000 1.40
+++ usr.bin/kdump/mksubr 6 May 2025 03:20:41 -0000
@@ -583,6 +583,27 @@ cat <<_EOF_
or = 1;
if_print_or(fflags, NOTE_ABSTIME, or);
break;
+ case EVFILT_USER:
+ if (fflags & NOTE_FFCTRLMASK) {
+ switch (fflags & NOTE_FFCTRLMASK) {
+ case NOTE_FFAND:
+ printf("NOTE_FFAND");
+ break;
+ case NOTE_FFOR:
+ printf("NOTE_FFOR");
+ break;
+ case NOTE_FFCOPY:
+ printf("NOTE_FFCOPY");
+ break;
+ }
+ or = 1;
+ }
+ if_print_or(fflags, NOTE_TRIGGER, or);
+ if (fflags & NOTE_FFLAGSMASK) {
+ printf("%s%#x", or ? "|" : "",
+ fflags & NOTE_FFLAGSMASK);
+ }
+ break;
}
printf(">");
}
EVFILT_USER and kevent(2)