From 533f95ccbf4b28c1a6545386177c08e3401cd998 Mon Sep 17 00:00:00 2001 From: des Date: Wed, 9 Aug 2006 14:49:49 +0000 Subject: [PATCH] Add an epoll()-based acceptor for Linux 2.6. Simple empirical tests indicate that epoll() performs significantly better than poll() (less CPU usage). git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@780 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache_acceptor.c | 122 ++++++++++++++++++++ varnish-cache/configure.ac | 1 + 2 files changed, 123 insertions(+) diff --git a/varnish-cache/bin/varnishd/cache_acceptor.c b/varnish-cache/bin/varnishd/cache_acceptor.c index b09627d3..78892143 100644 --- a/varnish-cache/bin/varnishd/cache_acceptor.c +++ b/varnish-cache/bin/varnishd/cache_acceptor.c @@ -7,10 +7,13 @@ */ #undef ACCEPTOR_USE_KQUEUE +#undef ACCEPTOR_USE_EPOLL #undef ACCEPTOR_USE_POLL #if defined(HAVE_KQUEUE) #define ACCEPTOR_USE_KQUEUE 1 +#elif defined(HAVE_EPOLL_CTL) +#define ACCEPTOR_USE_EPOLL 1 #elif defined(HAVE_POLL) #define ACCEPTOR_USE_POLL 1 #else @@ -260,6 +263,125 @@ vca_return_session(struct sess *sp) #endif /* ACCEPTOR_USE_POLL */ /*====================================================================*/ +#ifdef ACCEPTOR_USE_EPOLL + +#include + +static int epfd = -1; +static int pipes[2]; + +static TAILQ_HEAD(,sess) sesshead = TAILQ_HEAD_INITIALIZER(sesshead); + +static void +vca_add(int fd, void *data) +{ + struct epoll_event ev = { EPOLLIN | EPOLLPRI, { data } }; + AZ(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev)); +} + +static void +vca_del(int fd) +{ + AZ(epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL)); +} + +static void +vca_rcvhdev(struct sess *sp) +{ + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + clock_gettime(CLOCK_MONOTONIC, &sp->t_idle); + TAILQ_INSERT_TAIL(&sesshead, sp, list); + vca_add(sp->fd, sp); +} + +static void +accept_f(int fd) +{ + struct sess *sp; + + sp = vca_accept_sess(fd); + if (sp == NULL) + return; + http_RecvPrep(sp->http); + vca_rcvhdev(sp); +} + +static void * +vca_main(void *arg) +{ + struct epoll_event ev; + struct timespec t; + struct sess *sp, *sp2; + int i; + + (void)arg; + + epfd = epoll_create(16); + assert(epfd >= 0); + + AZ(pipe(pipes)); + vca_add(pipes[0], pipes); + + if (heritage.socket >= 0) + vca_add(heritage.socket, accept_f); + + while (1) { + if (epoll_wait(epfd, &ev, 1, 5000) > 0) { + if (ev.data.ptr == pipes) { + i = read(pipes[0], &sp, sizeof sp); + assert(i == sizeof sp); + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + if (http_RecvPrepAgain(sp->http)) + vca_handover(sp, 0); + else + vca_rcvhdev(sp); + } else if (ev.data.ptr == accept_f) { + accept_f(heritage.socket); + } else { + CAST_OBJ_NOTNULL(sp, ev.data.ptr, SESS_MAGIC); + i = http_RecvSome(sp->fd, sp->http); + if (i != -1) { + TAILQ_REMOVE(&sesshead, sp, list); + vca_del(sp->fd); + vca_handover(sp, i); + } + } + } + /* check for timeouts */ + clock_gettime(CLOCK_MONOTONIC, &t); + TAILQ_FOREACH_SAFE(sp, &sesshead, list, sp2) { + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + if (sp->t_idle.tv_sec + 5 < t.tv_sec) { + TAILQ_REMOVE(&sesshead, sp, list); + vca_del(sp->fd); + vca_close_session(sp, "timeout"); + vca_return_session(sp); + continue; + } + } + } + + INCOMPL(); +} + +/*--------------------------------------------------------------------*/ + +void +vca_return_session(struct sess *sp) +{ + + if (sp->fd < 0) { + SES_Delete(sp); + return; + } + (void)clock_gettime(CLOCK_REALTIME, &sp->t_open); + VSL(SLT_SessionReuse, sp->fd, "%s %s", sp->addr, sp->port); + assert(sizeof sp == write(pipes[1], &sp, sizeof sp)); +} + +#endif /* ACCEPTOR_USE_EPOLL */ +/*====================================================================*/ #ifdef ACCEPTOR_USE_KQUEUE #include diff --git a/varnish-cache/configure.ac b/varnish-cache/configure.ac index 172c37d2..925eb4c7 100644 --- a/varnish-cache/configure.ac +++ b/varnish-cache/configure.ac @@ -90,6 +90,7 @@ AM_CONDITIONAL(NEED_LIBMD, test x$need_libmd = xyes) # Check which mechanism to use for the acceptor AC_CHECK_FUNCS([kqueue]) +AC_CHECK_FUNCS([epoll_ctl]) AC_CHECK_FUNCS([poll]) AC_CONFIG_FILES([ -- 2.39.5