Subject: Re: interrupting kevent()
To: Bill Stouder-Studenmund <>
From: Antti Kantee <>
List: tech-kern
Date: 10/25/2007 13:44:05
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

On Wed Oct 24 2007 at 22:52:51 -0700, Bill Stouder-Studenmund wrote:
> The canonical way I know to do this is to create a pipe and add a kevent
> to listen to it. That way you get what you want w/o any kernel mods. Plus,
> if you use an atomic write (everything in one write{,v}() call), then you
> can use the write to the pipe as a form of ITC (Inter-Thread
> Communication) - not only do you wake the thread, but you carry the
> message w/o needing locks on the sending side.

Yes, but see other mails in the thread.  And no are locks needed now

> The concern/objection I have to what you do have is that it doesn't follow 
> kevent methodology. I think your kevent should show up as an event. As it 
> stands, you only get an event if there is nothing else going on, and it 
> shows up out-of-band with the events. A busy server could delay 
> conveying the "tickle" for a few system calls.

Except it isn't a real event.  A signal doesn't show up as a real event.
A timeout doesn't show up as a real event.  Why should this?

There was a bug in the patch which caused a tickle to be returned even
if there were real events pending.  That was unintentional (obviously).
I'm attaching a new version where this is fixed.

> So I'd like to politely ask you to go back to the drawing board. While I 
> think something other than a pipe could be cute, I think we should do 
> something that will work in more cases than just your current one.

Unfortunately with just vague handwaving I have no idea of what you
want here.  Pending the kitchen_sink.h design, I'll use this method in
my local tree and commit something general.

Antti Kantee <>                     Of course he runs NetBSD                
    "la qualité la plus indispensable du cuisinier est l'exactitude"

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

Index: 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_event.c	8 Oct 2007 15:12:07 -0000	1.41
+++ kern_event.c	25 Oct 2007 10:33:23 -0000
@@ -958,8 +958,11 @@ kqueue_scan(struct file *fp, size_t maxe
 	if (kq->kq_count == 0) {
 		if (timeout < 0) {
+			simple_unlock(&kq->kq_lock);
 			error = EWOULDBLOCK;
+		} else if (kq->kq_state & KQ_TICKLED) {
+			error = EINTR;
 		} else {
 			kq->kq_state |= KQ_SLEEP;
 			error = ltsleep(kq, PSOCK | PCATCH | PNORELOCK,
@@ -1061,6 +1064,11 @@ kqueue_scan(struct file *fp, size_t maxe
 		    &kq->kq_kev[0], ulistp, nevents, nkev);
 	*retval = maxevents - count;
+	/* We are returning, clear tickle-indicator */
+	simple_lock(&kq->kq_lock);
+	kq->kq_state &= ~KQ_TICKLED;
+	simple_unlock(&kq->kq_lock);
 	return (error);
@@ -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:
 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);
+		simple_lock(&kq->kq_lock);
+		kq->kq_state |= KQ_TICKLED;
+		simple_unlock(&kq->kq_lock);
+		kqueue_wakeup(kq);
+		break;
 		error = ENOTTY;