From: Roy Marples Date: Wed, 4 Mar 2015 15:47:04 +0000 (+0000) Subject: Support kqueue(2). X-Git-Tag: v6.8.0~61 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8c3d363e8bb4954f246af159cb592b4f362a39a8;p=thirdparty%2Fdhcpcd.git Support kqueue(2). --- diff --git a/configure b/configure index 697e368c..7b0ff835 100755 --- a/configure +++ b/configure @@ -789,6 +789,22 @@ else echo "#define HAVE_SPAWN_H" >>$CONFIG_H fi +if [ -z "$POLL" ]; then + printf "Testing for kqueue ... " + cat <_kqueue.c +#include +int main(void) { + return kqueue(); +} +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 @@ -853,6 +869,9 @@ EOF rm -f _pselect.c _pselect fi case "$POLL" in +kqueue) + echo "#define HAVE_KQUEUE" >>$CONFIG_H + ;; epoll) echo "#define HAVE_EPOLL" >>$CONFIG_H ;; diff --git a/dhcpcd.c b/dhcpcd.c index 209d498f..3f261fa7 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -68,12 +68,12 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2015 Roy Marples"; #ifdef USE_SIGNALS const int dhcpcd_handlesigs[] = { + SIGTERM, + SIGINT, SIGALRM, SIGHUP, - SIGINT, - SIGPIPE, - SIGTERM, SIGUSR1, + SIGPIPE, 0 }; @@ -1060,14 +1060,10 @@ stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release) } #ifdef USE_SIGNALS -struct dhcpcd_siginfo { - int signo; - pid_t pid; -} dhcpcd_siginfo; - -#define sigmsg "received signal %s from PID %d, %s" -static void -handle_signal1(void *arg) +struct dhcpcd_siginfo dhcpcd_siginfo; +#define sigmsg "received signal %s, %s" +void +dhcpcd_handle_signal(void *arg) { struct dhcpcd_ctx *ctx; struct dhcpcd_siginfo *si; @@ -1080,19 +1076,19 @@ handle_signal1(void *arg) exit_code = EXIT_FAILURE; switch (si->signo) { case SIGINT: - syslog(LOG_INFO, sigmsg, "INT", (int)si->pid, "stopping"); + syslog(LOG_INFO, sigmsg, "INT", "stopping"); break; case SIGTERM: - syslog(LOG_INFO, sigmsg, "TERM", (int)si->pid, "stopping"); + syslog(LOG_INFO, sigmsg, "TERM", "stopping"); exit_code = EXIT_SUCCESS; break; case SIGALRM: - syslog(LOG_INFO, sigmsg, "ALRM", (int)si->pid, "releasing"); + syslog(LOG_INFO, sigmsg, "ALRM", "releasing"); do_release = 1; exit_code = EXIT_SUCCESS; break; case SIGHUP: - syslog(LOG_INFO, sigmsg, "HUP", (int)si->pid, "rebinding"); + syslog(LOG_INFO, sigmsg, "HUP", "rebinding"); reload_config(ctx); /* Preserve any options passed on the commandline * when we were started. */ @@ -1100,7 +1096,7 @@ handle_signal1(void *arg) ctx->argc - ctx->ifc); return; case SIGUSR1: - syslog(LOG_INFO, sigmsg, "USR1", (int)si->pid, "reconfiguring"); + syslog(LOG_INFO, sigmsg, "USR1", "reconfiguring"); TAILQ_FOREACH(ifp, ctx->ifaces, next) { ipv4_applyaddr(ifp); } @@ -1110,9 +1106,9 @@ handle_signal1(void *arg) return; default: syslog(LOG_ERR, - "received signal %d from PID %d, " + "received signal %d, " "but don't know what to do with it", - si->signo, (int)si->pid); + si->signo); return; } @@ -1121,39 +1117,44 @@ handle_signal1(void *arg) eloop_exit(ctx->eloop, exit_code); } +#ifndef HAVE_KQUEUE static void -handle_signal(int sig, siginfo_t *siginfo, __unused void *context) +handle_signal(int sig, __unused siginfo_t *siginfo, __unused void *context) { /* So that we can operate safely under a signal we instruct * eloop to pass a copy of the siginfo structure to handle_signal1 * as the very first thing to do. */ dhcpcd_siginfo.signo = sig; - dhcpcd_siginfo.pid = siginfo ? siginfo->si_pid : 0; eloop_timeout_add_now(dhcpcd_ctx->eloop, - handle_signal1, &dhcpcd_siginfo); + dhcpcd_handle_signal, &dhcpcd_siginfo); } +#endif static int signal_init(sigset_t *oldset) { - unsigned int i; - struct sigaction sa; sigset_t newset; +#ifndef HAVE_KQUEUE + int i; + struct sigaction sa; +#endif sigfillset(&newset); if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1) return -1; +#ifndef HAVE_KQUEUE memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = handle_signal; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); - for (i = 0; dhcpcd_handlesigs[i]; i++) { + for (i = 0; i < dhcpcd_handlesigs[i]; i++) { if (sigaction(dhcpcd_handlesigs[i], &sa, NULL) == -1) return -1; } +#endif return 0; } #endif diff --git a/dhcpcd.h b/dhcpcd.h index 30617ecd..d289d601 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -150,7 +150,12 @@ struct dhcpcd_ctx { }; #ifdef USE_SIGNALS +struct dhcpcd_siginfo { + int signo; +}; + extern const int dhcpcd_handlesigs[]; +void dhcpcd_handle_signal(void *); #endif int dhcpcd_oneup(struct dhcpcd_ctx *); diff --git a/eloop.c b/eloop.c index a209f089..36a9d38c 100644 --- a/eloop.c +++ b/eloop.c @@ -42,7 +42,16 @@ #include "dhcpcd.h" #include "eloop.h" -#if defined(HAVE_EPOLL) +#if defined(HAVE_KQUEUE) +#include +#ifdef __NetBSD__ +/* udata is void * except on NetBSD */ +#define UPTR(x) ((intptr_t)(x)) +#else +#define UPTR(x) (x) +#endif +#define eloop_event_setup_fds(ctx) +#elif defined(HAVE_EPOLL) #include #define eloop_event_setup_fds(ctx) #else @@ -74,7 +83,9 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, void (*write_cb)(void *), void *write_cb_arg) { struct eloop_event *e; -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + struct kevent ke[2], *nfds; +#elif HAVE_EPOLL struct epoll_event epe, *nfds; #else struct pollfd *nfds; @@ -99,7 +110,16 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, e->write_cb = write_cb; e->write_cb_arg = write_cb_arg; } -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + EV_SET(&ke[0], fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e)); + if (write_cb) + EV_SET(&ke[1], fd, EVFILT_WRITE, EV_ADD, + 0, 0, UPTR(e)); + if (kevent(ctx->kqueue_fd, ke, write_cb ? 2 : 1, + NULL, 0, NULL) == -1) + goto err; + return 0; +#elif HAVE_EPOLL epe.data.ptr = e; return epoll_ctl(ctx->epoll_fd, EPOLL_CTL_MOD, fd, &epe); @@ -129,7 +149,6 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, ctx->fds = nfds; } - /* Now populate the structure and add it to the list */ e->fd = fd; e->read_cb = read_cb; @@ -137,7 +156,13 @@ eloop_event_add(struct eloop_ctx *ctx, int fd, e->write_cb = write_cb; e->write_cb_arg = write_cb_arg; -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + EV_SET(&ke[0], fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e)); + if (write_cb) + EV_SET(&ke[1], fd, EVFILT_WRITE, EV_ADD, 0, 0, UPTR(e)); + if (kevent(ctx->kqueue_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1) + goto err; +#elif HAVE_EPOLL epe.data.ptr = e; if (epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, fd, &epe) == -1) goto err; @@ -166,15 +191,34 @@ void eloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only) { struct eloop_event *e; +#ifdef HAVE_KQUEUE + struct kevent ke; +#endif TAILQ_FOREACH(e, &ctx->events, next) { if (e->fd == fd) { if (write_only) { - e->write_cb = NULL; - e->write_cb_arg = NULL; + if (e->write_cb) { + e->write_cb = NULL; + e->write_cb_arg = NULL; +#ifdef HAVE_KQUEUE + EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, + 0, 0, UPTR(NULL)); + kevent(ctx->kqueue_fd, &ke, 1, NULL, 0, + NULL); +#endif + } + } else { TAILQ_REMOVE(&ctx->events, e, next); -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, + 0, 0, UPTR(NULL)); + kevent(ctx->kqueue_fd, &ke, 1, NULL, 0, NULL); + EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, + 0, 0, UPTR(NULL)); + kevent(ctx->kqueue_fd, &ke, 1, NULL, 0, NULL); +#elif HAVE_EPOLL /* NULL event is safe because we * rely on epoll_pwait which as added * after the delete without event was fixed. */ @@ -299,6 +343,9 @@ eloop_init(void) { struct eloop_ctx *ctx; struct timespec now; +#ifdef HAVE_KQUEUE + int i; +#endif /* Check we have a working monotonic clock. */ if (get_monotonic(&now) == -1) @@ -311,7 +358,32 @@ eloop_init(void) TAILQ_INIT(&ctx->timeouts); TAILQ_INIT(&ctx->free_timeouts); ctx->exitcode = EXIT_FAILURE; -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + if ((ctx->kqueue_fd = kqueue()) == -1) { + free(ctx); + return NULL; + } + /* There is no sigmask parameter to kqueue, instead + * we have to use it's filters. */ + ctx->fds_len = 0; + while ((int)ctx->fds_len < dhcpcd_handlesigs[ctx->fds_len]) + ctx->fds_len++; + ctx->fds = malloc(ctx->fds_len * sizeof(*ctx->fds)); + if (ctx->fds == NULL) { + free(ctx); + return NULL; + } + for (i = 0; i < dhcpcd_handlesigs[i]; i++) + EV_SET(&ctx->fds[i], dhcpcd_handlesigs[i], + EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL)); + if (kevent(ctx->kqueue_fd, ctx->fds, ctx->fds_len, + NULL, 0, NULL) == -1) + { + free(ctx->fds); + free(ctx); + return NULL; + } +#elif HAVE_EPOLL if ((ctx->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) == -1) { free(ctx); return NULL; @@ -332,6 +404,12 @@ void eloop_free(struct eloop_ctx *ctx) if (ctx == NULL) return; +#ifdef HAVE_KQUEUE + close(ctx->kqueue_fd); +#elif HAVE_EPOLL + close(ctx->epoll_fd); +#endif + while ((e = TAILQ_FIRST(&ctx->events))) { TAILQ_REMOVE(&ctx->events, e, next); free(e); @@ -364,7 +442,7 @@ eloop_start(struct dhcpcd_ctx *dctx) #if defined(HAVE_EPOLL) || !defined(USE_SIGNALS) int timeout; #endif -#ifdef HAVE_EPOLL +#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) int i; #endif @@ -411,7 +489,10 @@ eloop_start(struct dhcpcd_ctx *dctx) (tsp->tv_nsec + 999999) / 1000000); #endif -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + n = kevent(ctx->kqueue_fd, NULL, 0, ctx->fds, ctx->events_len, + tsp); +#elif HAVE_EPOLL #ifdef USE_SIGNALS n = epoll_pwait(ctx->epoll_fd, ctx->fds, (int)ctx->events_len, timeout, &dctx->sigset); @@ -434,27 +515,43 @@ eloop_start(struct dhcpcd_ctx *dctx) break; } - /* Process any triggered events. */ -#ifdef HAVE_EPOLL + /* Process any triggered events. + * We break after calling each callback incase + * the current event or next event is removed. */ +#ifdef HAVE_KQUEUE + for (i = 0; i < n; i++) { + if (ctx->fds[i].filter == EVFILT_SIGNAL) { + struct dhcpcd_siginfo si; + + si.signo = (int)ctx->fds[i].ident; + dhcpcd_handle_signal(&si); + break; + } + e = (struct eloop_event *)ctx->fds[i].udata; + if (ctx->fds[i].filter == EVFILT_WRITE && + e->write_cb) + { + e->write_cb(e->write_cb_arg); + break; + } + if (ctx->fds[i].filter == EVFILT_READ) { + e->read_cb(e->read_cb_arg); + break; + } + } +#elif 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 & + if (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; } } @@ -465,16 +562,10 @@ eloop_start(struct dhcpcd_ctx *dctx) 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 (e->pollfd->revents) { e->read_cb(e->read_cb_arg); - /* We need to break here as the - * callback could destroy the next - * fd to process. */ break; } } diff --git a/eloop.h b/eloop.h index e906dc84..955194c5 100644 --- a/eloop.h +++ b/eloop.h @@ -47,7 +47,7 @@ struct eloop_event { void *read_cb_arg; void (*write_cb)(void *); void *write_cb_arg; -#if !defined(HAVE_EPOLL) +#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL) struct pollfd *pollfd; #endif }; @@ -71,7 +71,10 @@ struct eloop_ctx { void (*timeout0)(void *); void *timeout0_arg; -#ifdef HAVE_EPOLL +#ifdef HAVE_KQUEUE + int kqueue_fd; + struct kevent *fds; +#elif HAVE_EPOLL int epoll_fd; struct epoll_event *fds; #else