changeset 5301:e6f1372f2cf0 draft

eloop: Just use ppoll(2) epoll and kqueue are really too heavy weight. With privsep, we now favour more processes for BPF and per address sockets. As such, the number of fds to monitor will always be quite small. All modern OS now have ppoll(2) (NetBSD has pollts, which is the same) which works perfectly for us. If neither are present, the a wrapper around pselect(2) is provided, which can be found on all POSIX systems. This makes the code a lot smaller and easier to follow. The reduced binary size and memory usage is a nice win here.
author Roy Marples <roy@marples.name>
date Wed, 03 Jun 2020 23:30:08 +0100
parents d6366bcea63f
children ef799c0ff5cb
files BUILDING.md configure src/dhcpcd.c src/eloop.c src/eloop.h src/privsep-root.c src/privsep.c
diffstat 7 files changed, 121 insertions(+), 563 deletions(-) [+]
line wrap: on
line diff
--- a/BUILDING.md	Wed Jun 03 23:12:59 2020 +0100
+++ b/BUILDING.md	Wed Jun 03 23:30:08 2020 +0100
@@ -129,18 +129,6 @@
 NOTE: in Gentoo at least, `sys-fs/udev` as provided by systemd leaks memory
 `sys-fs/eudev`, the fork of udev does not and as such is recommended.
 
-## select
-dhcpcd uses eloop.c, which is a portable main event loop with timeouts and
-signal handling. Unlike libevent and similar, it can be transplanted directly
-within the application - the only caveat outside of POSIX calls is that
-you provide queue.h based on a recent BSD (glibc sys/queue.h is not enough).
-eloop supports the following polling mechanisms, listed in order of preference:
-	kqueue, epoll, pollts, ppoll and pselect.
-If signal handling is disabled (ie in RTEMS or other single process
-OS's) then eloop can use poll.
-You can decide which polling mechanism dhcpcd will select in eloop like so
-`./configure --with-poll=[kqueue|epoll|pselect|pollts|ppoll]`
-
 
 ## Importing into another source control system
 To import the full sources, use the import target.
@@ -153,8 +141,7 @@
 
 ## Hooks
 Not all the hooks in dhcpcd-hooks are installed by default.
-By default we install `01-test`, `02-dump`, `10-mtu`, `20-resolv.conf`
-and `30-hostname`.
+By default we install `01-test`, `20-resolv.conf`and `30-hostname`.
 The other hooks, `10-wpa_supplicant`, `15-timezone` and `29-lookup-hostname`
 are installed to `$(datadir)/dhcpcd/hooks` by default and need to be
 copied to `$(libexecdir)/dhcpcd-hooks` for use.
--- a/configure	Wed Jun 03 23:12:59 2020 +0100
+++ b/configure	Wed Jun 03 23:30:08 2020 +0100
@@ -1211,65 +1211,42 @@
 echo "#define	HAVE_REALLOCARRAY" >>$CONFIG_H
 
 if [ -z "$POLL" ]; then
-	printf "Testing for kqueue1 ... "
-	cat <<EOF >_kqueue.c
-#include <sys/types.h>
-#include <sys/event.h>
+	printf "Testing for ppoll ... "
+	cat <<EOF >_ppoll.c
+#include <poll.h>
+#include <stddef.h>
 int main(void) {
-	return kqueue1(0);
-}
-EOF
-	if $XCC _kqueue.c -o _kqueue 2>&3; then
-		POLL=kqueue1
- 		echo "yes"
- 	else
- 		echo "no"
- 	fi
-	rm -f _kqueue.c _kqueue
-fi
-if [ -z "$POLL" ]; then
-	printf "Testing for kqueue ... "
-	cat <<EOF >_kqueue.c
-#include <sys/types.h>
-#include <sys/event.h>
-int main(void) {
-	return kqueue();
+	struct pollfd fds;
+	return ppoll(&fds, 1, NULL, NULL);
 }
 EOF
-	if $XCC _kqueue.c -o _kqueue 2>&3; then
-		POLL=kqueue
- 		echo "yes"
- 	else
- 		echo "no"
- 	fi
-	rm -f _kqueue.c _kqueue
-fi
-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) {
-	epoll_create1(EPOLL_CLOEXEC);
-	epoll_pwait(-1, NULL, 0, 0, NULL);
-	return 0;
-}
-EOF
-	if $XCC _epoll.c -o _epoll 2>&3; then
-		POLL=epoll
-		echo "#define	HAVE_EPOLL" >>$CONFIG_MK
+	if $XCC _ppoll.c -o _ppoll 2>&3; then
+		POLL=ppoll
+		echo "#define	HAVE_PPOLL" >>$CONFIG_MK
 		echo "yes"
 	else
 		echo "no"
 	fi
