diff options
-rw-r--r-- | lib/libc/sys/kqueue.2 | 40 | ||||
-rw-r--r-- | sys/kern/kern_event.c | 99 | ||||
-rw-r--r-- | sys/sys/event.h | 22 |
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 */ |