Subject: interrupting kevent()
To: None <tech-kern@netbsd.org>
From: Antti Kantee <pooka@cs.hut.fi>
List: tech-kern
Date: 10/23/2007 15:45:49
--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

Hi,

I have a dual eventloop/thread model and I need to interrupt the event
call from a thread sometimes.  I didn't find any sensible way of doing
this, so I added a KEVENT_TICKLE ioctl() to kqueue for interrupting
the wait.

Did I miss something or does the following look ok?

-- 
Antti Kantee <pooka@iki.fi>                     Of course he runs NetBSD
http://www.iki.fi/pooka/                          http://www.NetBSD.org/
    "la qualité la plus indispensable du cuisinier est l'exactitude"

--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="kqueue.patch"

Index: kern/kern_event.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_event.c,v
retrieving revision 1.41
diff -p -u -r1.41 kern_event.c
--- kern/kern_event.c	8 Oct 2007 15:12:07 -0000	1.41
+++ kern/kern_event.c	23 Oct 2007 12:28:23 -0000
@@ -956,7 +956,7 @@ kqueue_scan(struct file *fp, size_t maxe
 	kevp = kq->kq_kev;
 	s = splsched();
 	simple_lock(&kq->kq_lock);
-	if (kq->kq_count == 0) {
+	if (kq->kq_count == 0 && (kq->kq_state & KQ_TICKLED) == 0) {
 		if (timeout < 0) {
 			error = EWOULDBLOCK;
 			simple_unlock(&kq->kq_lock);
@@ -976,6 +976,14 @@ kqueue_scan(struct file *fp, size_t maxe
 		goto done;
 	}
 
+	if (kq->kq_state & KQ_TICKLED) {
+		kq->kq_state &= ~KQ_TICKLED;
+		simple_unlock(&kq->kq_lock);
+		splx(s);
+		error = EINTR;
+		goto done;
+	}
+
 	/* mark end of knote list */
 	TAILQ_INSERT_TAIL(&kq->kq_head, marker, kn_tqe);
 	simple_unlock(&kq->kq_lock);
@@ -1098,6 +1106,9 @@ kqueue_write(struct file *fp, off_t *off
  *	KFILTER_BYNAME		find name for filter, and return result in
  *				name, which is of size len.
  *	KFILTER_BYFILTER	find filter for name. len is ignored.
+ *
+ * A third can be used to wake up a kevent:
+ *	KEVENT_TICKLE
  */
 /*ARGSUSED*/
 static int
@@ -1105,9 +1116,11 @@ kqueue_ioctl(struct file *fp, u_long com
 {
 	struct kfilter_mapping	*km;
 	const struct kfilter	*kfilter;
+	struct kqueue		*kq;
 	char			*name;
 	int			error;
 
+	kq = (struct kqueue *)fp->f_data;
 	km = (struct kfilter_mapping *)data;
 	error = 0;
 
@@ -1136,6 +1149,13 @@ kqueue_ioctl(struct file *fp, u_long com
 		FREE(name, M_KEVENT);
 		break;
 
+	case KEVENT_TICKLE:
+		simple_lock(&kq->kq_lock);
+		kq->kq_state |= KQ_TICKLED;
+		simple_unlock(&kq->kq_lock);
+		kqueue_wakeup(kq);
+		break;
+
 	default:
 		error = ENOTTY;
 
Index: sys/event.h
===================================================================
RCS file: /cvsroot/src/sys/sys/event.h,v
retrieving revision 1.18
diff -p -u -r1.18 event.h
--- sys/event.h	21 Jul 2007 19:20:40 -0000	1.18
+++ sys/event.h	23 Oct 2007 12:28:26 -0000
@@ -141,6 +141,7 @@ struct kfilter_mapping {
 #define KFILTER_BYFILTER	_IOWR('k', 0, struct kfilter_mapping)
 /* map name to filter (len ignored) */
 #define KFILTER_BYNAME		_IOWR('k', 1, struct kfilter_mapping)
+#define KEVENT_TICKLE		_IO('k', 2)
 
 #ifdef _KERNEL
 #include <sys/mallocvar.h>		/* for malloc types */
Index: sys/eventvar.h
===================================================================
RCS file: /cvsroot/src/sys/sys/eventvar.h,v
retrieving revision 1.7
diff -p -u -r1.7 eventvar.h
--- sys/eventvar.h	8 Oct 2007 15:45:54 -0000	1.7
+++ sys/eventvar.h	23 Oct 2007 12:28:29 -0000
@@ -45,6 +45,7 @@ struct kqueue {
 	struct filedesc *kq_fdp;
 	int		kq_state;
 #define	KQ_SLEEP	0x01
+#define	KQ_TICKLED	0x02
 	struct kevent	kq_kev[KQ_NEVENTS];
 };
 

--YiEDa0DAkWCtVeE4--