-	rm -f _epoll.c _epoll
+	rm -f _ppoll.c _ppoll
+fi
+if [ -z "$POLL" ]; then
+	printf "Testing for pollts ... "
+	cat <<EOF >_pollts.c
+#include <poll.h>
+#include <stddef.h>
+int main(void) {
+	struct pollfd fds;
+	return pollts(&fds, 1, NULL, NULL);
+}
+EOF
+	if $XCC _pollts.c -o _pollts 2>&3; then
+		POLL=pollts
+		echo "#define	HAVE_PPOLL" >>$CONFIG_MK
+		echo "yes"
+	else
+		echo "no"
+	fi
+	rm -f _pollts.c _pollts
 fi
 if [ -z "$POLL" ]; then
 	printf "Testing for pselect ... "
@@ -1290,22 +1267,12 @@
 	rm -f _pselect.c _pselect
 fi
 case "$POLL" in
-kqueue1)
-	echo "#define	HAVE_KQUEUE" >>$CONFIG_H
-	echo "#define	HAVE_KQUEUE1" >>$CONFIG_H
-	;;
-kqueue)
-	echo "#define	HAVE_KQUEUE" >>$CONFIG_H
-	;;
-epoll)
-	echo "#define	HAVE_EPOLL" >>$CONFIG_H
+ppoll)
+	echo "#define	HAVE_PPOLL" >>$CONFIG_H
 	;;
 pollts)
 	echo "#define	HAVE_POLLTS" >>$CONFIG_H
 	;;
-ppoll)
-	echo "#define	HAVE_PPOLL" >>$CONFIG_H
-	;;
 pselect)
 	echo "#define	HAVE_PSELECT" >>$CONFIG_H
 	;;
--- a/src/dhcpcd.c	Wed Jun 03 23:12:59 2020 +0100
+++ b/src/dhcpcd.c	Wed Jun 03 23:30:08 2020 +0100
@@ -2039,13 +2039,9 @@
 		signal(dhcpcd_signals_ignore[si], SIG_IGN);
 
 	/* Save signal mask, block and redirect signals to our handler */
-	if (eloop_signal_set_cb(ctx.eloop,
+	eloop_signal_set_cb(ctx.eloop,
 	    dhcpcd_signals, dhcpcd_signals_len,
-	    dhcpcd_signal_cb, &ctx) == -1)
-	{
-		logerr("%s: eloop_signal_set_cb", __func__);
-		goto exit_failure;
-	}
+	    dhcpcd_signal_cb, &ctx);
 	if (eloop_signal_mask(ctx.eloop, &ctx.sigset) == -1) {
 		logerr("%s: eloop_signal_mask", __func__);
 		goto exit_failure;
@@ -2211,7 +2207,6 @@
 			logerr("fork");
 			goto exit_failure;
 		case 0:
-			eloop_requeue(ctx.eloop);
 			break;
 		default:
 			ctx.options |= DHCPCD_FORKED; /* A lie */
--- a/src/eloop.c	Wed Jun 03 23:12:59 2020 +0100
+++ b/src/eloop.c	Wed Jun 03 23:30:08 2020 +0100
@@ -26,60 +26,30 @@
  * SUCH DAMAGE.
  */
 
-#if (defined(__unix__) || defined(unix)) && !defined(USG)
-#include <sys/param.h>
-#endif
 #include <sys/time.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
+#include <poll.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-/* config.h should define HAVE_KQUEUE, HAVE_EPOLL, etc. */
+/* config.h should define HAVE_PPOLL, etc. */
 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_H)
 #include "config.h"
 #endif
 
