Date: Wed, 16 Sep 2009 03:15:57 +0000 (UTC) From: Stacey Son <sson@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r197240 - in head/sys: kern sys Message-ID: <200909160315.n8G3FvBB010648@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: sson Date: Wed Sep 16 03:15:57 2009 New Revision: 197240 URL: http://svn.freebsd.org/changeset/base/197240 Log: Add optional touch event filter hooks to kevents. The touch event filter is called when a kernel event data is possibly updated. There are two hook points. First, during a kevent() system call. Second, when an event has been triggered. Approved by: rwatson (co-mentor) Modified: head/sys/kern/kern_event.c head/sys/sys/event.h Modified: head/sys/kern/kern_event.c ============================================================================== --- head/sys/kern/kern_event.c Tue Sep 15 22:46:06 2009 (r197239) +++ head/sys/kern/kern_event.c Wed Sep 16 03:15:57 2009 (r197240) @@ -1,6 +1,7 @@ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> * Copyright 2004 John-Mark Gurney <jmg@FreeBSD.org> + * Copyright (c) 2009 Apple, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -934,17 +935,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) { @@ -983,34 +978,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)) @@ -1019,6 +996,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; @@ -1198,7 +1206,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; @@ -1330,12 +1338,23 @@ 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; + /* + * 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); kq->kq_count--; } else Modified: head/sys/sys/event.h ============================================================================== --- head/sys/sys/event.h Tue Sep 15 22:46:06 2009 (r197239) +++ head/sys/sys/event.h Wed Sep 16 03:15:57 2009 (r197240) @@ -154,11 +154,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, long type); }; /* @@ -193,6 +204,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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200909160315.n8G3FvBB010648>