summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/kqueue.240
-rw-r--r--sys/kern/kern_event.c99
-rw-r--r--sys/sys/event.h22
3 files changed, 159 insertions, 2 deletions
diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index 119ff79..1e5e2b5 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 6, 2007
+.Dd September 15, 2009
.Dt KQUEUE 2
.Os
.Sh NAME
@@ -441,6 +441,44 @@ The link state is invalid.
On return,
.Va fflags
contains the events which triggered the filter.
+.It Dv EVFILT_USER
+Establishes a user event identified by
+.Va ident
+which is not assosicated 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_COPY
+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
The
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index cf402a2..92afec2 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -142,6 +142,10 @@ static void filt_timerexpire(void *knx);
static int filt_timerattach(struct knote *kn);
static void filt_timerdetach(struct knote *kn);
static int filt_timer(struct knote *kn, long hint);
+static int filt_userattach(struct knote *kn);
+static void filt_userdetach(struct knote *kn);
+static int filt_user(struct knote *kn, long hint);
+static void filt_usertouch(struct knote *kn, struct kevent *kev, long type);
static struct filterops file_filtops = {
.f_isfd = 1,
@@ -165,6 +169,12 @@ static struct filterops timer_filtops = {
.f_detach = filt_timerdetach,
.f_event = filt_timer,
};
+static struct filterops user_filtops = {
+ .f_attach = filt_userattach,
+ .f_detach = filt_userdetach,
+ .f_event = filt_user,
+ .f_touch = filt_usertouch,
+};
static uma_zone_t knote_zone;
static int kq_ncallouts = 0;
@@ -271,6 +281,7 @@ static struct {
{ &file_filtops }, /* EVFILT_NETDEV */
{ &fs_filtops }, /* EVFILT_FS */
{ &null_filtops }, /* EVFILT_LIO */
+ { &user_filtops }, /* EVFILT_USER */
};
/*
@@ -573,6 +584,94 @@ filt_timer(struct knote *kn, long hint)
return (kn->kn_data != 0);
}
+static int
+filt_userattach(struct knote *kn)
+{
+
+ /*
+ * EVFILT_USER knotes are not attached to anything in the kernel.
+ */
+ kn->kn_hook = NULL;
+ if (kn->kn_fflags & NOTE_TRIGGER)
+ kn->kn_hookid = 1;
+ else
+ kn->kn_hookid = 0;
+ return (0);
+}
+
+static void
+filt_userdetach(__unused struct knote *kn)
+{
+
+ /*
+ * EVFILT_USER knotes are not attached to anything in the kernel.
+ */
+}
+
+static int
+filt_user(struct knote *kn, __unused long hint)
+{
+
+ return (kn->kn_hookid);
+}
+
+static void
+filt_usertouch(struct knote *kn, struct kevent *kev, long type)
+{
+ int ffctrl;
+
+ 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;
+ }
+}
+
int
kqueue(struct thread *td, struct kqueue_args *uap)
{
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 4319f57..eb0fefd 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -41,7 +41,8 @@
#define EVFILT_NETDEV (-8) /* network devices */
#define EVFILT_FS (-9) /* filesystem events */
#define EVFILT_LIO (-10) /* attached to lio requests */
-#define EVFILT_SYSCOUNT 10
+#define EVFILT_USER (-11) /* User events */
+#define EVFILT_SYSCOUNT 11
#define EV_SET(kevp_, a, b, c, d, e, f) do { \
struct kevent *kevp = (kevp_); \
@@ -79,6 +80,25 @@ struct kevent {
#define EV_EOF 0x8000 /* EOF detected */
#define EV_ERROR 0x4000 /* 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 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 /* Cause the event to be
+ triggered for output. */
+
/*
* data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
*/
OpenPOWER on IntegriCloud