-/* Attempt to autodetect kqueue or epoll.
- * Failing that, fall back to pselect. */
-#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL) && !defined(HAVE_PSELECT) && \
-    !defined(HAVE_POLLTS) && !defined(HAVE_PPOLL)
-#if defined(BSD)
-/* Assume BSD has a working sys/queue.h and kqueue(2) interface. */
-#define HAVE_SYS_QUEUE_H
-#define HAVE_KQUEUE
-#define WARN_SELECT
-#elif defined(__linux__) || defined(__sun)
-/* Assume Linux and Solaris have a working epoll(3) interface. */
-#define HAVE_EPOLL
-#define WARN_SELECT
-#else
-/* pselect(2) is a POSIX standard. */
+#if defined(HAVE_PPOLL)
+#elif defined(HAVE_POLLTS)
+#define ppoll pollts
+#elif !defined(HAVE_PSELECT)
+#pragma message("Compiling eloop with pselect(2) support.")
 #define HAVE_PSELECT
-#define WARN_SELECT
-#endif
-#endif
-
-/* pollts and ppoll require poll.
- * pselect is wrapped in a pollts/ppoll style interface
- * and as such require poll as well. */
-#if defined(HAVE_PSELECT) || defined(HAVE_POLLTS) || defined(HAVE_PPOLL)
-#ifndef HAVE_POLL
-#define HAVE_POLL
-#endif
-#if defined(HAVE_POLLTS)
-#define POLLTS pollts
-#elif defined(HAVE_PPOLL)
-#define POLLTS ppoll
-#else
-#define POLLTS eloop_pollts
-#define ELOOP_NEED_POLLTS
-#endif
+#define ppoll eloop_ppoll
 #endif
 
 #include "eloop.h"
@@ -95,42 +65,9 @@
 #endif
 #endif
 
-#if defined(HAVE_KQUEUE)
-#include <sys/event.h>
-#include <fcntl.h>
-#ifdef __NetBSD__
-/* udata is void * except on NetBSD.
- * lengths are int except on NetBSD. */
-#define UPTR(x)	((intptr_t)(x))
-#define LENC(x)	(x)
-#else
-#define UPTR(x)	(x)
-#define LENC(x)	((int)(x))
-#endif
-#elif defined(HAVE_EPOLL)
-#include <sys/epoll.h>
-#elif defined(HAVE_POLL)
-#if defined(HAVE_PSELECT)
+#ifdef HAVE_PSELECT
 #include <sys/select.h>
 #endif
-#include <poll.h>
-#endif
-
-#ifdef WARN_SELECT
-#if defined(HAVE_KQUEUE)
-#pragma message("Compiling eloop with kqueue(2) support.")
-#elif defined(HAVE_EPOLL)
-#pragma message("Compiling eloop with epoll(7) support.")
-#elif defined(HAVE_PSELECT)
-#pragma message("Compiling eloop with pselect(2) support.")
-#elif defined(HAVE_PPOLL)
-#pragma message("Compiling eloop with ppoll(2) support.")
-#elif defined(HAVE_POLLTS)
-#pragma message("Compiling eloop with pollts(2) support.")
-#else
-#error Unknown select mechanism for eloop
-#endif
-#endif
 
 /* Our structures require TAILQ macros, which really every libc should
  * ship as they are useful beyond belief.
@@ -171,6 +108,7 @@
 	void *read_cb_arg;
 	void (*write_cb)(void *);
 	void *write_cb_arg;
+	struct pollfd *pollfd;
 };
 
 struct eloop_timeout {
@@ -183,11 +121,9 @@
 };
 
 struct eloop {
-	size_t events_len;
 	TAILQ_HEAD (event_head, eloop_event) events;
+	size_t nevents;
 	struct event_head free_events;
-	int events_maxfd;
-	struct eloop_event **event_fds;
 
 	struct timespec now;
 	TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
@@ -200,12 +136,8 @@
 	void (*signal_cb)(int, void *);
 	void *signal_cb_ctx;
 
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-	int poll_fd;
-#elif defined(HAVE_POLL)
 	struct pollfd *fds;
-	size_t fds_len;
-#endif
+	size_t nfds;
 
 	int exitnow;
 	int exitcode;
@@ -229,30 +161,10 @@
 }
 #endif
 
-#ifdef HAVE_POLL
-static void
-eloop_event_setup_fds(struct eloop *eloop)
-{
-	struct eloop_event *e;
-	size_t i;
-
-	i = 0;
-	TAILQ_FOREACH(e, &eloop->events, next) {
-		eloop->fds[i].fd = e->fd;
-		eloop->fds[i].events = 0;
-		if (e->read_cb)
-			eloop->fds[i].events |= POLLIN;
-		if (e->write_cb)
-			eloop->fds[i].events |= POLLOUT;
-		eloop->fds[i].revents = 0;
-		i++;
-	}
-}
-
-#ifdef ELOOP_NEED_POLLTS
-/* Wrapper around pselect, to imitate the NetBSD pollts call. */
+#ifdef HAVE_PSELECT
+/* Wrapper around pselect, to imitate the ppoll call. */
 static int
