summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes7
-rw-r--r--ev.c35
-rw-r--r--ev_epoll.c24
-rw-r--r--ev_poll.c2
4 files changed, 38 insertions, 30 deletions
diff --git a/Changes b/Changes
index b6a771c..fe8324b 100644
--- a/Changes
+++ b/Changes
@@ -1,6 +1,13 @@
Revision history for libev, a high-performance and full-featured event loop.
WISH? monotonic clocks times/GetTickCount for coarse corrections?
+
+ - further optimise away the EPOLL_CTL_ADD/MOD combo in the epoll
+ backend by assuming the kernel event mask hasn't changed if
+ ADD fails with EEXIST.
+ - use memset to initialise most arrays now and do away with the
+ init functions.
+
3.45 Tue Oct 21 21:59:26 CEST 2008
- disable inotify usage on linux <2.6.25, as it is broken
(reported by Yoann Vandoorselaere).
diff --git a/ev.c b/ev.c
index 1d041fe..9358364 100644
--- a/ev.c
+++ b/ev.c
@@ -451,6 +451,8 @@ typedef struct
WL head;
unsigned char events;
unsigned char reify;
+ unsigned char emask; /* the epoll backend stores the actual kernel mask in here */
+ unsigned char unused; /* currently unused padding */
#if EV_SELECT_IS_WINSOCKET
SOCKET handle;
#endif
@@ -613,6 +615,9 @@ array_realloc (int elem, void *base, int *cur, int cnt)
return ev_realloc (base, elem * *cur);
}
+#define array_init_zero(base,count) \
+ memset ((void *)(base), 0, sizeof (*(base)) * (count))
+
#define array_needsize(type,base,cur,cnt,init) \
if (expect_false ((cnt) > (cur))) \
{ \
@@ -665,19 +670,6 @@ queue_events (EV_P_ W *events, int eventcnt, int type)
/*****************************************************************************/
-void inline_size
-anfds_init (ANFD *base, int count)
-{
- while (count--)
- {
- base->head = 0;
- base->events = EV_NONE;
- base->reify = 0;
-
- ++base;
- }
-}
-
void inline_speed
fd_event (EV_P_ int fd, int revents)
{
@@ -977,18 +969,6 @@ static int signalmax;
static EV_ATOMIC_T gotsig;
-void inline_size
-signals_init (ANSIG *base, int count)
-{
- while (count--)
- {
- base->head = 0;
- base->gotsig = 0;
-
- ++base;
- }
-}
-
/*****************************************************************************/
void inline_speed
@@ -2141,11 +2121,12 @@ ev_io_start (EV_P_ ev_io *w)
return;
assert (("ev_io_start called with negative fd", fd >= 0));
+ assert (("ev_io start called with illegal event mask", !(w->events & ~(EV_IOFDSET | EV_READ | EV_WRITE))));
EV_FREQUENT_CHECK;
ev_start (EV_A_ (W)w, 1);
- array_needsize (ANFD, anfds, anfdmax, fd + 1, anfds_init);
+ array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
wlist_add (&anfds[fd].head, (WL)w);
fd_change (EV_A_ fd, w->events & EV_IOFDSET | 1);
@@ -2347,7 +2328,7 @@ ev_signal_start (EV_P_ ev_signal *w)
sigprocmask (SIG_SETMASK, &full, &prev);
#endif
- array_needsize (ANSIG, signals, signalmax, w->signum, signals_init);
+ array_needsize (ANSIG, signals, signalmax, w->signum, array_init_zero);
#ifndef _WIN32
sigprocmask (SIG_SETMASK, &prev, 0);
diff --git a/ev_epoll.c b/ev_epoll.c
index 934e8e3..e36dbcc 100644
--- a/ev_epoll.c
+++ b/ev_epoll.c
@@ -57,20 +57,34 @@
#include <sys/epoll.h>
+void inline_size
+unsigned_char_init (unsigned char *base, int count)
+{
+ /* memset might be overkill */
+ while (count--)
+ *base++ = 0;
+}
+
static void
epoll_modify (EV_P_ int fd, int oev, int nev)
{
struct epoll_event ev;
+ unsigned char oldmask;
/*
* we handle EPOLL_CTL_DEL by ignoring it here
* on the assumption that the fd is gone anyways
* if that is wrong, we have to handle the spurious
* event in epoll_poll.
+ * the fd is later added, we try to ADD it, and, if that
+ * fails, we assume it still has the same eventmask.
*/
if (!nev)
return;
+ oldmask = anfds [fd].emask;
+ anfds [fd].emask = nev;
+
ev.data.u64 = fd; /* use u64 to fully initialise the struct, for nicer strace etc. */
ev.events = (nev & EV_READ ? EPOLLIN : 0)
| (nev & EV_WRITE ? EPOLLOUT : 0);
@@ -80,7 +94,7 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
if (expect_true (errno == ENOENT))
{
- /* on ENOENT the fd went away, so try to do the right thing */
+ /* if ENOENT then the fd went away, so try to do the right thing */
if (!nev)
return;
@@ -89,8 +103,9 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
}
else if (expect_true (errno == EEXIST))
{
- /* on EEXIST we ignored a previous DEL */
- if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev))
+ /* EEXIST means we ignored a previous DEL, but the fd is still active */
+ /* if the kernel mask is the same as the new mask, we assume it hasn't changed */
+ if (oldmask == nev || !epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev))
return;
}
@@ -122,7 +137,10 @@ epoll_poll (EV_P_ ev_tstamp timeout)
if (expect_false (got & ~want))
{
+ anfds [fd].emask = want;
+
/* we received an event but are not interested in it, try mod or del */
+ /* I don't think we ever need MOD, but let's handle it anyways */
ev->events = (want & EV_READ ? EPOLLIN : 0)
| (want & EV_WRITE ? EPOLLOUT : 0);
diff --git a/ev_poll.c b/ev_poll.c
index 4a9efdc..e9f5e51 100644
--- a/ev_poll.c
+++ b/ev_poll.c
@@ -42,6 +42,8 @@
void inline_size
pollidx_init (int *base, int count)
{
+ /* consider using memset (.., -1, ...), which is pratically guarenteed
+ * to work on all systems implementing poll */
while (count--)
*base++ = -1;
}