svn commit: r198732 - in stable/8: lib/libc lib/libc/gen
lib/libc/stdio lib/libc/stdtime lib/libc/string lib/libc/sys
sys sys/amd64/include/xen sys/cddl/contrib/opensolaris
sys/contrib/dev/acpica s...
Stacey Son
sson at FreeBSD.org
Sat Oct 31 21:22:18 UTC 2009
Author: sson
Date: Sat Oct 31 21:22:18 2009
New Revision: 198732
URL: http://svn.freebsd.org/changeset/base/198732
Log:
MFC 197240,197241,197242,197243,197293,197294,197407:
Add EVFILT_USER filter and EV_DISPATCH/EV_RECEIPT flags to kevent(2).
Approved by: rwatson (mentor)
Modified:
stable/8/lib/libc/ (props changed)
stable/8/lib/libc/gen/ (props changed)
stable/8/lib/libc/stdio/asprintf.c (props changed)
stable/8/lib/libc/stdtime/ (props changed)
stable/8/lib/libc/string/ffsll.c (props changed)
stable/8/lib/libc/string/flsll.c (props changed)
stable/8/lib/libc/string/wcpcpy.c (props changed)
stable/8/lib/libc/string/wcpncpy.c (props changed)
stable/8/lib/libc/sys/kqueue.2
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
stable/8/sys/dev/xen/xenpci/ (props changed)
stable/8/sys/kern/kern_event.c
stable/8/sys/sys/event.h
Modified: stable/8/lib/libc/sys/kqueue.2
==============================================================================
--- stable/8/lib/libc/sys/kqueue.2 Sat Oct 31 20:59:13 2009 (r198731)
+++ stable/8/lib/libc/sys/kqueue.2 Sat Oct 31 21:22:18 2009 (r198732)
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 6, 2007
+.Dd September 15, 2009
.Dt KQUEUE 2
.Os
.Sh NAME
@@ -201,11 +201,25 @@ Disable the event so
.Fn kevent
will not return it.
The filter itself is not disabled.
+.It EV_DISPATCH
+Disable the event source immediately after delivery of an event.
+See
+.Dv EV_DISABLE
+above.
.It EV_DELETE
Removes the event from the kqueue.
Events which are attached to
file descriptors are automatically deleted on the last close of
the descriptor.
+.It EV_RECEIPT
+This flag is useful for making bulk changes to a kqueue without draining
+any pending events.
+When passed as input, it forces
+.Dv EV_ERROR
+to always be returned.
+When a filter is successfully added the
+.Va data
+field will be zero.
.It EV_ONESHOT
Causes the event to return only the first occurrence of the filter
being triggered.
@@ -441,6 +455,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
Modified: stable/8/sys/kern/kern_event.c
==============================================================================
--- stable/8/sys/kern/kern_event.c Sat Oct 31 20:59:13 2009 (r198731)
+++ stable/8/sys/kern/kern_event.c Sat Oct 31 21:22:18 2009 (r198732)
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon at FreeBSD.org>
* Copyright 2004 John-Mark Gurney <jmg at FreeBSD.org>
+ * Copyright (c) 2009 Apple, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -141,6 +142,11 @@ 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,
+ u_long type);
static struct filterops file_filtops =
{ 1, filt_fileattach, NULL, NULL };
@@ -151,6 +157,12 @@ static struct filterops proc_filtops =
{ 0, filt_procattach, filt_procdetach, filt_proc };
static struct filterops timer_filtops =
{ 0, filt_timerattach, filt_timerdetach, 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;
@@ -255,6 +267,7 @@ static struct {
{ &file_filtops }, /* EVFILT_NETDEV */
{ &fs_filtops }, /* EVFILT_FS */
{ &null_filtops }, /* EVFILT_LIO */
+ { &user_filtops }, /* EVFILT_USER */
};
/*
@@ -557,6 +570,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, u_long type)
+{
+ u_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)
{
@@ -717,7 +818,7 @@ kern_kevent(struct thread *td, int fd, i
continue;
kevp->flags &= ~EV_SYSFLAGS;
error = kqueue_register(kq, kevp, td, 1);
- if (error) {
+ if (error || (kevp->flags & EV_RECEIPT)) {
if (nevents != 0) {
kevp->flags = EV_ERROR;
kevp->data = error;
@@ -919,17 +1020,11 @@ findkn:
goto findkn;
}
- if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
- KQ_UNLOCK(kq);
- error = ENOENT;
- goto done;
- }
-
/*
* 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) {
kn = tkn;
tkn = NULL;
if (kn == NULL) {
@@ -968,34 +1063,16 @@ findkn:
goto done;
}
KN_LIST_LOCK(kn);
+ 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 has already been triggered.
- */
- kn->kn_status |= KN_INFLUX;
+ /* No matching knote and the EV_ADD flag is not set. */
KQ_UNLOCK(kq);
- KN_LIST_LOCK(kn);
- kn->kn_sfflags = kev->fflags;
- kn->kn_sdata = kev->data;
- kn->kn_kevent.udata = kev->udata;
+ error = ENOENT;
+ goto done;
}
-
- /*
- * We can get here with kn->kn_knlist == NULL.
- * This can happen when the initial attach event decides that
- * the event is "completed" already. i.e. filt_procattach
- * is called on a zombie process. It will call filt_proc
- * which will remove it from the list, and NULL kn_knlist.
- */
- event = kn->kn_fop->f_event(kn, 0);
- KQ_LOCK(kq);
- if (event)
- KNOTE_ACTIVATE(kn, 1);
- kn->kn_status &= ~KN_INFLUX;
- KN_LIST_UNLOCK(kn);
- } else if (kev->flags & EV_DELETE) {
+ }
+
+ if (kev->flags & EV_DELETE) {
kn->kn_status |= KN_INFLUX;
KQ_UNLOCK(kq);
if (!(kn->kn_status & KN_DETACHED))
@@ -1004,6 +1081,37 @@ findkn:
goto done;
}
+ /*
+ * The user may change some filter values after the initial EV_ADD,
+ * but doing so will not reset any filter which has already been
+ * triggered.
+ */
+ kn->kn_status |= KN_INFLUX;
+ KQ_UNLOCK(kq);
+ KN_LIST_LOCK(kn);
+ kn->kn_kevent.udata = kev->udata;
+ if (!fops->f_isfd && fops->f_touch != NULL) {
+ fops->f_touch(kn, kev, EVENT_REGISTER);
+ } else {
+ kn->kn_sfflags = kev->fflags;
+ kn->kn_sdata = kev->data;
+ }
+
+ /*
+ * We can get here with kn->kn_knlist == NULL. This can happen when
+ * the initial attach event decides that the event is "completed"
+ * already. i.e. filt_procattach is called on a zombie process. It
+ * will call filt_proc which will remove it from the list, and NULL
+ * kn_knlist.
+ */
+done_ev_add:
+ event = kn->kn_fop->f_event(kn, 0);
+ KQ_LOCK(kq);
+ if (event)
+ KNOTE_ACTIVATE(kn, 1);
+ kn->kn_status &= ~KN_INFLUX;
+ KN_LIST_UNLOCK(kn);
+
if ((kev->flags & EV_DISABLE) &&
((kn->kn_status & KN_DISABLED) == 0)) {
kn->kn_status |= KN_DISABLED;
@@ -1183,7 +1291,7 @@ kqueue_scan(struct kqueue *kq, int maxev
struct timeval atv, rtv, ttv;
struct knote *kn, *marker;
int count, timeout, nkev, error, influx;
- int haskqglobal;
+ int haskqglobal, touch;
count = maxevents;
nkev = 0;
@@ -1315,12 +1423,25 @@ start:
influx = 1;
continue;
}
- *kevp = kn->kn_kevent;
+ touch = (!kn->kn_fop->f_isfd &&
+ kn->kn_fop->f_touch != NULL);
+ if (touch)
+ kn->kn_fop->f_touch(kn, kevp, EVENT_PROCESS);
+ else
+ *kevp = kn->kn_kevent;
KQ_LOCK(kq);
KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
- if (kn->kn_flags & EV_CLEAR) {
- kn->kn_data = 0;
- kn->kn_fflags = 0;
+ if (kn->kn_flags & (EV_CLEAR | EV_DISPATCH)) {
+ /*
+ * Manually clear knotes who weren't
+ * 'touch'ed.
+ */
+ if (touch == 0 && kn->kn_flags & EV_CLEAR) {
+ kn->kn_data = 0;
+ kn->kn_fflags = 0;
+ }
+ if (kn->kn_flags & EV_DISPATCH)
+ kn->kn_status |= KN_DISABLED;
kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
kq->kq_count--;
} else
Modified: stable/8/sys/sys/event.h
==============================================================================
--- stable/8/sys/sys/event.h Sat Oct 31 20:59:13 2009 (r198731)
+++ stable/8/sys/sys/event.h Sat Oct 31 21:22:18 2009 (r198732)
@@ -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_); \
@@ -71,6 +72,8 @@ struct kevent {
/* flags */
#define EV_ONESHOT 0x0010 /* only report one occurrence */
#define EV_CLEAR 0x0020 /* clear event state after reporting */
+#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
+#define EV_DISPATCH 0x0080 /* disable event after reporting */
#define EV_SYSFLAGS 0xF000 /* reserved by system */
#define EV_FLAG1 0x2000 /* filter-specific flag */
@@ -79,6 +82,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
*/
@@ -154,11 +176,22 @@ MALLOC_DECLARE(M_KQUEUE);
*/
#define NOTE_SIGNAL 0x08000000
+/*
+ * 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
+
struct filterops {
int f_isfd; /* true if ident == filedescriptor */
int (*f_attach)(struct knote *kn);
void (*f_detach)(struct knote *kn);
int (*f_event)(struct knote *kn, long hint);
+ void (*f_touch)(struct knote *kn, struct kevent *kev, u_long type);
};
/*
@@ -193,6 +226,7 @@ struct knote {
} kn_ptr;
struct filterops *kn_fop;
void *kn_hook;
+ int kn_hookid;
#define kn_id kn_kevent.ident
#define kn_filter kn_kevent.filter
More information about the svn-src-stable-8
mailing list