-eloop_pollts(struct pollfd * fds, nfds_t nfds,
+eloop_ppoll(struct pollfd * fds, nfds_t nfds,
     const struct timespec *ts, const sigset_t *sigmask)
 {
 	fd_set read_fds, write_fds;
@@ -287,10 +199,7 @@
 
 	return r;
 }
-#endif /* pollts */
-#else /* !HAVE_POLL */
-#define eloop_event_setup_fds(a) {}
-#endif /* HAVE_POLL */
+#endif
 
 unsigned long long
 eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp,
@@ -360,19 +269,33 @@
 	eloop->now = now;
 }
 
+static void
+eloop_event_setup_fds(struct eloop *eloop)
+{
+	struct eloop_event *e;
+	struct pollfd *pfd;
+
+	pfd = eloop->fds;
+	TAILQ_FOREACH(e, &eloop->events, next) {
+		e->pollfd = pfd;
+		pfd->fd = e->fd;
+		pfd->events = 0;
+		if (e->read_cb != NULL)
+			pfd->events |= POLLIN;
+		if (e->write_cb != NULL)
+			pfd->events |= POLLOUT;
+		pfd->revents = 0;
+		pfd++;
+	}
+}
+
 int
 eloop_event_add_rw(struct eloop *eloop, int fd,
     void (*read_cb)(void *), void *read_cb_arg,
     void (*write_cb)(void *), void *write_cb_arg)
 {
 	struct eloop_event *e;
-#if defined(HAVE_KQUEUE)
-	struct kevent ke[2];
-#elif defined(HAVE_EPOLL)
-	struct epoll_event epe;
-#elif defined(HAVE_POLL)
-	struct pollfd *nfds;
-#endif
+	struct pollfd *pfd;
 
 	assert(eloop != NULL);
 	assert(read_cb != NULL || write_cb != NULL);
@@ -381,122 +304,41 @@
 		return -1;
 	}
 
