From: Roy Marples Date: Wed, 4 Mar 2015 11:51:55 +0000 (+0000) Subject: Support epoll(7) X-Git-Tag: v6.8.0~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8dc5723bceb5f01f26eb3170e1690c176c93d9ed;p=thirdparty%2Fdhcpcd.git Support epoll(7) --- diff --git a/configure b/configure index cf91a171..697e368c 100755 --- a/configure +++ b/configure @@ -24,6 +24,7 @@ STATIC= INCLUDEDIR= DEVS= EMBEDDED= +POLL= for x do opt=${x%%=*} @@ -66,13 +67,12 @@ for x do --without-getline) GETLINE=no;; --without-strlcpy) STRLCPY=no;; --without-posix_spawn) POSIX_SPAWN=no;; - --without-pollts) POLLTS=no;; - --with-pollts) POLLTS=$var;; --without-md5) MD5=no;; --without-sha2) SHA2=no;; --without-sha256) SHA2=no;; --without-dev) DEV=no;; --without-udev) UDEV=no;; + --with-poll) POLL="$var";; --serviceexists) SERVICEEXISTS=$var;; --servicecmd) SERVICECMD=$var;; --servicestatus) SERVICESTATUS=$var;; @@ -789,27 +789,34 @@ else echo "#define HAVE_SPAWN_H" >>$CONFIG_H fi -if [ -z "$POLLTS" ]; then - printf "Testing for pollts ... " - cat <_pollts.c -#include -#include -#include -#include +if [ -z "$POLL" ]; then + printf "Testing for epoll ... " + cat <_epoll.c +#ifdef __linux__ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) +#error kernel has buggy epoll_wait timeout +#endif +#endif + +#include +#include int main(void) { - pollts(NULL, 0, NULL, NULL); + epoll_create1(EPOLL_CLOEXEC); + epoll_pwait(-1, NULL, 0, 0, NULL); return 0; } EOF - if $XCC _pollts.c -o _pollts 2>&3; then - POLLTS=yes + if $XCC _epoll.c -o _epoll 2>&3; then + POLL=epoll + echo "#define HAVE_EPOLL" >>$CONFIG_MK + echo "yes" else - POLLTS=no + echo "no" fi - echo "$POLLTS" - rm -f _pollts.c _pollts + rm -f _epoll.c _epoll fi -if [ "$POLLTS" = no ]; then +if [ -z "$POLL" ]; then printf "Testing for ppoll ... " cat <_ppoll.c #include @@ -820,15 +827,14 @@ int main(void) { } EOF if $XCC _ppoll.c -o _ppoll 2>&3; then - POLLTS=ppoll - echo "yes" - else - POLLTS=no - echo "no" - fi + POLL=ppoll + echo "yes" + else + echo "no" + fi rm -f _ppoll.c _ppoll fi -if [ "$POLLTS" = no ]; then +if [ -z "$POLL" ]; then printf "Testing for pselect ... " cat <_pselect.c #include @@ -839,16 +845,16 @@ int main(void) { } EOF if $XCC _pselect.c -o _pselect 2>&3; then - POLLTS=pselect + POLL=pselect echo "yes" else - POLLTS=no echo "no" fi rm -f _pselect.c _pselect fi -case "$POLLTS" in -yes) +case "$POLL" in +epoll) + echo "#define HAVE_EPOLL" >>$CONFIG_H ;; ppoll) echo "#define pollts ppoll" >>$CONFIG_H diff --git a/eloop.c b/eloop.c index da448360..a209f089 100644 --- a/eloop.c +++ b/eloop.c @@ -32,9 +32,9 @@ #include #include -#include #include #include +#include #include #include "config.h" @@ -42,6 +42,11 @@ #include "dhcpcd.h" #include "eloop.h" +#if defined(HAVE_EPOLL) +#include +#define eloop_event_setup_fds(ctx) +#else +#include static void eloop_event_setup_fds(struct eloop_ctx *ctx) { @@ -61,6 +66,7 @@ eloop_event_setup_fds(struct eloop_ctx *ctx) i++; } } +#endif int eloop_event_add(struct eloop_ctx *ctx, int fd, @@ -68,7 +74,19 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, void (*write_cb)(void *), void *write_cb_arg) { struct eloop_event *e; +#ifdef HAVE_EPOLL + struct epoll_event epe, *nfds; +#else struct pollfd *nfds; +#endif + +#ifdef HAVE_EPOLL + memset(&epe, 0, sizeof(epe)); + epe.data.fd = fd; + epe.events = EPOLLIN; + if (write_cb) + epe.events |= EPOLLOUT; +#endif /* We should only have one callback monitoring the fd */ TAILQ_FOREACH(e, &ctx->events, next) { @@ -81,8 +99,14 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, e->write_cb = write_cb; e->write_cb_arg = write_cb_arg; } +#ifdef HAVE_EPOLL + epe.data.ptr = e; + return epoll_ctl(ctx->epoll_fd, EPOLL_CTL_MOD, + fd, &epe); +#else eloop_event_setup_fds(ctx); return 0; +#endif } } @@ -91,34 +115,34 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, TAILQ_REMOVE(&ctx->free_events, e, next); } else { e = malloc(sizeof(*e)); - if (e == NULL) { - syslog(LOG_ERR, "%s: %m", __func__); - return -1; - } + if (e == NULL) + goto err; } /* Ensure we can actually listen to it */ ctx->events_len++; if (ctx->events_len > ctx->fds_len) { + nfds = realloc(ctx->fds, sizeof(*ctx->fds) * (ctx->fds_len+5)); + if (nfds == NULL) + goto err; ctx->fds_len += 5; - nfds = malloc(sizeof(*ctx->fds) * (ctx->fds_len + 5)); - if (nfds == NULL) { - syslog(LOG_ERR, "%s: %m", __func__); - ctx->events_len--; - TAILQ_INSERT_TAIL(&ctx->free_events, e, next); - return -1; - } - ctx->fds_len += 5; - free(ctx->fds); ctx->fds = nfds; } + /* Now populate the structure and add it to the list */ e->fd = fd; e->read_cb = read_cb; e->read_cb_arg = read_cb_arg; e->write_cb = write_cb; e->write_cb_arg = write_cb_arg; + +#ifdef HAVE_EPOLL + epe.data.ptr = e; + if (epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, fd, &epe) == -1) + goto err; +#endif + /* The order of events should not matter. * However, some PPP servers love to close the link right after * sending their final message. So to ensure dhcpcd processes this @@ -128,6 +152,14 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, TAILQ_INSERT_HEAD(&ctx->events, e, next); eloop_event_setup_fds(ctx); return 0; + +err: + syslog(LOG_ERR, "%s: %m", __func__); + if (e) { + ctx->events_len--; + TAILQ_INSERT_TAIL(&ctx->free_events, e, next); + } + return -1; } void @@ -142,6 +174,13 @@ eloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only) e->write_cb_arg = NULL; } else { TAILQ_REMOVE(&ctx->events, e, next); +#ifdef HAVE_EPOLL + /* NULL event is safe because we + * rely on epoll_pwait which as added + * after the delete without event was fixed. */ + epoll_ctl(ctx->epoll_fd, EPOLL_CTL_DEL, + fd, NULL); +#endif TAILQ_INSERT_TAIL(&ctx->free_events, e, next); ctx->events_len--; } @@ -272,7 +311,15 @@ eloop_init(void) TAILQ_INIT(&ctx->timeouts); TAILQ_INIT(&ctx->free_timeouts); ctx->exitcode = EXIT_FAILURE; +#ifdef HAVE_EPOLL + if ((ctx->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) == -1) { + free(ctx); + return NULL; + } +#endif + } + return ctx; } @@ -314,9 +361,12 @@ eloop_start(struct dhcpcd_ctx *dctx) struct eloop_timeout *t; struct timespec now, ts, *tsp; void (*t0)(void *); -#ifndef USE_SIGNALS +#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS) int timeout; #endif +#ifdef HAVE_EPOLL + int i; +#endif ctx = dctx->eloop; for (;;) { @@ -349,10 +399,7 @@ eloop_start(struct dhcpcd_ctx *dctx) break; } -#ifdef USE_SIGNALS - n = pollts(ctx->fds, (nfds_t)ctx->events_len, - tsp, &dctx->sigset); -#else +#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS) if (tsp == NULL) timeout = -1; else if (tsp->tv_sec > INT_MAX / 1000 || @@ -360,9 +407,25 @@ eloop_start(struct dhcpcd_ctx *dctx) (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000)) timeout = INT_MAX; else - timeout = tsp->tv_sec * 1000 + - (tsp->tv_nsec + 999999) / 1000000; - n = poll(ctx->fds, ctx->events_len, timeout); + timeout = (int)(tsp->tv_sec * 1000 + + (tsp->tv_nsec + 999999) / 1000000); +#endif + +#ifdef HAVE_EPOLL +#ifdef USE_SIGNALS + n = epoll_pwait(ctx->epoll_fd, ctx->fds, (int)ctx->events_len, + timeout, &dctx->sigset); +#else + n = epoll_wait(ctx->epoll_fd, ctx->fds, (int)ctx->events_len, + timeout); +#endif +#else +#ifdef USE_SIGNALS + n = pollts(ctx->fds, (nfds_t)ctx->events_len, + tsp, &dctx->sigset); +#else + n = poll(ctx->fds, (nfds_t)ctx->events_len, timeout); +#endif #endif if (n == -1) { if (errno == EINTR) @@ -372,10 +435,34 @@ eloop_start(struct dhcpcd_ctx *dctx) } /* Process any triggered events. */ +#ifdef HAVE_EPOLL + for (i = 0; i < n; i++) { + e = (struct eloop_event *)ctx->fds[i].data.ptr; + if (ctx->fds[i].events & EPOLLOUT && + e->write_cb) + { + e->write_cb(e->write_cb_arg); + /* We need to break here as the + * callback could destroy the next + * fd to process. */ + break; + } + if (ctx->fds[i].events && + ctx->fds[i].events & + (EPOLLIN | EPOLLERR | EPOLLHUP)) + { + e->read_cb(e->read_cb_arg); + /* We need to break here as the + * callback could destroy the next + * fd to process. */ + break; + } + } +#else if (n > 0) { TAILQ_FOREACH(e, &ctx->events, next) { if (e->pollfd->revents & POLLOUT && - e->write_cb) + e->write_cb) { e->write_cb(e->write_cb_arg); /* We need to break here as the @@ -392,6 +479,7 @@ eloop_start(struct dhcpcd_ctx *dctx) } } } +#endif } return ctx->exitcode; diff --git a/eloop.h b/eloop.h index 29bf1fe1..e906dc84 100644 --- a/eloop.h +++ b/eloop.h @@ -30,6 +30,8 @@ #include +#include "config.h" + #ifndef ELOOP_QUEUE #define ELOOP_QUEUE 1 #endif @@ -45,7 +47,9 @@ struct eloop_event { void *read_cb_arg; void (*write_cb)(void *); void *write_cb_arg; +#if !defined(HAVE_EPOLL) struct pollfd *pollfd; +#endif }; struct eloop_timeout { @@ -67,7 +71,12 @@ struct eloop_ctx { void (*timeout0)(void *); void *timeout0_arg; +#ifdef HAVE_EPOLL + int epoll_fd; + struct epoll_event *fds; +#else struct pollfd *fds; +#endif size_t fds_len; int exitnow;