NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/55663: Support for EVFILT_USER in kqueue(2)



>Number:         55663
>Category:       kern
>Synopsis:       Support for EVFILT_USER in kqueue(2)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 16 19:15:00 +0000 2020
>Originator:     Ruslan Nikolaev
>Release:        master
>Organization:
Virginia Tech
>Environment:
>Description:
NetBSD lacks support for EVTFILT_USER (e.g., see the bug report for pkg/54627). This option was introduced in FreeBSD long time ago, but NetBSD still lacks it.

While working on our project which uses the NetBSD code (https://github.com/ssrg-vt/rumprun-smp), we encountered that problem and ported a patch. We partially based our patch on that of OpenBSD (https://www.mail-archive.com/tech%openbsd.org@localhost/msg42433.html). OpenBSD's patch itself is backported from FreeBSD.

We relocated the patch to the most recent version (master branch). Please let us know if that can be upstreamed into NetBSD and who can review our patch.
>How-To-Repeat:

>Fix:
diff --git a/share/man/man9/kfilter_register.9 b/share/man/man9/kfilter_register.9
index 43ba379b8c40..f405819140aa 100644
--- a/share/man/man9/kfilter_register.9
+++ b/share/man/man9/kfilter_register.9
@@ -97,6 +97,7 @@ struct filterops {
 				/* called when knote is DELETEd */
 	int	(*f_event)(struct knote *kn, long hint);
 				/* called when event is triggered */
+	void	(*f_touch)(struct knote *kn, struct kevent *kev, long hint);
 };
 .Ed
 .Pp
diff --git a/sys/arch/amiga/dev/event.c b/sys/arch/amiga/dev/event.c
index 153176189f3d..6eb76425a5b9 100644
--- a/sys/arch/amiga/dev/event.c
+++ b/sys/arch/amiga/dev/event.c
@@ -195,6 +195,7 @@ static const struct filterops ev_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_evrdetach,
 	.f_event = filt_evread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/arc/dev/opms.c b/sys/arch/arc/dev/opms.c
index 222905f3cee3..aa20ab9f43c9 100644
--- a/sys/arch/arc/dev/opms.c
+++ b/sys/arch/arc/dev/opms.c
@@ -477,6 +477,7 @@ static const struct filterops opmsread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_opmsrdetach,
 	.f_event = filt_opmsread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/arm/xscale/pxa2x0_apm.c b/sys/arch/arm/xscale/pxa2x0_apm.c
index f27b56901f82..7a9d987d3e1f 100644
--- a/sys/arch/arm/xscale/pxa2x0_apm.c
+++ b/sys/arch/arm/xscale/pxa2x0_apm.c
@@ -105,7 +105,7 @@ int	filt_apmread(struct knote *kn, long hint);
 int	apmkqfilter(dev_t dev, struct knote *kn);
 
 struct filterops apmread_filtops =
-	{ 1, NULL, filt_apmrdetach, filt_apmread};
+	{ 1, NULL, filt_apmrdetach, filt_apmread, NULL };
 #endif
 
 /*
diff --git a/sys/arch/atari/dev/event.c b/sys/arch/atari/dev/event.c
index ca325c187319..4b2077a02ee8 100644
--- a/sys/arch/atari/dev/event.c
+++ b/sys/arch/atari/dev/event.c
@@ -194,6 +194,7 @@ static const struct filterops ev_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_evrdetach,
 	.f_event = filt_evread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/landisk/dev/button.c b/sys/arch/landisk/dev/button.c
index 1dc52c0d3af9..98bda5264e42 100644
--- a/sys/arch/landisk/dev/button.c
+++ b/sys/arch/landisk/dev/button.c
@@ -317,6 +317,7 @@ static const struct filterops btn_read_filtops = {
     .f_attach = NULL,
     .f_detach = filt_btn_rdetach,
     .f_event = filt_btn_read,
+	.f_touch = NULL,
 };
 
 static const struct filterops btn_write_filtops = {
@@ -324,6 +325,7 @@ static const struct filterops btn_write_filtops = {
     .f_attach = NULL,
     .f_detach = filt_btn_rdetach,
     .f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/mac68k/dev/aed.c b/sys/arch/mac68k/dev/aed.c
index a0e3b0eacfb7..45352e4c30a8 100644
--- a/sys/arch/mac68k/dev/aed.c
+++ b/sys/arch/mac68k/dev/aed.c
@@ -602,6 +602,7 @@ static const struct filterops aedread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_aedrdetach,
 	.f_event = filt_aedread,
+	.f_touch = NULL,
 };
 
 static const struct filterops aed_seltrue_filtops = {
@@ -609,6 +610,7 @@ static const struct filterops aed_seltrue_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_aedrdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/macppc/dev/aed.c b/sys/arch/macppc/dev/aed.c
index eb1551d68c55..21f6256ccf38 100644
--- a/sys/arch/macppc/dev/aed.c
+++ b/sys/arch/macppc/dev/aed.c
@@ -606,14 +606,16 @@ static const struct filterops aedread_filtops = {
 	.f_isfd = 1,
 	.f_attach = NULL,
 	.f_detach = filt_aedrdetach,
-	.f_event = filt_aedread
+	.f_event = filt_aedread,
+	.f_touch = NULL,
 };
 
 static const struct filterops aed_seltrue_filtops = {
 	.f_isfd = 1,
 	.f_attach = NULL,
 	.f_detach = filt_aedrdetach,
-	.f_event = filt_seltrue
+	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/macppc/dev/apm.c b/sys/arch/macppc/dev/apm.c
index c96f2aac2b2d..db515f309690 100644
--- a/sys/arch/macppc/dev/apm.c
+++ b/sys/arch/macppc/dev/apm.c
@@ -432,7 +432,7 @@ filt_apmread(struct knote *kn, long hint)
 }
 
 static struct filterops apmread_filtops =
-	{ 1, NULL, filt_apmrdetach, filt_apmread};
+	{ 1, NULL, filt_apmrdetach, filt_apmread, NULL };
 
 int
 apmkqfilter(dev_t dev, struct knote *kn)
diff --git a/sys/arch/mips/ralink/ralink_gpio.c b/sys/arch/mips/ralink/ralink_gpio.c
index 127acd6b5991..3ccec0a74dd3 100644
--- a/sys/arch/mips/ralink/ralink_gpio.c
+++ b/sys/arch/mips/ralink/ralink_gpio.c
@@ -498,7 +498,8 @@ static struct filterops app_fops = {
 	0,
 	gpio_event_app_user_attach,
 	gpio_event_app_user_detach,
-	gpio_event_app_user_event
+	gpio_event_app_user_event,
+	NULL
 };
 static struct callout led_tick_callout;
 static int gpio_driver_blink_leds = 1;
diff --git a/sys/arch/sandpoint/sandpoint/satmgr.c b/sys/arch/sandpoint/sandpoint/satmgr.c
index c3b049d6a075..f22c85989d36 100644
--- a/sys/arch/sandpoint/sandpoint/satmgr.c
+++ b/sys/arch/sandpoint/sandpoint/satmgr.c
@@ -607,6 +607,7 @@ static const struct filterops read_filtops ={
 	.f_attach = NULL,
 	.f_detach = filt_rdetach,
 	.f_event = filt_read,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/arch/shark/shark/opms.c b/sys/arch/shark/shark/opms.c
index 3dd08d4acc41..9b3c8fe9cb05 100644
--- a/sys/arch/shark/shark/opms.c
+++ b/sys/arch/shark/shark/opms.c
@@ -984,6 +984,7 @@ static const struct filterops opmsread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_opmsrdetach,
 	.f_event = filt_opmsread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/sparc/dev/tctrl.c b/sys/arch/sparc/dev/tctrl.c
index 7fd9d74acf0b..ceb5b06ab65c 100644
--- a/sys/arch/sparc/dev/tctrl.c
+++ b/sys/arch/sparc/dev/tctrl.c
@@ -1236,6 +1236,7 @@ static const struct filterops tctrlread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_tctrlrdetach,
 	.f_event = filt_tctrlread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/arch/x68k/dev/event.c b/sys/arch/x68k/dev/event.c
index 7fb4a41bdfae..102e905d7644 100644
--- a/sys/arch/x68k/dev/event.c
+++ b/sys/arch/x68k/dev/event.c
@@ -221,6 +221,7 @@ static const struct filterops ev_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_evrdetach,
 	.f_event = filt_evread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/coda/coda_psdev.c b/sys/coda/coda_psdev.c
index c42d1db98bd0..745d2985b7d2 100644
--- a/sys/coda/coda_psdev.c
+++ b/sys/coda/coda_psdev.c
@@ -491,6 +491,7 @@ static const struct filterops vc_nb_read_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_vc_nb_detach,
 	.f_event = filt_vc_nb_read,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/apm/apm.c b/sys/dev/apm/apm.c
index 04e5c541308e..794ae0eee7f0 100644
--- a/sys/dev/apm/apm.c
+++ b/sys/dev/apm/apm.c
@@ -888,6 +888,7 @@ static const struct filterops apmread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_apmrdetach,
 	.f_event = filt_apmread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/audio/audio.c b/sys/dev/audio/audio.c
index 0d04894795b6..89ed11183b39 100644
--- a/sys/dev/audio/audio.c
+++ b/sys/dev/audio/audio.c
@@ -3099,6 +3099,7 @@ static const struct filterops audioread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_audioread_detach,
 	.f_event = filt_audioread_event,
+	.f_touch = NULL,
 };
 
 static void
@@ -3146,6 +3147,7 @@ static const struct filterops audiowrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_audiowrite_detach,
 	.f_event = filt_audiowrite_event,
+	.f_touch = NULL,
 };
 
 static void
diff --git a/sys/dev/hpc/apm/apmdev.c b/sys/dev/hpc/apm/apmdev.c
index 6b182349ef53..917cd8a10a36 100644
--- a/sys/dev/hpc/apm/apmdev.c
+++ b/sys/dev/hpc/apm/apmdev.c
@@ -929,6 +929,7 @@ static const struct filterops apmread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_apmrdetach,
 	.f_event = filt_apmread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/ir/irframe_tty.c b/sys/dev/ir/irframe_tty.c
index e3c70dd752fa..6bf37dfe81af 100644
--- a/sys/dev/ir/irframe_tty.c
+++ b/sys/dev/ir/irframe_tty.c
@@ -834,6 +834,7 @@ static const struct filterops irframetread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_irframetrdetach,
 	.f_event = filt_irframetread,
+	.f_touch = NULL,
 };
 
 static const struct filterops irframetwrite_filtops = {
@@ -841,6 +842,7 @@ static const struct filterops irframetwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_irframetwdetach,
 	.f_event = filt_irframetwrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/midi.c b/sys/dev/midi.c
index 4949cc1feca9..d2a4f7b70571 100644
--- a/sys/dev/midi.c
+++ b/sys/dev/midi.c
@@ -1768,6 +1768,7 @@ static const struct filterops midiread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_midirdetach,
 	.f_event = filt_midiread,
+	.f_touch = NULL,
 };
 
 static void
@@ -1816,6 +1817,7 @@ static const struct filterops midiwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_midiwdetach,
 	.f_event = filt_midiwrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/pci/oboe.c b/sys/dev/pci/oboe.c
index db77bcc30c58..90fab594ed6e 100644
--- a/sys/dev/pci/oboe.c
+++ b/sys/dev/pci/oboe.c
@@ -499,6 +499,7 @@ static const struct filterops oboeread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_oboerdetach,
 	.f_event = filt_oboeread,
+	.f_touch = NULL,
 };
 
 static const struct filterops oboewrite_filtops = {
@@ -506,6 +507,7 @@ static const struct filterops oboewrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_oboewdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/pci/vio9p.c b/sys/dev/pci/vio9p.c
index cfc8449b25e0..2c0432ee8368 100644
--- a/sys/dev/pci/vio9p.c
+++ b/sys/dev/pci/vio9p.c
@@ -412,6 +412,7 @@ static const struct filterops vio9p_read_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_vio9p_detach,
 	.f_event = filt_vio9p_read,
+	.f_touch = NULL,
 };
 
 static int
@@ -428,6 +429,7 @@ static const struct filterops vio9p_write_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_vio9p_detach,
 	.f_event = filt_vio9p_write,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/pci/xmm7360.c b/sys/dev/pci/xmm7360.c
index 17a28aeb9aad..34586b99a5a5 100644
--- a/sys/dev/pci/xmm7360.c
+++ b/sys/dev/pci/xmm7360.c
@@ -2800,6 +2800,7 @@ static const struct filterops wwancread_filtops = {
 	.f_attach	= NULL,
 	.f_detach	= filt_wwancrdetach,
 	.f_event	= filt_wwancread,
+	.f_touch	= NULL,
 };
 
 static const struct filterops wwancwrite_filtops = {
@@ -2807,6 +2808,7 @@ static const struct filterops wwancwrite_filtops = {
 	.f_attach	= NULL,
 	.f_detach	= filt_wwancwdetach,
 	.f_event	= filt_wwancwrite,
+	.f_touch	= NULL,
 };
 
 int
diff --git a/sys/dev/putter/putter.c b/sys/dev/putter/putter.c
index 7d4f57d30f6a..9997643ae03e 100644
--- a/sys/dev/putter/putter.c
+++ b/sys/dev/putter/putter.c
@@ -496,6 +496,7 @@ static const struct filterops putter_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_putterdetach,
 	.f_event = filt_putter,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/qbus/qd.c b/sys/dev/qbus/qd.c
index 9a36533adf92..431949a601ed 100644
--- a/sys/dev/qbus/qd.c
+++ b/sys/dev/qbus/qd.c
@@ -1585,6 +1585,7 @@ static const struct filterops qdread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_qdrdetach,
 	.f_event = filt_qdread,
+	.f_touch = NULL,
 };
 
 static const struct filterops qdwrite_filtops = {
@@ -1592,6 +1593,7 @@ static const struct filterops qdwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_qdrdetach,
 	.f_event = filt_qdwrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/sbus/bpp.c b/sys/dev/sbus/bpp.c
index 76cf6fabb718..dc9d328372c0 100644
--- a/sys/dev/sbus/bpp.c
+++ b/sys/dev/sbus/bpp.c
@@ -525,6 +525,7 @@ static const struct filterops bppread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_bpprdetach,
 	.f_event = filt_bppread,
+	.f_touch = NULL,
 };
 
 static void
@@ -555,6 +556,7 @@ static const struct filterops bppwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_bppwdetach,
 	.f_event = filt_bpfwrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/scsipi/ch.c b/sys/dev/scsipi/ch.c
index 208aa77e2886..df758d73b200 100644
--- a/sys/dev/scsipi/ch.c
+++ b/sys/dev/scsipi/ch.c
@@ -492,6 +492,7 @@ static const struct filterops chread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_chdetach,
 	.f_event = filt_chread,
+	.f_touch = NULL,
 };
 
 static const struct filterops chwrite_filtops = {
@@ -499,6 +500,7 @@ static const struct filterops chwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_chdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/sequencer.c b/sys/dev/sequencer.c
index 3cbeb6ca9d02..b2add01e6c40 100644
--- a/sys/dev/sequencer.c
+++ b/sys/dev/sequencer.c
@@ -931,6 +931,7 @@ static const struct filterops sequencerread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_sequencerrdetach,
 	.f_event = filt_sequencerread,
+	.f_touch = NULL,
 };
 
 static void
@@ -969,6 +970,7 @@ static const struct filterops sequencerwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_sequencerwdetach,
 	.f_event = filt_sequencerwrite,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/sun/event.c b/sys/dev/sun/event.c
index 60504f9cc92f..4a2ba12116ff 100644
--- a/sys/dev/sun/event.c
+++ b/sys/dev/sun/event.c
@@ -201,6 +201,7 @@ static const struct filterops ev_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_evrdetach,
 	.f_event = filt_evread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/sysmon/sysmon_power.c b/sys/dev/sysmon/sysmon_power.c
index e06f0830fd1e..a72c54db5313 100644
--- a/sys/dev/sysmon/sysmon_power.c
+++ b/sys/dev/sysmon/sysmon_power.c
@@ -559,6 +559,7 @@ static const struct filterops sysmon_power_read_filtops = {
     .f_attach = NULL,
     .f_detach = filt_sysmon_power_rdetach,
     .f_event = filt_sysmon_power_read,
+	.f_touch = NULL,
 };
 
 static const struct filterops sysmon_power_write_filtops = {
@@ -566,6 +567,7 @@ static const struct filterops sysmon_power_write_filtops = {
     .f_attach = NULL,
     .f_detach = filt_sysmon_power_rdetach,
     .f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 /*
diff --git a/sys/dev/usb/udsir.c b/sys/dev/usb/udsir.c
index ee2ae7153cab..73dc0d968c87 100644
--- a/sys/dev/usb/udsir.c
+++ b/sys/dev/usb/udsir.c
@@ -667,6 +667,7 @@ static const struct filterops udsirread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_udsirrdetach,
 	.f_event = filt_udsirread,
+	.f_touch = NULL,
 };
 
 static const struct filterops udsirwrite_filtops = {
@@ -674,6 +675,7 @@ static const struct filterops udsirwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_udsirwdetach,
 	.f_event = filt_udsirwrite,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
index d887f1e80dcc..a1f4e0f70146 100644
--- a/sys/dev/usb/ugen.c
+++ b/sys/dev/usb/ugen.c
@@ -2140,6 +2140,7 @@ static const struct filterops ugenread_intr_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ugenrdetach,
 	.f_event = filt_ugenread_intr,
+	.f_touch = NULL,
 };
 
 static const struct filterops ugenread_isoc_filtops = {
@@ -2147,6 +2148,7 @@ static const struct filterops ugenread_isoc_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ugenrdetach,
 	.f_event = filt_ugenread_isoc,
+	.f_touch = NULL,
 };
 
 static const struct filterops ugenread_bulk_filtops = {
@@ -2154,6 +2156,7 @@ static const struct filterops ugenread_bulk_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ugenrdetach,
 	.f_event = filt_ugenread_bulk,
+	.f_touch = NULL,
 };
 
 static const struct filterops ugenwrite_bulk_filtops = {
@@ -2161,6 +2164,7 @@ static const struct filterops ugenwrite_bulk_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ugenrdetach,
 	.f_event = filt_ugenwrite_bulk,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 072e201fcfb4..dfdbeb507d5f 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -800,6 +800,7 @@ static const struct filterops uhidread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_uhidrdetach,
 	.f_event = filt_uhidread,
+	.f_touch = NULL,
 };
 
 static const struct filterops uhid_seltrue_filtops = {
@@ -807,6 +808,7 @@ static const struct filterops uhid_seltrue_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_uhidrdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/dev/usb/uirda.c b/sys/dev/usb/uirda.c
index 06697ad74af1..48be32e242fc 100644
--- a/sys/dev/usb/uirda.c
+++ b/sys/dev/usb/uirda.c
@@ -645,6 +645,7 @@ static const struct filterops uirdaread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_uirdardetach,
 	.f_event = filt_uirdaread,
+	.f_touch = NULL,
 };
 
 static const struct filterops uirdawrite_filtops = {
@@ -652,6 +653,7 @@ static const struct filterops uirdawrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_uirdawdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 0876ae6189ec..63fad3594131 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1042,6 +1042,7 @@ static const struct filterops usbread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_usbrdetach,
 	.f_event = filt_usbread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/usb/uscanner.c b/sys/dev/usb/uscanner.c
index 299c34ea7ae3..8cf40cf85068 100644
--- a/sys/dev/usb/uscanner.c
+++ b/sys/dev/usb/uscanner.c
@@ -683,6 +683,7 @@ static const struct filterops uscanner_seltrue_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_uscannerdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/dev/usb/ustir.c b/sys/dev/usb/ustir.c
index df3776d525ba..bb1ba4bb69e9 100644
--- a/sys/dev/usb/ustir.c
+++ b/sys/dev/usb/ustir.c
@@ -1099,6 +1099,7 @@ static const struct filterops ustirread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ustirrdetach,
 	.f_event = filt_ustirread,
+	.f_touch = NULL,
 };
 
 static const struct filterops ustirwrite_filtops = {
@@ -1106,6 +1107,7 @@ static const struct filterops ustirwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ustirwdetach,
 	.f_event = filt_ustirwrite,
+	.f_touch = NULL,
 };
 
 Static int
diff --git a/sys/dev/wscons/wsevent.c b/sys/dev/wscons/wsevent.c
index a3c34b1e3630..c37acf69e831 100644
--- a/sys/dev/wscons/wsevent.c
+++ b/sys/dev/wscons/wsevent.c
@@ -330,6 +330,7 @@ static const struct filterops wsevent_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_wseventrdetach,
 	.f_event = filt_wseventread,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/external/bsd/drm2/drm/drm_cdevsw.c b/sys/external/bsd/drm2/drm/drm_cdevsw.c
index 20073f5a5dc8..081846d903dd 100644
--- a/sys/external/bsd/drm2/drm/drm_cdevsw.c
+++ b/sys/external/bsd/drm2/drm/drm_cdevsw.c
@@ -390,6 +390,7 @@ static const struct filterops drm_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_drm_detach,
 	.f_event = filt_drm_event,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/kern/kern_entropy.c b/sys/kern/kern_entropy.c
index 1bb1350c68e6..e3d637147718 100644
--- a/sys/kern/kern_entropy.c
+++ b/sys/kern/kern_entropy.c
@@ -1458,6 +1458,7 @@ static const struct filterops entropy_read_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_entropy_read_detach,
 	.f_event = filt_entropy_read_event,
+	.f_touch = NULL,
 };
 
 /*
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 6ed5bec32e52..ccab72d51e92 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -31,6 +31,7 @@
 
 /*-
  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon%FreeBSD.org@localhost>
+ * Copyright (c) 2009 Apple, Inc
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -109,6 +110,10 @@ static int	filt_timer(struct knote *, long hint);
 static int	filt_fsattach(struct knote *kn);
 static void	filt_fsdetach(struct knote *kn);
 static int	filt_fs(struct knote *kn, long hint);
+static int	filt_userattach(struct knote *);
+static void	filt_userdetach(struct knote *);
+static int	filt_user(struct knote *, long hint);
+static void	filt_usertouch(struct knote *, struct kevent *, long type);
 
 static const struct fileops kqueueops = {
 	.fo_name = "kqueue",
@@ -128,6 +133,7 @@ static const struct filterops kqread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_kqdetach,
 	.f_event = filt_kqueue,
+	.f_touch = NULL,
 };
 
 static const struct filterops proc_filtops = {
@@ -135,6 +141,7 @@ static const struct filterops proc_filtops = {
 	.f_attach = filt_procattach,
 	.f_detach = filt_procdetach,
 	.f_event = filt_proc,
+	.f_touch = NULL,
 };
 
 static const struct filterops file_filtops = {
@@ -142,6 +149,7 @@ static const struct filterops file_filtops = {
 	.f_attach = filt_fileattach,
 	.f_detach = NULL,
 	.f_event = NULL,
+	.f_touch = NULL,
 };
 
 static const struct filterops timer_filtops = {
@@ -149,6 +157,7 @@ static const struct filterops timer_filtops = {
 	.f_attach = filt_timerattach,
 	.f_detach = filt_timerdetach,
 	.f_event = filt_timer,
+	.f_touch = NULL,
 };
 
 static const struct filterops fs_filtops = {
@@ -156,6 +165,15 @@ static const struct filterops fs_filtops = {
 	.f_attach = filt_fsattach,
 	.f_detach = filt_fsdetach,
 	.f_event = filt_fs,
+	.f_touch = NULL,
+};
+
+static const struct filterops user_filtops = {
+	.f_isfd = 0,
+	.f_attach = filt_userattach,
+	.f_detach = filt_userdetach,
+	.f_event = filt_user,
+	.f_touch = filt_usertouch,
 };
 
 static u_int	kq_ncallouts = 0;
@@ -192,6 +210,7 @@ static struct kfilter sys_kfilters[] = {
 	{ "EVFILT_SIGNAL",	EVFILT_SIGNAL,	0, &sig_filtops, 0 },
 	{ "EVFILT_TIMER",	EVFILT_TIMER,	0, &timer_filtops, 0 },
 	{ "EVFILT_FS",		EVFILT_FS,	0, &fs_filtops, 0 },
+	{ "EVFILT_USER",	EVFILT_USER,	0, &user_filtops, 0 },
 	{ NULL,			0,		0, NULL, 0 },
 };
 
@@ -776,6 +795,106 @@ filt_fs(struct knote *kn, long hint)
 	return rv;
 }
 
+static int
+filt_userattach(struct knote *kn)
+{
+	struct kqueue *kq = kn->kn_kq;
+
+	/*
+	 * EVFILT_USER knotes are not attached to anything in the kernel.
+	 */
+	mutex_spin_enter(&kq->kq_lock);
+	kn->kn_hook = NULL;
+	if (kn->kn_fflags & NOTE_TRIGGER)
+		kn->kn_hookid = 1;
+	else
+		kn->kn_hookid = 0;
+	mutex_spin_exit(&kq->kq_lock);
+	return (0);
+}
+
+static void
+filt_userdetach(struct knote *kn)
+{
+
+	/*
+	 * EVFILT_USER knotes are not attached to anything in the kernel.
+	 */
+}
+
+static int
+filt_user(struct knote *kn, long hint)
+{
+	struct kqueue *kq = kn->kn_kq;
+	int hookid;
+
+	mutex_spin_enter(&kq->kq_lock);
+	hookid = kn->kn_hookid;
+	mutex_spin_exit(&kq->kq_lock);
+
+	return hookid;
+}
+
+static void
+filt_usertouch(struct knote *kn, struct kevent *kev, long type)
+{
+	struct kqueue *kq = kn->kn_kq;
+	int ffctrl;
+
+	mutex_spin_enter(&kq->kq_lock);
+	switch (type) {
+	case EVENT_REGISTER:
+		if (kev->fflags & NOTE_TRIGGER)
+			kn->kn_hookid = 1;
+
+		ffctrl = kev->fflags & NOTE_FFCTRLMASK;
+		kev->fflags &= NOTE_FFLAGSMASK;
+		switch (ffctrl) {
+		case NOTE_FFNOP:
+			break;
+
+		case NOTE_FFAND:
+			kn->kn_sfflags &= kev->fflags;
+			break;
+
+		case NOTE_FFOR:
+			kn->kn_sfflags |= kev->fflags;
+			break;
+
+		case NOTE_FFCOPY:
+			kn->kn_sfflags = kev->fflags;
+			break;
+
+		default:
+			/* XXX Return error? */
+			break;
+		}
+		kn->kn_sdata = kev->data;
+		if (kev->flags & EV_CLEAR) {
+			kn->kn_hookid = 0;
+			kn->kn_data = 0;
+			kn->kn_fflags = 0;
+		}
+		break;
+
+	case EVENT_PROCESS:
+		*kev = kn->kn_kevent;
+		kev->fflags = kn->kn_sfflags;
+		kev->data = kn->kn_sdata;
+		if (kn->kn_flags & EV_CLEAR) {
+			kn->kn_hookid = 0;
+			kn->kn_data = 0;
+			kn->kn_fflags = 0;
+		}
+		break;
+
+	default:
+		panic("filt_usertouch() - invalid type (%ld)", type);
+		break;
+	}
+	mutex_spin_exit(&kq->kq_lock);
+}
+
 /*
  * filt_seltrue:
  *
@@ -809,6 +928,7 @@ const struct filterops seltrue_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_seltruedetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
@@ -1072,8 +1192,8 @@ kqueue_register(struct kqueue *kq, struct kevent *kev)
 	/*
 	 * kn now contains the matching knote, or NULL if no match
 	 */
