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>