#ifdef USE_SIGNALS
const int dhcpcd_handlesigs[] = {
+ SIGTERM,
+ SIGINT,
SIGALRM,
SIGHUP,
- SIGINT,
- SIGPIPE,
- SIGTERM,
SIGUSR1,
+ SIGPIPE,
0
};
}
#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;
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. */
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);
}
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;
}
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
#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
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;
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);
ctx->fds = nfds;
}
-
/* Now populate the structure and add it to the list */
e->fd = fd;
e->read_cb = read_cb;
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;
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. */
{
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)
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;
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);
#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
int timeout;
#endif
-#ifdef HAVE_EPOLL
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
int i;
#endif
(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);
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;
}
}
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;
}
}