-#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. */
-	if (fd <= eloop->events_maxfd) {
-		if ((e = eloop->event_fds[fd]) != NULL) {
-			int error;
-
-#if defined(HAVE_KQUEUE)
-			EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
-			    0, 0, UPTR(e));
-			if (write_cb)
-				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
-				    EV_ADD, 0, 0, UPTR(e));
-			else if (e->write_cb)
-				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
-				    EV_DELETE, 0, 0, UPTR(e));
-			error = kevent(eloop->poll_fd, ke,
-			    e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
-			epe.data.ptr = e;
-			error = epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD,
-			    fd, &epe);
-#else
-			error = 0;
-#endif
-			if (read_cb) {
-				e->read_cb = read_cb;
-				e->read_cb_arg = read_cb_arg;
-			}
-			if (write_cb) {
-				e->write_cb = write_cb;
-				e->write_cb_arg = write_cb_arg;
-			}
-			eloop_event_setup_fds(eloop);
-			return error;
-		}
-	} else {
-		struct eloop_event **new_fds;
-		int maxfd, i;
-
-		/* Reserve ourself and 4 more. */
-		maxfd = fd + 4;
-		new_fds = eloop_realloca(eloop->event_fds,
-		    ((size_t)maxfd + 1), sizeof(*eloop->event_fds));
-		if (new_fds == NULL)
-			return -1;
-
-		/* set new entries NULL as the fd's may not be contiguous. */
-		for (i = maxfd; i > eloop->events_maxfd; i--)
-			new_fds[i] = NULL;
-
-		eloop->event_fds = new_fds;
-		eloop->events_maxfd = maxfd;
+	TAILQ_FOREACH(e, &eloop->events, next) {
+		if (e->fd == fd)
+			break;
 	}
 
-	/* Allocate a new event if no free ones already allocated. */
-	if ((e = TAILQ_FIRST(&eloop->free_events))) {
-		TAILQ_REMOVE(&eloop->free_events, e, next);
-	} else {
-		e = malloc(sizeof(*e));
-		if (e == NULL)
-			goto err;
+	if (e == NULL) {
+		if (eloop->nevents + 1 > eloop->nfds) {
+			pfd = eloop_realloca(eloop->fds, eloop->nevents + 1,
+			    sizeof(*pfd));
+			if (pfd == NULL)
+				return -1;
+			eloop->fds = pfd;
+			eloop->nfds++;
+		}
+
+		e = TAILQ_FIRST(&eloop->free_events);
+		if (e != NULL)
+			TAILQ_REMOVE(&eloop->free_events, e, next);
+		else {
+			e = malloc(sizeof(*e));
+			if (e == NULL)
+				return -1;
+			TAILQ_INSERT_HEAD(&eloop->events, e, next);
+		}
+		e->fd = fd;
+		eloop->nevents++;
 	}
 
-	/* Ensure we can actually listen to it. */
-	eloop->events_len++;
-#ifdef HAVE_POLL
-	if (eloop->events_len > eloop->fds_len) {
-		nfds = eloop_realloca(eloop->fds,
-		    (eloop->fds_len + 5), sizeof(*eloop->fds));
-		if (nfds == NULL)
-			goto err;
-		eloop->fds_len += 5;
-		eloop->fds = nfds;
-	}
-#endif
-
-	/* 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;
 
-#if defined(HAVE_KQUEUE)
-	if (read_cb != NULL)
-		EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
-		    EV_ADD, 0, 0, UPTR(e));
-	if (write_cb != NULL)
-		EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
-		    EV_ADD, 0, 0, UPTR(e));
-	if (kevent(eloop->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
-		goto err;
-#elif defined(HAVE_EPOLL)
-	epe.data.ptr = e;
-	if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
-		goto err;
-#endif
-
-	TAILQ_INSERT_HEAD(&eloop->events, e, next);
-	eloop->event_fds[e->fd] = e;
 	eloop_event_setup_fds(eloop);
 	return 0;
-
-err:
-	if (e) {
-		eloop->events_len--;
-		TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
-	}
-	return -1;
 }
 
 int
@@ -519,17 +361,14 @@
 eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
 {
 	struct eloop_event *e;
-#if defined(HAVE_KQUEUE)
-	struct kevent ke[2];
-#elif defined(HAVE_EPOLL)
-	struct epoll_event epe;
-#endif
 
 	assert(eloop != NULL);
 
-	if (fd > eloop->events_maxfd ||
-	    (e = eloop->event_fds[fd]) == NULL)
-	{
+	TAILQ_FOREACH(e, &eloop->events, next) {
+		if (e->fd == fd)
+			break;
+	}
+	if (e == NULL) {
 		errno = ENOENT;
 		return -1;
 	}
@@ -541,41 +380,15 @@
 			goto remove;
 		e->write_cb = NULL;
 		e->write_cb_arg = NULL;
-#if defined(HAVE_KQUEUE)
-		EV_SET(&ke[0], (uintptr_t)e->fd,
-		    EVFILT_WRITE, EV_DELETE, 0, 0, UPTR(NULL));
-		kevent(eloop->poll_fd, ke, 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
-		memset(&epe, 0, sizeof(epe));
-		epe.data.fd = e->fd;
-		epe.data.ptr = e;
-		epe.events = EPOLLIN;
-		epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD, fd, &epe);
-#endif
-		eloop_event_setup_fds(eloop);
-		return 1;
+		goto done;
 	}
 
 remove:
 	TAILQ_REMOVE(&eloop->events, e, next);
-	eloop->event_fds[e->fd] = NULL;
 	TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
-	eloop->events_len--;
+	eloop->nevents--;
 
-#if defined(HAVE_KQUEUE)
-	EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
-	    EV_DELETE, 0, 0, UPTR(NULL));
-	if (e->write_cb)
-		EV_SET(&ke[1], (uintptr_t)fd,
-		    EVFILT_WRITE, EV_DELETE, 0, 0, UPTR(NULL));
-	kevent(eloop->poll_fd, ke, e->write_cb ? 2 : 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
-	/* NULL event is safe because we
-	 * rely on epoll_pwait which as added
-	 * after the delete without event was fixed. */
-	epoll_ctl(eloop->poll_fd, EPOLL_CTL_DEL, fd, NULL);
-#endif
-
+done:
 	eloop_event_setup_fds(eloop);
 	return 1;
 }
@@ -681,7 +494,6 @@
 		(unsigned int)seconds, (unsigned int)nseconds, callback, arg);
 }
 
-#if !defined(HAVE_KQUEUE)
 static int
 eloop_timeout_add_now(struct eloop *eloop,
     void (*callback)(void *), void *arg)
