]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Support kqueue(2).
authorRoy Marples <roy@marples.name>
Wed, 4 Mar 2015 15:47:04 +0000 (15:47 +0000)
committerRoy Marples <roy@marples.name>
Wed, 4 Mar 2015 15:47:04 +0000 (15:47 +0000)
configure
dhcpcd.c
dhcpcd.h
eloop.c
eloop.h

index 697e368cd3481aae668b4cd24041347c4de5bac0..7b0ff83556962a155bb94e5ae1a471740542debb 100755 (executable)
--- 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 <<EOF >_kqueue.c
+#include <sys/event.h>
+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 <<EOF >_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
        ;;
index 209d498f391b42d6cfa2d44ab042d695fa9f5b5b..3f261fa7555e208cbf30a4dffe202a395964eaf9 100644 (file)
--- 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
index 30617ecd3893cf855c0385a463fe6008a71810f2..d289d6019e66bae6335d46cf27ebcf7dbc24ecf0 100644 (file)
--- 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 a209f089902a5851a0703771729ccdcae7c9c3b6..36a9d38cc079db3961e3c43f0e23d5abb67245ce 100644 (file)
--- a/eloop.c
+++ b/eloop.c
 #include "dhcpcd.h"
 #include "eloop.h"
 
-#if defined(HAVE_EPOLL)
+#if defined(HAVE_KQUEUE)
+#include <sys/event.h>
+#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 <sys/epoll.h>
 #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 e906dc84cbb20756fba4cda259c35ae55fcb1945..955194c586827d73b8cd5f9f3e38d5faa029c3c2 100644 (file)
--- 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