-	if (kev->flags & EV_ADD) {
-		if (kn == NULL) {
+	if (kn == NULL) {
+		if (kev->flags & EV_ADD) {
 			/* create new knote */
 			kn = newkn;
 			newkn = NULL;
@@ -1137,41 +1257,51 @@ kqueue_register(struct kqueue *kq, struct kevent *kev)
 				goto done;
 			}
 			atomic_inc_uint(&kfilter->refcnt);
+			goto done_ev_add;
 		} else {
-			/*
-			 * The user may change some filter values after the
-			 * initial EV_ADD, but doing so will not reset any
-			 * filter which have already been triggered.
-			 */
-			kn->kn_sfflags = kev->fflags;
-			kn->kn_sdata = kev->data;
-			kn->kn_kevent.udata = kev->udata;
+			/* No matching knote and the EV_ADD flag is not set. */
+			error = ENOENT;
+			goto doneunlock;
 		}
-		/*
-		 * We can get here if we are trying to attach
-		 * an event to a file descriptor that does not
-		 * support events, and the attach routine is
-		 * broken and does not return an error.
-		 */
-		KASSERT(kn->kn_fop != NULL);
-		KASSERT(kn->kn_fop->f_event != NULL);
+	}
+
+	if (kev->flags & EV_DELETE) {
+		/* knote_detach() drops fdp->fd_lock */
+		knote_detach(kn, fdp, true);
+		goto done;
+	}
+
+	/*
+	 * The user may change some filter values after the
+	 * initial EV_ADD, but doing so will not reset any
+	 * filter which have already been triggered.
+	 */
+	kn->kn_kevent.udata = kev->udata;
+	KASSERT(kn->kn_fop != NULL);
+	if (!kn->kn_fop->f_isfd && kn->kn_fop->f_touch != NULL) {
 		KERNEL_LOCK(1, NULL);			/* XXXSMP */
-		rv = (*kn->kn_fop->f_event)(kn, 0);
+		(*kn->kn_fop->f_touch)(kn, kev, EVENT_REGISTER);
 		KERNEL_UNLOCK_ONE(NULL);		/* XXXSMP */
-		if (rv)
-			knote_activate(kn);
 	} else {
-		if (kn == NULL) {
-			error = ENOENT;
-			goto doneunlock;
-		}
-		if (kev->flags & EV_DELETE) {
-			/* knote_detach() drops fdp->fd_lock */
-			knote_detach(kn, fdp, true);
-			goto done;
-		}
+		kn->kn_sfflags = kev->fflags;
+		kn->kn_sdata = kev->data;
 	}
 
+	/*
+	 * We can get here if we are trying to attach
+	 * an event to a file descriptor that does not
+	 * support events, and the attach routine is
+	 * broken and does not return an error.
+	 */
+done_ev_add:
+	KASSERT(kn->kn_fop != NULL);
+	KASSERT(kn->kn_fop->f_event != NULL);
+	KERNEL_LOCK(1, NULL);			/* XXXSMP */
+	rv = (*kn->kn_fop->f_event)(kn, 0);
+	KERNEL_UNLOCK_ONE(NULL);		/* XXXSMP */
+	if (rv)
+		knote_activate(kn);
+
 	/* disable knote */
 	if ((kev->flags & EV_DISABLE)) {
 		mutex_spin_enter(&kq->kq_lock);
@@ -1271,7 +1401,7 @@ kqueue_scan(file_t *fp, size_t maxevents, struct kevent *ulistp,
 	struct timespec	ats, sleepts;
 	struct knote	*kn, *marker, morker;
 	size_t		count, nkev, nevents;
-	int		timeout, error, rv;
+	int		timeout, error, touch, rv;
 	filedesc_t	*fdp;
 
 	fdp = curlwp->l_fd;
@@ -1382,8 +1512,20 @@ kqueue_scan(file_t *fp, size_t maxevents, struct kevent *ulistp,
 					continue;
 				}
 			}
+			KASSERT(kn->kn_fop != NULL);
+			touch = (!kn->kn_fop->f_isfd &&
+					kn->kn_fop->f_touch != NULL);
 			/* XXXAD should be got from f_event if !oneshot. */
-			*kevp++ = kn->kn_kevent;
+			if (touch) {
+				mutex_spin_exit(&kq->kq_lock);
+				KERNEL_LOCK(1, NULL);		/* XXXSMP */
+				(*kn->kn_fop->f_touch)(kn, kevp, EVENT_PROCESS);
+				KERNEL_UNLOCK_ONE(NULL);	/* XXXSMP */
+				mutex_spin_enter(&kq->kq_lock);
+			} else {
+				*kevp = kn->kn_kevent;
+			}
+			kevp++;
 			nkev++;
 			if (kn->kn_flags & EV_ONESHOT) {
 				/* delete ONESHOT events after retrieval */
@@ -1396,6 +1538,14 @@ kqueue_scan(file_t *fp, size_t maxevents, struct kevent *ulistp,
 				/* clear state after retrieval */
 				kn->kn_data = 0;
 				kn->kn_fflags = 0;
+				/*
+				 * Manually clear knotes who weren't
+				 * 'touch'ed.
+				 */
+				if (touch == 0) {
+					kn->kn_data = 0;
+					kn->kn_fflags = 0;
+				}
 				kn->kn_status &= ~(KN_QUEUED|KN_ACTIVE|KN_BUSY);
 			} else if (kn->kn_flags & EV_DISPATCH) {
 				kn->kn_status |= KN_DISABLED;
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 1e4c4449bb49..5af9504eaf0a 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2665,4 +2665,5 @@ const struct filterops sig_filtops = {
 		.f_attach = filt_sigattach,
 		.f_detach = filt_sigdetach,
 		.f_event = filt_signal,
+		.f_touch = NULL,
 };
diff --git a/sys/kern/subr_log.c b/sys/kern/subr_log.c
index ad57b693b343..90ecea9808bf 100644
--- a/sys/kern/subr_log.c
+++ b/sys/kern/subr_log.c
@@ -294,6 +294,7 @@ static const struct filterops logread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_logrdetach,
 	.f_event = filt_logread,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index a5e2fb11b818..a147d3192b8a 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -1092,6 +1092,7 @@ static const struct filterops pipe_rfiltops = {
 	.f_attach = NULL,
 	.f_detach = filt_pipedetach,
 	.f_event = filt_piperead,
+	.f_touch = NULL,
 };
 
 static const struct filterops pipe_wfiltops = {
@@ -1099,6 +1100,7 @@ static const struct filterops pipe_wfiltops = {
 	.f_attach = NULL,
 	.f_detach = filt_pipedetach,
 	.f_event = filt_pipewrite,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index e5d4bd96618c..96229c08b8ce 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1515,6 +1515,7 @@ static const struct filterops ttyread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ttyrdetach,
 	.f_event = filt_ttyread,
+	.f_touch = NULL,
 };
 
 static const struct filterops ttywrite_filtops = {
@@ -1522,6 +1523,7 @@ static const struct filterops ttywrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ttywdetach,
 	.f_event = filt_ttywrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index 68d267c8852c..61051c45b044 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -1006,6 +1006,7 @@ static const struct filterops ptcread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ptcrdetach,
 	.f_event = filt_ptcread,
+	.f_touch = NULL,
 };
 
 static const struct filterops ptcwrite_filtops = {
@@ -1013,6 +1014,7 @@ static const struct filterops ptcwrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_ptcwdetach,
 	.f_event = filt_ptcwrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 702868f1cf5d..10e2783746f7 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -2319,6 +2319,7 @@ static const struct filterops solisten_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_sordetach,
 	.f_event = filt_solisten,
+	.f_touch = NULL,
 };
 
 static const struct filterops soread_filtops = {
@@ -2326,6 +2327,7 @@ static const struct filterops soread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_sordetach,
 	.f_event = filt_soread,
+	.f_touch = NULL,
 };
 
 static const struct filterops sowrite_filtops = {
@@ -2333,6 +2335,7 @@ static const struct filterops sowrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_sowdetach,
 	.f_event = filt_sowrite,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c
index 5cb407b22bc3..fdfb113ee898 100644
--- a/sys/miscfs/fifofs/fifo_vnops.c
+++ b/sys/miscfs/fifofs/fifo_vnops.c
@@ -584,6 +584,7 @@ static const struct filterops fiforead_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_fifordetach,
 	.f_event = filt_fiforead,
+	.f_touch = NULL,
 };
 
 static const struct filterops fifowrite_filtops = {
@@ -591,6 +592,7 @@ static const struct filterops fifowrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_fifowdetach,
 	.f_event = filt_fifowrite,
+	.f_touch = NULL,
 };
 
 /* ARGSUSED */
diff --git a/sys/miscfs/genfs/genfs_vnops.c b/sys/miscfs/genfs/genfs_vnops.c
index 8f586e41e22c..baa152de50ab 100644
--- a/sys/miscfs/genfs/genfs_vnops.c
+++ b/sys/miscfs/genfs/genfs_vnops.c
@@ -575,6 +575,7 @@ static const struct filterops genfsread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_genfsdetach,
 	.f_event = filt_genfsread,
+	.f_touch = NULL,
 };
 
 static const struct filterops genfswrite_filtops = {
@@ -582,6 +583,7 @@ static const struct filterops genfswrite_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_genfsdetach,
 	.f_event = filt_genfswrite,
+	.f_touch = NULL,
 };
 
 static const struct filterops genfsvnode_filtops = {
@@ -589,6 +591,7 @@ static const struct filterops genfsvnode_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_genfsdetach,
 	.f_event = filt_genfsvnode,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 331758630392..b9f237713ba4 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -1552,6 +1552,7 @@ static const struct filterops bpfread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_bpfrdetach,
 	.f_event = filt_bpfread,
+	.f_touch = NULL,
 };
 
 static int
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index d6505938e6c3..d553e6b1e2f9 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -1233,9 +1233,9 @@ tap_dev_poll(int unit, int events, struct lwp *l)
 }
 
 static struct filterops tap_read_filterops = { 1, NULL, tap_kqdetach,
-	tap_kqread };
+	tap_kqread, NULL };
 static struct filterops tap_seltrue_filterops = { 1, NULL, tap_kqdetach,
-	filt_seltrue };
+	filt_seltrue, NULL };
 
 static int
 tap_cdev_kqfilter(dev_t dev, struct knote *kn)
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 4aedddec131f..b21bff9ec3c1 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -1082,6 +1082,7 @@ static const struct filterops tunread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_tunrdetach,
 	.f_event = filt_tunread,
+	.f_touch = NULL,
 };
 
 static const struct filterops tun_seltrue_filtops = {
@@ -1089,6 +1090,7 @@ static const struct filterops tun_seltrue_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_tunrdetach,
 	.f_event = filt_seltrue,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/nfs/nfs_kq.c b/sys/nfs/nfs_kq.c
index 8ceecc5d6f38..4c918d20717b 100644
--- a/sys/nfs/nfs_kq.c
+++ b/sys/nfs/nfs_kq.c
@@ -281,6 +281,7 @@ static const struct filterops nfsread_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_nfsdetach,
 	.f_event = filt_nfsread,
+	.f_touch = NULL,
 };
 
 static const struct filterops nfsvnode_filtops = {
@@ -288,6 +289,7 @@ static const struct filterops nfsvnode_filtops = {
 	.f_attach = NULL,
 	.f_detach = filt_nfsdetach,
 	.f_event = filt_nfsvnode,
+	.f_touch = NULL,
 };
 
 int
diff --git a/sys/sys/event.h b/sys/sys/event.h
index dd18e51bb4ce..2473d7b220e3 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -44,7 +44,8 @@
 #define	EVFILT_SIGNAL		5U	/* attached to struct proc */
 #define	EVFILT_TIMER		6U	/* arbitrary timer (in ms) */
 #define	EVFILT_FS		7U	/* filesystem events */
-#define	EVFILT_SYSCOUNT		8U	/* number of filters */
+#define	EVFILT_USER		8U	/* user events */
+#define	EVFILT_SYSCOUNT		9U	/* number of filters */
 
 struct kevent {
 	uintptr_t	ident;		/* identifier for this event */
@@ -90,6 +91,26 @@ _EV_SET(struct kevent *_kevp, uintptr_t _ident, uint32_t _filter,
 #define	EV_EOF		0x8000U		/* EOF detected */
 #define	EV_ERROR	0x4000U		/* error, data contains errno */
 
+/*
+ * data/hint flags/masks for EVFILT_USER, shared with userspace
+ *
+ * On input, the top two bits of fflags specifies how the lower twenty four
+ * bits should be applied to the stored value of fflags.
+ *
+ * On output, the top two bits will always be set to NOTE_FFNOP and the
+ * remaining twenty four bits will contain the stored fflags value.
+ */
+#define	NOTE_FFNOP	0x00000000U		/* ignore input fflags */
+#define	NOTE_FFAND	0x40000000U		/* AND fflags */
+#define	NOTE_FFOR	0x80000000U		/* OR fflags */
+#define	NOTE_FFCOPY	0xc0000000U		/* copy fflags */
+
+#define	NOTE_FFCTRLMASK	0xc0000000U		/* masks for operations */
+#define	NOTE_FFLAGSMASK	0x00ffffffU
+
+#define	NOTE_TRIGGER	0x01000000U		/* Cause the event to be
+						   triggered for output. */
+
 /*
  * hint flag for in-kernel use - must not equal any existing note
  */
@@ -161,6 +182,16 @@ struct kfilter_mapping {
  */
 #define	NOTE_SIGNAL	0x08000000U
 
+/*
+ * Hint values for the optional f_touch event filter.  If f_touch is not set
+ * to NULL and f_isfd is zero the f_touch filter will be called with the type
+ * argument set to EVENT_REGISTER during a kevent() system call.  It is also
+ * called under the same conditions with the type argument set to EVENT_PROCESS
+ * when the event has been triggered.
+ */
+#define	EVENT_REGISTER	1
+#define	EVENT_PROCESS	2
+
 /*
  * Callback methods for each filter type.
  */
@@ -172,6 +203,7 @@ struct filterops {
 					/* called when knote is DELETEd */
 	int	(*f_event)	(struct knote *, long);
 					/* called when event is triggered */
+	void	(*f_touch)	(struct knote *, struct kevent *, long);
 };
 
 /*
@@ -196,6 +228,7 @@ struct knote {
 	const struct filterops	*kn_fop;
 	struct kfilter		*kn_kfilter;
 	void 			*kn_hook;
+	int			kn_hookid;
 
 #define	KN_ACTIVE	0x01U			/* event has been triggered */
 #define	KN_QUEUED	0x02U			/* event is on queue */





Home | Main Index | Thread Index | Old Index