[PATCH 02/12] event-loop: Add support for BSD???s kevent() instead of epoll()

Philip Withnall philip at tecnocode.co.uk
Fri Feb 15 04:56:25 PST 2013


This is a large step towards supporting the BSDs. There’s quite a lot of
little in the test suite).

Signed-off-by: Philip Withnall <philip at tecnocode.co.uk>
---
 configure.ac             |   8 ++
 src/event-loop.c         | 361 +++++++++++++++++++++++++++++++++++++++++++++--
 src/wayland-os.c         |  23 ++-
 src/wayland-os.h         |   7 +
 tests/os-wrappers-test.c |  34 +++++
 5 files changed, 419 insertions(+), 14 deletions(-)

diff --git a/configure.ac b/configure.ac
index 883411c..935afbd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,6 +41,14 @@ AC_SUBST(GCC_CFLAGS)
 
 AC_CHECK_FUNCS([accept4 mkostemp])
 
+# Use epoll on Linux or kqueue on BSD
+AC_CHECK_HEADERS([sys/epoll.h sys/event.h])
+if test "x$ac_cv_header_sys_epoll_h" != "xyes" && test "x$ac_cv_header_sys_event_h" != "xyes"; then
+	AC_MSG_ERROR([Can't find sys/epoll.h or sys/event.h. Please ensure either epoll or kqueue is available.])
+fi
+
+AC_CHECK_HEADERS([sys/signalfd.h sys/timerfd.h])
+
 AC_ARG_ENABLE([scanner],
               [AC_HELP_STRING([--disable-scanner],
                               [Disable compilation of wayland-scanner])],
diff --git a/src/event-loop.c b/src/event-loop.c
index e556cc7..05baa48 100644
--- a/src/event-loop.c
+++ b/src/event-loop.c
@@ -20,6 +20,8 @@
  * OF THIS SOFTWARE.
  */
 
+#include "../config.h"
+
 #include <stddef.h>
 #include <stdio.h>
 #include <errno.h>
@@ -29,9 +31,23 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+
+#ifdef HAVE_SYS_EPOLL_H
 #include <sys/epoll.h>
+#ifdef HAVE_SYS_SIGNALFD_H
 #include <sys/signalfd.h>
+#endif /* signalfd */
+#ifdef HAVE_SYS_TIMERFD_H
 #include <sys/timerfd.h>
+#endif /* timerfd */
+#elif HAVE_SYS_EVENT_H
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#else /* !epoll && !kqueue */
+#error "Unsupported event system. Only epoll and kqueue are supported."
+#endif
+
 #include <unistd.h>
 #include <assert.h>
 #include "wayland-server.h"
@@ -39,7 +55,7 @@
 #include "wayland-os.h"
 
 struct wl_event_loop {
-	int epoll_fd;
+	int event_fd;
 	struct wl_list check_list;
 	struct wl_list idle_list;
 	struct wl_list destroy_list;
@@ -48,8 +64,13 @@ struct wl_event_loop {
 };
 
 struct wl_event_source_interface {
+#ifdef HAVE_SYS_EPOLL_H
 	int (*dispatch)(struct wl_event_source *source,
 			struct epoll_event *ep);
+#elif HAVE_SYS_EVENT_H
+	int (*dispatch)(struct wl_event_source *source,
+	                struct kevent *ep);
+#endif
 };
 
 struct wl_event_source {
@@ -66,11 +87,13 @@ struct wl_event_source_fd {
 	int fd;
 };
 
+#ifdef HAVE_SYS_EPOLL_H
 static int
 wl_event_source_fd_dispatch(struct wl_event_source *source,
 			    struct epoll_event *ep)
 {
-	struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
+	struct wl_event_source_fd *fd_source =
+		(struct wl_event_source_fd *) source;
 	uint32_t mask;
 
 	mask = 0;
@@ -85,11 +108,32 @@ wl_event_source_fd_dispatch(struct wl_event_source *source,
 
 	return fd_source->func(fd_source->fd, mask, source->data);
 }
+#elif HAVE_SYS_EVENT_H
+static int
+wl_event_source_fd_dispatch(struct wl_event_source *source,
+                            struct kevent *ev)
+{
+	struct wl_event_source_fd *fd_source =
+		(struct wl_event_source_fd *) source;
+	uint32_t mask;
+
+	mask = 0;
+	if (ev->filter == EVFILT_READ)
+		mask |= WL_EVENT_READABLE;
+	if (ev->filter == EVFILT_WRITE)
+		mask |= WL_EVENT_WRITABLE;
+	if (ev->flags & EV_ERROR)
+		mask |= WL_EVENT_ERROR;
+
+	return fd_source->func(fd_source->fd, mask, source->data);
+}
+#endif
 
 struct wl_event_source_interface fd_source_interface = {
 	wl_event_source_fd_dispatch,
 };
 
+#ifdef HAVE_SYS_EPOLL_H
 static struct wl_event_source *
 add_source(struct wl_event_loop *loop,
 	   struct wl_event_source *source, uint32_t mask, void *data)
@@ -113,7 +157,47 @@ add_source(struct wl_event_loop *loop,
 		ep.events |= EPOLLOUT;
 	ep.data.ptr = source;
 
-	if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+	if (epoll_ctl(loop->event_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+		close(source->fd);
+		free(source);
+		return NULL;
+	}
+
+	return source;
+}
+#elif HAVE_SYS_EVENT_H
+static struct wl_event_source *
+add_source(struct wl_event_loop *loop,
+           struct wl_event_source *source, uint32_t mask, void *data)
+{
+	struct kevent events[2];
+	unsigned int num_events = 0;
+
+	if (source->fd < 0) {
+		fprintf(stderr, "could not add source\n: %m");
+		free(source);
+		return NULL;
+	}
+
+	source->loop = loop;
+	source->data = data;
+	wl_list_init(&source->link);
+
+	if (mask & WL_EVENT_READABLE) {
+		EV_SET(&events[num_events], source->fd, EVFILT_READ,
+		       EV_ADD | EV_ENABLE, 0, 0, source);
+		num_events++;
+	}
+
+	if (mask & WL_EVENT_WRITABLE) {
+		EV_SET(&events[num_events], source->fd, EVFILT_WRITE,
+		       EV_ADD | EV_ENABLE, 0, 0, source);
+		num_events++;
+	}
+
+	if (kevent(loop->event_fd, events, num_events, NULL, 0, NULL) < 0) {
+		fprintf(stderr, "error adding source %i (%p) to loop %p: %s\n",
+		        source->fd, source, loop, strerror(errno));
 		close(source->fd);
 		free(source);
 		return NULL;
@@ -121,6 +205,7 @@ add_source(struct wl_event_loop *loop,
 
 	return source;
 }
+#endif
 
 WL_EXPORT struct wl_event_source *
 wl_event_loop_add_fd(struct wl_event_loop *loop,
@@ -142,6 +227,7 @@ wl_event_loop_add_fd(struct wl_event_loop *loop,
 	return add_source(loop, &source->base, mask, data);
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 WL_EXPORT int
 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
 {
@@ -155,27 +241,63 @@ wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
 		ep.events |= EPOLLOUT;
 	ep.data.ptr = source;
 
-	return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
+	return epoll_ctl(loop->event_fd, EPOLL_CTL_MOD, source->fd, &ep);
+}
+#elif HAVE_SYS_EVENT_H
+WL_EXPORT int
+wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
+{
+	struct wl_event_loop *loop = source->loop;
+	struct kevent events[2];
+	unsigned int num_events = 0;
+
+	if (mask & WL_EVENT_READABLE) {
+		EV_SET(&events[num_events], source->fd, EVFILT_READ,
+		       EV_ADD | EV_ENABLE, 0, 0, source);
+		num_events++;
+	}
+
+	if (mask & WL_EVENT_WRITABLE) {
+		EV_SET(&events[num_events], source->fd, EVFILT_WRITE,
+		       EV_ADD | EV_ENABLE, 0, 0, source);
+		num_events++;
+	}
+
+	return kevent(loop->event_fd, events, num_events, NULL, 0, NULL);
 }
+#endif
 
 struct wl_event_source_timer {
 	struct wl_event_source base;
 	wl_event_loop_timer_func_t func;
 };
 
+#ifdef HAVE_SYS_EPOLL_H
 static int
 wl_event_source_timer_dispatch(struct wl_event_source *source,
 			       struct epoll_event *ep)
+#elif HAVE_SYS_EVENT_H
+static int
+wl_event_source_timer_dispatch(struct wl_event_source *source,
+                               struct kevent *ev)
+#endif
 {
 	struct wl_event_source_timer *timer_source =
 		(struct wl_event_source_timer *) source;
 	uint64_t expires;
+
+#ifdef HAVE_SYS_TIMERFD_H
 	int len;
 
+	/* Linux. Read the number of missed expirations from the FD. */
 	len = read(source->fd, &expires, sizeof expires);
 	if (len != sizeof expires)
 		/* Is there anything we can do here?  Will this ever happen? */
 		fprintf(stderr, "timerfd read error: %m\n");
+#else
+	/* FreeBSD. Grab the number of missed expires from the kevent. */
+	expires = ev->data;
+#endif
 
 	return timer_source->func(timer_source->base.data);
 }
@@ -196,15 +318,28 @@ wl_event_loop_add_timer(struct wl_event_loop *loop,
 		return NULL;
 
 	source->base.interface = &timer_source_interface;
-	source->base.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
 	source->func = func;
+#ifdef HAVE_SYS_TIMERFD_H
+	source->base.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
 
 	return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+#else
+	/* FreeBSD. We use kqueue() timers directly.
+	 * See: wl_event_source_timer_update(). */
+	source->base.fd = 0;
+	source->base.loop = loop;
+	source->base.data = data;
+	wl_list_init(&source->base.link);
+
+	return &source->base;
+#endif
 }
 
 WL_EXPORT int
 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
 {
+#ifdef HAVE_SYS_TIMERFD_H
+	/* Linux. */
 	struct itimerspec its;
 
 	its.it_interval.tv_sec = 0;
@@ -217,6 +352,20 @@ wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
 	}
 
 	return 0;
+#else
+	/* FreeBSD. */
+	struct kevent ev;
+
+	EV_SET(&ev, 0, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, 0,
+	       ms_delay, source);
+
+	if (kevent(source->loop->event_fd, &ev, 1, NULL, 0, NULL) < 0) {
+		fprintf(stderr, "could not set kqueue timer\n: %m");
+		return -1;
+	}
+
+	return 0;
+#endif
 }
 
 struct wl_event_source_signal {
@@ -225,12 +374,20 @@ struct wl_event_source_signal {
 	wl_event_loop_signal_func_t func;
 };
 
+#ifdef HAVE_SYS_EPOLL_H
 static int
 wl_event_source_signal_dispatch(struct wl_event_source *source,
 			       struct epoll_event *ep)
+#elif HAVE_SYS_EVENT_H
+static int
+wl_event_source_signal_dispatch(struct wl_event_source *source,
+                                struct kevent *ev)
+#endif
 {
 	struct wl_event_source_signal *signal_source =
 		(struct wl_event_source_signal *) source;
+
+#ifdef HAVE_SYS_SIGNALFD_H
 	struct signalfd_siginfo signal_info;
 	int len;
 
@@ -238,6 +395,7 @@ wl_event_source_signal_dispatch(struct wl_event_source *source,
 	if (len != sizeof signal_info)
 		/* Is there anything we can do here?  Will this ever happen? */
 		fprintf(stderr, "signalfd read error: %m\n");
+#endif
 
 	return signal_source->func(signal_source->signal_number,
 				   signal_source->base.data);
@@ -255,6 +413,9 @@ wl_event_loop_add_signal(struct wl_event_loop *loop,
 {
 	struct wl_event_source_signal *source;
 	sigset_t mask;
+#ifndef HAVE_SYS_SIGNALFD_H
+	struct kevent ev;
+#endif
 
 	source = malloc(sizeof *source);
 	if (source == NULL)
@@ -262,15 +423,37 @@ wl_event_loop_add_signal(struct wl_event_loop *loop,
 
 	source->base.interface = &signal_source_interface;
 	source->signal_number = signal_number;
+	source->func = func;
 
+	/* Block delivery of signal_number to this process. */
 	sigemptyset(&mask);
 	sigaddset(&mask, signal_number);
-	source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC);
 	sigprocmask(SIG_BLOCK, &mask, NULL);
 
-	source->func = func;
+#ifdef HAVE_SYS_SIGNALFD_H
+	/* Linux. Use signalfd. */
+	source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC);
 
 	return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+#else
+	/* FreeBSD. Use kqueue() signals directly. */
+	source->base.fd = 0;
+	source->base.loop = loop;
+	source->base.data = data;
+	wl_list_init(&source->base.link);
+
+	EV_SET(&ev, signal_number, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
+	       source);
+
+	if (kevent(loop->event_fd, &ev, 1, NULL, 0, NULL) < 0) {
+		fprintf(stderr, "error adding signal for %i (%p), %p: %s\n",
+		        signal_number, source, loop, strerror(errno));
+		free(source);
+		return NULL;
+	}
+
+	return &source->base;
+#endif
 }
 
 struct wl_event_source_idle {
@@ -311,6 +494,7 @@ wl_event_source_check(struct wl_event_source *source)
 	wl_list_insert(source->loop->check_list.prev, &source->link);
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 WL_EXPORT int
 wl_event_source_remove(struct wl_event_source *source)
 {
@@ -319,7 +503,7 @@ wl_event_source_remove(struct wl_event_source *source)
 	/* We need to explicitly remove the fd, since closing the fd
 	 * isn't enough in case we've dup'ed the fd. */
 	if (source->fd >= 0) {
-		epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
+		epoll_ctl(loop->event_fd, EPOLL_CTL_DEL, source->fd, NULL);
 		close(source->fd);
 		source->fd = -1;
 	}
@@ -329,6 +513,82 @@ wl_event_source_remove(struct wl_event_source *source)
 
 	return 0;
 }
+#elif HAVE_SYS_EVENT_H
+WL_EXPORT int
+wl_event_source_remove(struct wl_event_source *source)
+{
+	struct wl_event_loop *loop = source->loop;
+	int ret = 0, saved_errno = 0;
+
+	/* Since FreeBSD doesn't treat all event sources as FDs, we need to
+	 * differentiate by source interface. */
+	if (source->interface == &fd_source_interface && source->fd >= 0) {
+		struct kevent ev[2];
+		int _ret[2], _saved_errno[2];
+
+		/* We haven't stored state about the mask used when adding the
+		 * source, so we have to try and remove both READ and WRITE
+		 * filters. One may fail, which is OK. Removal of the source has
+		 * only failed if _both_ kevent() calls fail. We have to do two
+		 * kevent() calls so that we can get independent return values
+		 * for the two kevents. */
+		EV_SET(&ev[0], source->fd, EVFILT_READ, EV_DELETE, 0, 0,
+		       source);
+		EV_SET(&ev[1], source->fd, EVFILT_WRITE, EV_DELETE, 0, 0,
+		       source);
+
+		_ret[0] = kevent(loop->event_fd, &ev[0], 1, NULL, 0, NULL);
+		_saved_errno[0] = errno;
+		_ret[1] = kevent(loop->event_fd, &ev[1], 1, NULL, 0, NULL);
+		_saved_errno[1] = errno;
+
+		if (_ret[0] >= _ret[1]) {
+			ret = _ret[0];
+			saved_errno = _saved_errno[0];
+		} else {
+			ret = _ret[1];
+			saved_errno = _saved_errno[1];
+		}
+
+		close(source->fd);
+	} else if (source->interface == &timer_source_interface) {
+		struct kevent ev;
+
+		/* Only one kevent() call needed. */
+		EV_SET(&ev, 0, EVFILT_TIMER, EV_DELETE, 0, 0, source);
+		ret = kevent(loop->event_fd, &ev, 1, NULL, 0, NULL);
+		saved_errno = errno;
+	} else if (source->interface == &signal_source_interface) {
+		struct kevent ev;
+		int signal_number;
+		struct wl_event_source_signal *_source;
+
+		/* Only one kevent() call needed. */
+		_source = (struct wl_event_source_signal *) source;
+		signal_number = _source->signal_number;
+
+		EV_SET(&ev, signal_number, EVFILT_SIGNAL, EV_DELETE, 0, 0,
+		       source);
+		ret = kevent(loop->event_fd, &ev, 1, NULL, 0, NULL);
+		saved_errno = errno;
+	}
+
+	/* Handle any errors from kevent() calls. */
+	if (ret < 0) {
+		fprintf (stderr,
+		         "error removing event (%i) from kqueue: %s\n",
+		         source->fd, strerror(saved_errno));
+	}
+
+	/* Tidy up the source. */
+	source->fd = -1;
+
+	wl_list_remove(&source->link);
+	wl_list_insert(&loop->destroy_list, &source->link);
+
+	return 0;
+}
+#endif
 
 static void
 wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
@@ -350,11 +610,20 @@ wl_event_loop_create(void)
 	if (loop == NULL)
 		return NULL;
 
-	loop->epoll_fd = wl_os_epoll_create_cloexec();
-	if (loop->epoll_fd < 0) {
+#ifdef HAVE_SYS_EPOLL_H
+	loop->event_fd = wl_os_epoll_create_cloexec();
+	if (loop->event_fd < 0) {
+		free(loop);
+		return NULL;
+	}
+#elif HAVE_SYS_EVENT_H
+	loop->event_fd = wl_os_kqueue_create_cloexec();
+	if (loop->event_fd < 0) {
 		free(loop);
 		return NULL;
 	}
+#endif
+
 	wl_list_init(&loop->check_list);
 	wl_list_init(&loop->idle_list);
 	wl_list_init(&loop->destroy_list);
@@ -370,10 +639,15 @@ wl_event_loop_destroy(struct wl_event_loop *loop)
 	wl_signal_emit(&loop->destroy_signal, loop);
 
 	wl_event_loop_process_destroy_list(loop);
-	close(loop->epoll_fd);
+#ifdef HAVE_SYS_EPOLL_H
+	close(loop->event_fd);
+#elif HAVE_SYS_EVENT_H
+	close(loop->event_fd);
+#endif
 	free(loop);
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 static int
 post_dispatch_check(struct wl_event_loop *loop)
 {
@@ -388,6 +662,22 @@ post_dispatch_check(struct wl_event_loop *loop)
 
 	return n;
 }
+#elif HAVE_SYS_EVENT_H
+static int
+post_dispatch_check(struct wl_event_loop *loop)
+{
+	struct kevent ev;
+	struct wl_event_source *source, *next;
+	int n;
+
+	ev.filter = 0;
+	n = 0;
+	wl_list_for_each_safe(source, next, &loop->check_list, link)
+		n += source->interface->dispatch(source, &ev);
+
+	return n;
+}
+#endif
 
 WL_EXPORT void
 wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
@@ -402,6 +692,7 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
 	}
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 WL_EXPORT int
 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
 {
@@ -411,7 +702,7 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
 
 	wl_event_loop_dispatch_idle(loop);
 
-	count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
+	count = epoll_wait(loop->event_fd, ep, ARRAY_LENGTH(ep), timeout);
 	if (count < 0)
 		return -1;
 
@@ -429,12 +720,56 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
 		
 	return 0;
 }
+#elif HAVE_SYS_EVENT_H
+WL_EXPORT int
+wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
+{
+	struct kevent ev[32];
+	struct wl_event_source *source;
+	int i, count, n;
+	struct timespec timeout_spec;
 
+	wl_event_loop_dispatch_idle(loop);
+
+	/* timeout is provided in milliseconds; convert it to a timespec. */
+	timeout_spec.tv_sec = timeout / 1000;
+	timeout_spec.tv_nsec = (timeout % 1000) * 1000000;
+
+	count = kevent(loop->event_fd, NULL, 0, ev, ARRAY_LENGTH(ev),
+	               (timeout != -1) ? &timeout_spec : NULL);
+	if (count < 0)
+		return -1;
+
+	for (i = 0; i < count; i++) {
+		source = ev[i].udata;
+		if (source->fd != -1) {
+			source->interface->dispatch(source, &ev[i]);
+		}
+	}
+
+	wl_event_loop_process_destroy_list(loop);
+
+	do {
+		n = post_dispatch_check(loop);
+	} while (n > 0);
+
+	return 0;
+}
+#endif
+
+#ifdef HAVE_SYS_EPOLL_H
+WL_EXPORT int
+wl_event_loop_get_fd(struct wl_event_loop *loop)
+{
+	return loop->event_fd;
+}
+#elif HAVE_SYS_EVENT_H
 WL_EXPORT int
 wl_event_loop_get_fd(struct wl_event_loop *loop)
 {
-	return loop->epoll_fd;
+	return loop->event_fd;
 }
+#endif
 
 WL_EXPORT void
 wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
diff --git a/src/wayland-os.c b/src/wayland-os.c
index 1185e1d..aad6da6 100644
--- a/src/wayland-os.c
+++ b/src/wayland-os.c
@@ -22,14 +22,21 @@
 
 #define _GNU_SOURCE
 
+#include "../config.h"
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#ifdef HAVE_SYS_EPOLL_H
 #include <sys/epoll.h>
+#endif
+#ifdef HAVE_SYS_EVENT_H
+#include <sys/types.h>
+#include <sys/event.h>
+#endif
 
-#include "../config.h"
 #include "wayland-os.h"
 
 static int
@@ -129,6 +136,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
 	return recvmsg_cloexec_fallback(sockfd, msg, flags);
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 int
 wl_os_epoll_create_cloexec(void)
 {
@@ -145,6 +153,19 @@ wl_os_epoll_create_cloexec(void)
 	fd = epoll_create(1);
 	return set_cloexec_or_close(fd);
 }
+#endif
+
+#ifdef HAVE_SYS_EVENT_H
+int
+wl_os_kqueue_create_cloexec(void)
+{
+	int fd;
+
+	fd = kqueue();
+
+	return set_cloexec_or_close(fd);
+}
+#endif
 
 int
 wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
diff --git a/src/wayland-os.h b/src/wayland-os.h
index c612975..b2c3567 100644
--- a/src/wayland-os.h
+++ b/src/wayland-os.h
@@ -32,8 +32,15 @@ wl_os_dupfd_cloexec(int fd, long minfd);
 ssize_t
 wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
 
+#ifdef HAVE_SYS_EPOLL_H
 int
 wl_os_epoll_create_cloexec(void);
+#endif
+
+#ifdef HAVE_SYS_EVENT_H
+int
+wl_os_kqueue_create_cloexec(void);
+#endif
 
 int
 wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c
index 515fd81..ca79c5e 100644
--- a/tests/os-wrappers-test.c
+++ b/tests/os-wrappers-test.c
@@ -23,6 +23,8 @@
 
 #define _GNU_SOURCE
 
+#include "../config.h"
+
 #include <stdlib.h>
 #include <assert.h>
 #include <sys/types.h>
@@ -34,7 +36,12 @@
 #include <stdarg.h>
 #include <fcntl.h>
 #include <stdio.h>
+#if defined(HAVE_SYS_EPOLL_H)
 #include <sys/epoll.h>
+#elif defined(HAVE_SYS_EVENT_H)
+#include <sys/event.h>
+#include <sys/types.h>
+#endif
 
 #include "wayland-private.h"
 #include "test-runner.h"
@@ -51,8 +58,13 @@ static int wrapped_calls_fcntl;
 static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
 static int wrapped_calls_recvmsg;
 
+#ifdef HAVE_SYS_EPOLL_H
 static int (*real_epoll_create1)(int);
 static int wrapped_calls_epoll_create1;
+#else
+static int (*real_kqueue)(void);
+static int wrapped_calls_kqueue;
+#endif
 
 static void
 init_fallbacks(int do_fallbacks)
@@ -61,7 +73,11 @@ init_fallbacks(int do_fallbacks)
 	real_socket = dlsym(RTLD_NEXT, "socket");
 	real_fcntl = dlsym(RTLD_NEXT, "fcntl");
 	real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
+#ifdef HAVE_SYS_EPOLL_H
 	real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1");
+#else
+	real_kqueue = dlsym(RTLD_NEXT, "kqueue");
+#endif
 }
 
 __attribute__ ((visibility("default"))) int
@@ -110,6 +126,7 @@ recvmsg(int sockfd, struct msghdr *msg, int flags)
 	return real_recvmsg(sockfd, msg, flags);
 }
 
+#ifdef HAVE_SYS_EPOLL_H
 __attribute__ ((visibility("default"))) int
 epoll_create1(int flags)
 {
@@ -123,6 +140,15 @@ epoll_create1(int flags)
 
 	return real_epoll_create1(flags);
 }
+#else
+__attribute__ ((visibility("default"))) int
+kqueue(void)
+{
+	wrapped_calls_kqueue++;
+
+	return real_kqueue();
+}
+#endif
 
 static void
 do_os_wrappers_socket_cloexec(int n)
@@ -337,12 +363,20 @@ do_os_wrappers_epoll_create_cloexec(int n)
 
 	nr_fds = count_open_fds();
 
+#ifdef HAVE_SYS_EPOLL_H
 	fd = wl_os_epoll_create_cloexec();
+#else
+	fd = wl_os_kqueue_create_cloexec();
+#endif
 	assert(fd >= 0);
 
 #ifdef EPOLL_CLOEXEC
+#ifdef HAVE_SYS_EPOLL_H
 	assert(wrapped_calls_epoll_create1 == n);
 #else
+	assert(wrapped_calls_kqueue == n);
+#endif
+#else
 	printf("No epoll_create1.\n");
 #endif
 
-- 
1.7.11.7

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 230 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130215/79b25a21/attachment.pgp>


More information about the wayland-devel mailing list