Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Mar 2002 00:25:50 +0300 (MSK)
From:      Igor Sysoev <is@rambler-co.ru>
To:        freebsd-arch@FreeBSD.ORG
Subject:   kqueue EV_POLL proposal
Message-ID:  <Pine.BSF.4.21.0203170022150.12995-100000@is>

next in thread | raw e-mail | index | archive | help
Hi,

Suppose event-driven server that have forked to several processes.
Each process listens on the same one or several ports.
All sockets, listening and usual, are non-blocking and checked
via single kevent() call.
If several processes pass listening sockets to kevent() and
some of them ready then all these processes will get event
than will call accept() and many of them will get EAGAIN.


There is workaround for this situation - we can use
mutex (or token) to allow passing listening sockets to kevent().
But before (or after) each iteration we need to delete
previous not ready listening sockets if we have not acquired
mutex (or token). Code is following:
----
if (accept_mutex_locked = accept_mutex_trylock())
    for each listening sockets
        EV_SET(socket, EV_READ, EV_ADD|EV_ONESHOT);
else
    for each PREVIOUS NOT ready listening sockets
        EV_SET(socket, EV_READ, EV_DELETE);
   
kevent(changelist, eventlist);

for each ready listening sockets
    accept()

if (accept_mutex_locked)
    accept_mutex_unlock();

process other events   
----

I think that kqueue should have EV_POLL action (or flag) with following
sense - it's like EV_ONESHOT flag but if filter right now has no event
then it's removed, i.e. this filter lives for single kevent() call.
Than code can be clearer:
----
if (accept_mutex_locked = accept_mutex_trylock())
    for each listening sockets
        EV_SET(socket, EV_READ, EV_POLL);

kevent(changelist, eventlist);

for each ready listening sockets
    accept()

if (accept_mutex_locked)
    accept_mutex_unlock();

process other events   
----

Here is small tested patch made on FreeBSD-4.3.
It can be downloaded from http://sysoev.ru/freebsd/patch.ev_poll.txt
----
--- src/sys/sys/event.h	Mon Feb 26 07:23:21 2001
+++ src/sys/sys/event.h	Sat Mar 16 22:56:54 2002
@@ -61,6 +61,7 @@
 #define EV_DELETE	0x0002		/* delete event from kq */
 #define EV_ENABLE	0x0004		/* enable event */
 #define EV_DISABLE	0x0008		/* disable event (not reported) */
+#define EV_POLL		0x0040		/* poll event */
 
 /* flags */
 #define EV_ONESHOT	0x0010		/* only report one occurrence */
--- src/sys/kern/kern_event.c	Mon Feb 26 07:23:15 2001
+++ src/sys/kern/kern_event.c	Sat Mar 16 22:52:19 2002
@@ -414,7 +414,7 @@
 		}
 	}
 
-	if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
+	if (kn == NULL && ((kev->flags & (EV_ADD|EV_POLL)) == 0)) {
 		error = ENOENT;
 		goto done;
 	}
@@ -422,7 +422,7 @@
 	/*
 	 * kn now contains the matching knote, or NULL if no match
 	 */
-	if (kev->flags & EV_ADD) {
+	if (kev->flags & (EV_ADD|EV_POLL)) {
 
 		if (kn == NULL) {
 			kn = knote_alloc();
@@ -465,6 +465,11 @@
 		s = splhigh();
 		if (kn->kn_fop->f_event(kn, 0))
 			KNOTE_ACTIVATE(kn);
+		else if (kev->flags & EV_POLL) {
+			kn->kn_fop->f_detach(kn);
+			knote_drop(kn, p);
+			goto done;
+                }
 		splx(s);
 
 	} else if (kev->flags & EV_DELETE) {
@@ -585,7 +590,7 @@
 		*kevp = kn->kn_kevent;
 		kevp++;
 		nkev++;
-		if (kn->kn_flags & EV_ONESHOT) {
+		if (kn->kn_flags & (EV_ONESHOT|EV_POLL)) {
 			kn->kn_status &= ~KN_QUEUED;
 			kq->kq_count--;
 			splx(s);
----


Igor Sysoev


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0203170022150.12995-100000>