svn commit: r197240 - in head/sys: kern sys

Stacey Son sson at FreeBSD.org
Wed Sep 16 03:15:58 UTC 2009


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


More information about the svn-src-all mailing list