@@ -692,7 +504,6 @@
 	eloop->timeout0_arg = arg;
 	return 0;
 }
-#endif
 
 int
 eloop_q_timeout_delete(struct eloop *eloop, int queue,
@@ -734,106 +545,7 @@
 	eloop->exitnow = 0;
 }
 
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-static int
-eloop_open(struct eloop *eloop)
-{
-
-#if defined(HAVE_KQUEUE1)
-	return (eloop->poll_fd = kqueue1(O_CLOEXEC));
-#elif defined(HAVE_KQUEUE)
-	int i;
-
-	if ((eloop->poll_fd = kqueue()) == -1)
-		return -1;
-	if ((i = fcntl(eloop->poll_fd, F_GETFD, 0)) == -1 ||
-	    fcntl(eloop->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
-	{
-		close(eloop->poll_fd);
-		eloop->poll_fd = -1;
-	}
-
-	return eloop->poll_fd;
-#elif defined (HAVE_EPOLL)
-	return (eloop->poll_fd = epoll_create1(EPOLL_CLOEXEC));
-#else
-	return (eloop->poll_fd = -1);
-#endif
-}
-#endif
-
-int
-eloop_requeue(struct eloop *eloop)
-{
-#if defined(HAVE_POLL)
-
-	UNUSED(eloop);
-	return 0;
-#else /* !HAVE_POLL */
-	struct eloop_event *e;
-	int error;
-#if defined(HAVE_KQUEUE)
-	size_t i;
-	struct kevent *ke;
-#elif defined(HAVE_EPOLL)
-	struct epoll_event epe;
-#endif
-
-	assert(eloop != NULL);
-
-	if (eloop->poll_fd != -1)
-		close(eloop->poll_fd);
-	if (eloop_open(eloop) == -1)
-		return -1;
-#if defined (HAVE_KQUEUE)
-	i = eloop->signals_len;
-	TAILQ_FOREACH(e, &eloop->events, next) {
-		i++;
-		if (e->write_cb)
-			i++;
-	}
-
-	if ((ke = malloc(sizeof(*ke) * i)) == NULL)
-		return -1;
-
-	for (i = 0; i < eloop->signals_len; i++)
-		EV_SET(&ke[i], (uintptr_t)eloop->signals[i],
-		    EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
-
-	TAILQ_FOREACH(e, &eloop->events, next) {
-		EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
-		    EV_ADD, 0, 0, UPTR(e));
-		i++;
-		if (e->write_cb) {
-			EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
-			    EV_ADD, 0, 0, UPTR(e));
-			i++;
-		}
-	}
-
-	error =  kevent(eloop->poll_fd, ke, LENC(i), NULL, 0, NULL);
-	free(ke);
-
-#elif defined(HAVE_EPOLL)
-
-	error = 0;
-	TAILQ_FOREACH(e, &eloop->events, next) {
-		memset(&epe, 0, sizeof(epe));
-		epe.data.fd = e->fd;
-		epe.events = EPOLLIN;
-		if (e->write_cb)
-			epe.events |= EPOLLOUT;
-		epe.data.ptr = e;
-		if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
-			error = -1;
-	}
-#endif
-
-	return error;
-#endif /* HAVE_POLL */
-}
-
-int
+void
 eloop_signal_set_cb(struct eloop *eloop,
     const int *signals, size_t signals_len,
     void (*signal_cb)(int, void *), void *signal_cb_ctx)
@@ -845,10 +557,8 @@
 	eloop->signals_len = signals_len;
 	eloop->signal_cb = signal_cb;
 	eloop->signal_cb_ctx = signal_cb_ctx;
-	return eloop_requeue(eloop);
 }
 
-#ifndef HAVE_KQUEUE
 struct eloop_siginfo {
 	int sig;
 	struct eloop *eloop;
@@ -876,16 +586,16 @@
 	eloop_timeout_add_now(_eloop_siginfo.eloop,
 	    eloop_signal1, &_eloop_siginfo);
 }
