[PATCH 02/12] event-loop: Add support for BSD???s kevent() instead of epoll()
Jason Ekstrand
jason at jlekstrand.net
Fri Feb 15 07:33:22 PST 2013
I'm a little worried that we're going to make event-loop too much of a
mess of #defines without covering all the cases. My use-case,
Android, is Linux but not GNU/Linux; it uses something called Bionic.
Same kernel, different standard library and a different set of system
calls. Specifically, timerfd and signalfd are missing.
Would it be a better overall solution if we simply replace timerfd and
signalfd with a more generic architecture and then move the guts of
the event loop to poll or select? Another idea that was brought up on
IRC this last weekend was to use an external library such as libevent
where they've already done all of the event abstraction for us.
However, that involves pulling in another dependency which may not be
worth it.
Thoughts?
--Jason Ekstrand
On Fri, Feb 15, 2013 at 6:56 AM, Philip Withnall <philip at tecnocode.co.uk> wrote:
> 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
>
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list