INCLUDEDIR=
DEVS=
EMBEDDED=
+POLL=
for x do
opt=${x%%=*}
--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;;
echo "#define HAVE_SPAWN_H" >>$CONFIG_H
fi
-if [ -z "$POLLTS" ]; then
- printf "Testing for pollts ... "
- cat <<EOF >_pollts.c
-#include <poll.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <time.h>
+if [ -z "$POLL" ]; then
+ printf "Testing for epoll ... "
+ cat <<EOF >_epoll.c
+#ifdef __linux__
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+#error kernel has buggy epoll_wait timeout
+#endif
+#endif
+
+#include <sys/epoll.h>
+#include <unistd.h>
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 <<EOF >_ppoll.c
#include <poll.h>
}
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 <<EOF >_pselect.c
#include <sys/select.h>
}
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
#include <errno.h>
#include <limits.h>
-#include <poll.h>
#include <signal.h>
#include <stdlib.h>
+#include <string.h>
#include <syslog.h>
#include "config.h"
#include "dhcpcd.h"
#include "eloop.h"
+#if defined(HAVE_EPOLL)
+#include <sys/epoll.h>
+#define eloop_event_setup_fds(ctx)
+#else
+#include <poll.h>
static void
eloop_event_setup_fds(struct eloop_ctx *ctx)
{
i++;
}
}
+#endif
int
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) {
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
}
}
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
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
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--;
}
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;
}
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 (;;) {
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 ||
(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)
}
/* 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
}
}
}
+#endif
}
return ctx->exitcode;