-#endif
 
 int
 eloop_signal_mask(struct eloop *eloop, sigset_t *oldset)
 {
 	sigset_t newset;
 	size_t i;
-#ifndef HAVE_KQUEUE
-	struct sigaction sa;
-#endif
+	struct sigaction sa = {
+	    .sa_sigaction = eloop_signal3,
+	    .sa_flags = SA_SIGINFO,
+	};
 
 	assert(eloop != NULL);
 
@@ -895,19 +605,13 @@
 	if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
 		return -1;
 
-#ifndef HAVE_KQUEUE
 	_eloop = eloop;
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sa_sigaction = eloop_signal3;
-	sa.sa_flags = SA_SIGINFO;
 	sigemptyset(&sa.sa_mask);
 
 	for (i = 0; i < eloop->signals_len; i++) {
 		if (sigaction(eloop->signals[i], &sa, NULL) == -1)
 			return -1;
 	}
-#endif
 	return 0;
 }
 
@@ -927,19 +631,11 @@
 	}
 
 	TAILQ_INIT(&eloop->events);
-	eloop->events_maxfd = -1;
 	TAILQ_INIT(&eloop->free_events);
 	TAILQ_INIT(&eloop->timeouts);
 	TAILQ_INIT(&eloop->free_timeouts);
 	eloop->exitcode = EXIT_FAILURE;
 
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-	if (eloop_open(eloop) == -1) {
-		eloop_free(eloop);
-		return NULL;
-	}
-#endif
-
 	return eloop;
 }
 
@@ -952,10 +648,7 @@
 	if (eloop == NULL)
 		return;
 
-	free(eloop->event_fds);
-	eloop->event_fds = NULL;
-	eloop->events_len = 0;
-	eloop->events_maxfd = -1;
+	eloop->nevents = 0;
 	eloop->signals = NULL;
 	eloop->signals_len = 0;
 
@@ -976,21 +669,15 @@
 		free(t);
 	}
 
-#if defined(HAVE_POLL)
 	free(eloop->fds);
 	eloop->fds = NULL;
-	eloop->fds_len = 0;
-#endif
+	eloop->nfds = 0;
 }
 
 void
 eloop_free(struct eloop *eloop)
 {
 
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-	if (eloop != NULL)
-		close(eloop->poll_fd);
-#endif
 	eloop_clear(eloop);
 	free(eloop);
 }
@@ -1002,18 +689,7 @@
 	struct eloop_event *e;
 	struct eloop_timeout *t;
 	void (*t0)(void *);
-#if defined(HAVE_KQUEUE)
-	struct kevent ke;
-	UNUSED(signals);
-#elif defined(HAVE_EPOLL)
-	struct epoll_event epe;
-#endif
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
 	struct timespec ts, *tsp;
-#endif
-#ifndef HAVE_KQUEUE
-	int timeout;
-#endif
 
 	assert(eloop != NULL);
 
@@ -1030,7 +706,7 @@
 		}
 
 		t = TAILQ_FIRST(&eloop->timeouts);
-		if (t == NULL && eloop->events_len == 0)
+		if (t == NULL && eloop->nevents == 0)
 			break;
 
 		if (t != NULL)
@@ -1044,7 +720,6 @@
 		}
 
 		if (t != NULL) {
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
 			if (t->seconds > INT_MAX) {
 				ts.tv_sec = (time_t)INT_MAX;
 				ts.tv_nsec = 0;
@@ -1053,43 +728,10 @@
 				ts.tv_nsec = (long)t->nseconds;
 			}
 			tsp = &ts;
-#endif
-
-#ifndef HAVE_KQUEUE
-			if (t->seconds > INT_MAX / 1000 ||
-			    (t->seconds == INT_MAX / 1000 &&
-			    ((t->nseconds + 999999) / 1000000
-			    > INT_MAX % 1000000)))
-				timeout = INT_MAX;
-			else
-				timeout = (int)(t->seconds * 1000 +
-				    (t->nseconds + 999999) / 1000000);
-#endif
-		} else {
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
+		} else
 			tsp = NULL;
-#endif
-#ifndef HAVE_KQUEUE
-			timeout = -1;
-#endif
-		}
 
