From: Roy Marples Date: Wed, 3 Jun 2020 22:30:08 +0000 (+0100) Subject: eloop: Just use ppoll(2) X-Git-Tag: v9.1.1~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f16f1f6245649b1784da9835ff580d280ede1bf;p=thirdparty%2Fdhcpcd.git 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. --- diff --git a/BUILDING.md b/BUILDING.md index 3540557d..f672724a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -129,18 +129,6 @@ You can disable this with `--without-dev`, or `without-udev`. 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 @@ Example: `make DESTDIR=/usr/src/contrib/dhcpcd import-src` ## 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. diff --git a/configure b/configure index e82be878..b2532680 100755 --- a/configure +++ b/configure @@ -1211,65 +1211,42 @@ fi echo "#define HAVE_REALLOCARRAY" >>$CONFIG_H if [ -z "$POLL" ]; then - printf "Testing for kqueue1 ... " - cat <_kqueue.c -#include -#include + printf "Testing for ppoll ... " + cat <_ppoll.c +#include +#include int main(void) { - return kqueue1(0); + struct pollfd fds; + return ppoll(&fds, 1, NULL, NULL); } EOF - if $XCC _kqueue.c -o _kqueue 2>&3; then - POLL=kqueue1 - echo "yes" - else - echo "no" - fi - rm -f _kqueue.c _kqueue + 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 _ppoll.c _ppoll fi if [ -z "$POLL" ]; then - printf "Testing for kqueue ... " - cat <_kqueue.c -#include -#include + printf "Testing for pollts ... " + cat <_pollts.c +#include +#include int main(void) { - return kqueue(); + struct pollfd fds; + return pollts(&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 <_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) { - 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 _pollts.c -o _pollts 2>&3; then + POLL=pollts + echo "#define HAVE_PPOLL" >>$CONFIG_MK echo "yes" else echo "no" fi - rm -f _epoll.c _epoll + rm -f _pollts.c _pollts fi if [ -z "$POLL" ]; then printf "Testing for pselect ... " @@ -1290,22 +1267,12 @@ EOF 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 ;; diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 015b439e..0c759ca3 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -2039,13 +2039,9 @@ printpidfile: 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 @@ printpidfile: logerr("fork"); goto exit_failure; case 0: - eloop_requeue(ctx.eloop); break; default: ctx.options |= DHCPCD_FORKED; /* A lie */ diff --git a/src/eloop.c b/src/eloop.c index 2a67982e..39c43d9d 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -26,60 +26,30 @@ * SUCH DAMAGE. */ -#if (defined(__unix__) || defined(unix)) && !defined(USG) -#include -#endif #include #include #include #include +#include #include #include #include #include #include -/* 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 -#include -#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 -#elif defined(HAVE_POLL) -#if defined(HAVE_PSELECT) +#ifdef HAVE_PSELECT #include #endif -#include -#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 @@ struct eloop_event { void *read_cb_arg; void (*write_cb)(void *); void *write_cb_arg; + struct pollfd *pollfd; }; struct eloop_timeout { @@ -183,11 +121,9 @@ struct eloop_timeout { }; 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 @@ struct eloop { 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 @@ eloop_realloca(void *ptr, size_t n, size_t size) } #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 @@ eloop_pollts(struct pollfd * fds, nfds_t nfds, 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_reduce_timers(struct eloop *eloop) 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 @@ eloop_event_add_rw(struct eloop *eloop, int fd, 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++; + } - /* 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; + 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++; } -#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 @@ int 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 @@ eloop_event_delete_write(struct eloop *eloop, int fd, int write_only) 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--; - -#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 + eloop->nevents--; +done: eloop_event_setup_fds(eloop); return 1; } @@ -681,7 +494,6 @@ eloop_q_timeout_add_msec(struct eloop *eloop, int queue, unsigned long when, (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_timeout_add_now(struct eloop *eloop, eloop->timeout0_arg = arg; return 0; } -#endif int eloop_q_timeout_delete(struct eloop *eloop, int queue, @@ -734,106 +545,7 @@ eloop_enter(struct eloop *eloop) 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_signal_set_cb(struct eloop *eloop, 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_signal3(int sig, __unused siginfo_t *siginfo, __unused void *arg) 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 @@ eloop_signal_mask(struct eloop *eloop, sigset_t *oldset) 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 @@ eloop_new(void) } 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 @@ eloop_clear(struct eloop *eloop) 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 @@ eloop_clear(struct eloop *eloop) 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 @@ eloop_start(struct eloop *eloop, sigset_t *signals) 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 @@ eloop_start(struct eloop *eloop, sigset_t *signals) } 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 @@ eloop_start(struct eloop *eloop, sigset_t *signals) } 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 @@ eloop_start(struct eloop *eloop, sigset_t *signals) 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 @@ eloop_start(struct eloop *eloop, sigset_t *signals) 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; diff --git a/src/eloop.h b/src/eloop.h index 40a1b2ff..9001c1b7 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -83,12 +83,11 @@ int eloop_q_timeout_add_msec(struct eloop *, int, 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); diff --git a/src/privsep-root.c b/src/privsep-root.c index ae52c6ed..93cb8a29 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -788,10 +788,9 @@ ps_root_start(struct dhcpcd_ctx *ctx) 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; } diff --git a/src/privsep.c b/src/privsep.c index d4fdac1e..5d7e2ca5 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -243,12 +243,8 @@ ps_dostart(struct dhcpcd_ctx *ctx, 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) {