Add EVFILT_USER to kevents.

Add user events support to kernel events which are not associated with any
kernel mechanism but are triggered by user level code.  This is useful for
adding user level events to an event handler that may also be monitoring
kernel events.

Approved by:	rwatson (co-mentor)
This commit is contained in:
sson 2009-09-16 03:30:12 +00:00
parent 297d4ab14b
commit 7cb0718a03
3 changed files with 159 additions and 2 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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
*/