-#if defined(HAVE_KQUEUE)
-		n = kevent(eloop->poll_fd, NULL, 0, &ke, 1, tsp);
-#elif defined(HAVE_EPOLL)
-		if (signals)
-			n = epoll_pwait(eloop->poll_fd, &epe, 1,
-			    timeout, signals);
-		else
-			n = epoll_wait(eloop->poll_fd, &epe, 1, timeout);
-#elif defined(HAVE_POLL)
-		if (signals)
-			n = POLLTS(eloop->fds, (nfds_t)eloop->events_len,
-			    tsp, signals);
-		else
-			n = poll(eloop->fds, (nfds_t)eloop->events_len,
-			    timeout);
-#endif
+		n = ppoll(eloop->fds, (nfds_t)eloop->nevents, tsp, signals);
 		if (n == -1) {
 			if (errno == EINTR)
 				continue;
@@ -1098,47 +740,20 @@
 		if (n == 0)
 			continue;
 
-		/* Process any triggered events.
-		 * We go back to the start after calling each callback incase
-		 * the current event or next event is removed. */
-#if defined(HAVE_KQUEUE)
-		if (ke.filter == EVFILT_SIGNAL) {
-			eloop->signal_cb((int)ke.ident,
-			    eloop->signal_cb_ctx);
-		} else {
-			e = (struct eloop_event *)ke.udata;
-			if (ke.filter == EVFILT_WRITE && e->write_cb != NULL)
-				e->write_cb(e->write_cb_arg);
-			else if (ke.filter == EVFILT_READ && e->read_cb != NULL)
-				e->read_cb(e->read_cb_arg);
-		}
-#elif defined(HAVE_EPOLL)
-		e = (struct eloop_event *)epe.data.ptr;
-		if (epe.events & EPOLLOUT && e->write_cb != NULL)
-			e->write_cb(e->write_cb_arg);
-		else if (epe.events & (EPOLLIN | EPOLLERR | EPOLLHUP) &&
-		    e->read_cb != NULL)
-			e->read_cb(e->read_cb_arg);
-#elif defined(HAVE_POLL)
-		size_t i;
-
-		for (i = 0; i < eloop->events_len; i++) {
-			if (eloop->fds[i].revents & POLLOUT) {
-				e = eloop->event_fds[eloop->fds[i].fd];
+		TAILQ_FOREACH(e, &eloop->events, next) {
+			if (e->pollfd->revents & POLLOUT) {
 				if (e->write_cb != NULL) {
 					e->write_cb(e->write_cb_arg);
 					break;
 				}
 			}
-			if (eloop->fds[i].revents) {
-				e = eloop->event_fds[eloop->fds[i].fd];
+			if (e->pollfd->revents) {
 				if (e->read_cb != NULL) {
 					e->read_cb(e->read_cb_arg);
 					break;
 				}
 			}
 		}
-#endif
 	}
 
 	return eloop->exitcode;
--- a/src/eloop.h	Wed Jun 03 23:12:59 2020 +0100
+++ b/src/eloop.h	Wed Jun 03 23:30:08 2020 +0100
@@ -83,12 +83,11 @@
     unsigned long, void (*)(void *), void *);
 int eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
 
-int eloop_signal_set_cb(struct eloop *, const int *, size_t,
+void eloop_signal_set_cb(struct eloop *, const int *, size_t,
     void (*)(int, void *), void *);
 int eloop_signal_mask(struct eloop *, sigset_t *oldset);
 
 struct eloop * eloop_new(void);
-int eloop_requeue(struct eloop *);
 void eloop_clear(struct eloop *);
 void eloop_free(struct eloop *);
 void eloop_exit(struct eloop *, int);
--- a/src/privsep-root.c	Wed Jun 03 23:12:59 2020 +0100
+++ b/src/privsep-root.c	Wed Jun 03 23:30:08 2020 +0100
@@ -788,10 +788,9 @@
 	if ((ctx->ps_eloop = eloop_new()) == NULL)
 		return -1;
 
-	if (eloop_signal_set_cb(ctx->ps_eloop,
+	eloop_signal_set_cb(ctx->ps_eloop,
 	    dhcpcd_signals, dhcpcd_signals_len,
-	    ps_root_readerrorsig, ctx) == -1)
-		return -1;
+	    ps_root_readerrorsig, ctx);
 
 	return pid;
 }
--- a/src/privsep.c	Wed Jun 03 23:12:59 2020 +0100
+++ b/src/privsep.c	Wed Jun 03 23:30:08 2020 +0100
@@ -243,12 +243,8 @@
 		ctx->ps_inet_fd = -1;
 	}
 
-	if (eloop_signal_set_cb(ctx->eloop,
-	    dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx) == -1)
-	{
-		logerr("%s: eloop_signal_set_cb", __func__);
-		goto errexit;
-	}
+	eloop_signal_set_cb(ctx->eloop,
+	    dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx);
 
 	/* ctx->sigset aready has the initial sigmask set in main() */
 	if (eloop_signal_mask(ctx->eloop, NULL) == -1) {