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 <jle...@freebsd.org>
  * Copyright 2004 John-Mark Gurney <j...@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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to