Posting here, but will post elsewhere if this is not the right place.

Is there any desire for using kqueue natively in the wayland libraries
instead of epoll-shim? I'm sure epoll-shim is great, but I wanted to
learn to use kqueue and figured this was a good project (since I was
already working on a wlroots compositor for OpenBSD).

In any case, here's the diff. I've been running with this on my personal
latop for a couple of days now (unless I haven't linked properly), and I
haven't noticed any issues with it (I still have crashes, but those were
there before, and the core dumps don't indicate any issues

Thoughts? Should I try to get the wayland folks to merge this upstream?

diff --git a/meson.build b/meson.build
index 6b05bb5..e7f917c 100644
--- a/meson.build
+++ b/meson.build
@@ -18,6 +18,8 @@ config_h.set_quoted('PACKAGE_VERSION', 
meson.project_version())
 cc_args = []
 if host_machine.system() not in ['freebsd', 'openbsd']
        cc_args += ['-D_POSIX_C_SOURCE=200809L']
+else
+        cc_args += ['-D__USE_KQUEUE']
 endif
 add_project_arguments(cc_args, language: 'c')
 
@@ -72,18 +74,22 @@ if get_option('libraries')
        if host_machine.system() in ['freebsd', 'openbsd']
                # When building for FreeBSD, epoll(7) is provided by a userspace
                # wrapper around kqueue(2).
-               epoll_dep = dependency('epoll-shim')
+                epoll_dep = []
+                decls = [
+               { 'header': 'time.h', 'symbol': 'CLOCK_MONOTONIC' },
+               ]
+
        else
                # Otherwise, assume that epoll(7) is supported natively.
                epoll_dep = []
-       endif
-       ffi_dep = dependency('libffi')
-
-       decls = [
+               decls = [
                { 'header': 'sys/signalfd.h', 'symbol': 'SFD_CLOEXEC' },
                { 'header': 'sys/timerfd.h', 'symbol': 'TFD_CLOEXEC' },
                { 'header': 'time.h', 'symbol': 'CLOCK_MONOTONIC' },
-       ]
+               ]
+
+       endif
+       ffi_dep = dependency('libffi')
 
        foreach d: decls
                if not cc.has_header_symbol(d['header'], d['symbol'], 
dependencies: epoll_dep, args: cc_args)
diff --git a/src/event-loop.c b/src/event-loop.c
index 51c9b9d..86319ac 100644
--- a/src/event-loop.c
+++ b/src/event-loop.c
@@ -34,9 +34,15 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#ifdef __USE_KQUEUE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#else
 #include <sys/epoll.h>
 #include <sys/signalfd.h>
 #include <sys/timerfd.h>
+#endif
 #include <unistd.h>
 #include "wayland-util.h"
 #include "wayland-private.h"
@@ -68,7 +74,11 @@ struct wl_timer_heap {
 };
 
 struct wl_event_loop {
+#ifdef __USE_KQUEUE
+       int kqueue_fd;
+#else
        int epoll_fd;
+#endif
        struct wl_list check_list;
        struct wl_list idle_list;
        struct wl_list destroy_list;
@@ -78,11 +88,82 @@ struct wl_event_loop {
        struct wl_timer_heap timers;
 };
 
+#ifdef __USE_KQUEUE
+
+struct kevent_pair {
+#define KEPM_READ 0x1
+#define KEPM_WRITE 0x2
+       uint32_t        mask;
+       int             fd;
+       struct kevent   kqread;
+       struct kevent   kqwrite;
+};
+
 struct wl_event_source_interface {
        int (*dispatch)(struct wl_event_source *source,
-                       struct epoll_event *ep);
+                       struct kevent_pair *kp);
 };
 
+static int
+kq_modify_helper(struct wl_event_source *source, uint32_t mask) {
+       struct wl_event_loop *loop = source->loop;
+       struct kevent karray[2];
+       int retval, tries = 0;
+
+again:
+       if (mask & WL_EVENT_READABLE)
+               EV_SET(&karray[0], source->fd, EVFILT_READ,
+                      EV_ADD|EV_RECEIPT, 0, 0, source);
+       else
+               EV_SET(&karray[0], source->fd, EVFILT_READ,
+                      EV_DELETE|EV_RECEIPT, 0, 0, source);
+       if (mask & WL_EVENT_WRITABLE)
+               EV_SET(&karray[1], source->fd, EVFILT_WRITE,
+                      EV_ADD|EV_RECEIPT, 0, 0, source);
+       else
+               EV_SET(&karray[1], source->fd, EVFILT_WRITE,
+                      EV_DELETE|EV_RECEIPT, 0, 0, source);
+
+       retval = kevent(loop->kqueue_fd, karray, 2, karray, 2, NULL);
+       /* The following if is probably very rarely going to be hit. */
+       if (retval != 2) {
+               wl_log("wl_event_source_fd_update retval != 2");
+               if (retval == -1 && errno == EINTR)
+                       goto again;
+               if (retval == 1 && tries < 3) {
+                       /* If only one went through, try again. */
+                       tries++;
+                       if (tries >= 3)
+                               return -1;
+                       goto again;
+               }
+               return -1;
+       }
+       retval = 0;
+       if (mask & WL_EVENT_READABLE) {
+               if (karray[0].data != 0) /* Didn't get it. */
+                       retval = -1;
+       } else {
+               if (karray[0].data != 0 && karray[0].data != ENOENT)
+                       retval = -1; /* Didn't remove it. */
+       }
+       if (mask & WL_EVENT_WRITABLE) {
+               if (karray[1].data != 0) /* Didn't get it. */
+                       retval = -1;
+       } else {
+               if (karray[1].data != 0 && karray[1].data != ENOENT)
+                       retval = -1; /* Didn't remove it. */
+       }
+
+       return retval;
+
+}
+#else
+struct wl_event_source_interface {
+       int (*dispatch)(struct wl_event_source *source,
+                       struct epoll_event *ep);
+};
+#endif
 
 struct wl_event_source_fd {
        struct wl_event_source base;
@@ -92,15 +173,37 @@ struct wl_event_source_fd {
 
 /** \endcond */
 
+#ifdef __USE_KQUEUE
+static int
+wl_event_source_fd_dispatch(struct wl_event_source *source,
+                           struct kevent_pair *kp)
+#else
 static int
 wl_event_source_fd_dispatch(struct wl_event_source *source,
                            struct epoll_event *ep)
+#endif
 {
        struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) 
source;
        uint32_t mask;
 
        mask = 0;
-       if (ep->events & EPOLLIN)
+#ifdef __USE_KQUEUE
+        if (kp->mask & KEPM_READ) {
+               mask |= WL_EVENT_READABLE;
+               if (kp->kqread.flags & EV_EOF)
+                       mask |= WL_EVENT_HANGUP;
+               if (kp->kqread.flags & EV_ERROR)
+                        mask |= WL_EVENT_ERROR;
+       }
+        if (kp->mask & KEPM_WRITE) {
+               mask |= WL_EVENT_WRITABLE;
+               if (kp->kqwrite.flags & EV_EOF)
+                       mask |= WL_EVENT_HANGUP;
+               if (kp->kqwrite.flags & EV_ERROR)
+                       mask |= WL_EVENT_ERROR;
+       }
+#else
+        if (ep->events & EPOLLIN)
                mask |= WL_EVENT_READABLE;
        if (ep->events & EPOLLOUT)
                mask |= WL_EVENT_WRITABLE;
@@ -108,6 +211,7 @@ wl_event_source_fd_dispatch(struct wl_event_source *source,
                mask |= WL_EVENT_HANGUP;
        if (ep->events & EPOLLERR)
                mask |= WL_EVENT_ERROR;
+#endif
 
        return fd_source->func(fd_source->fd, mask, source->data);
 }
@@ -120,7 +224,12 @@ static struct wl_event_source *
 add_source(struct wl_event_loop *loop,
           struct wl_event_source *source, uint32_t mask, void *data)
 {
+#ifdef __USE_KQUEUE
+       struct kevent karray[2];
+       int retval;
+#else
        struct epoll_event ep;
+#endif
 
        if (source->fd < 0) {
                free(source);
@@ -131,6 +240,20 @@ add_source(struct wl_event_loop *loop,
        source->data = data;
        wl_list_init(&source->link);
 
+#ifdef __USE_KQUEUE
+       retval = kq_modify_helper(source, mask);
+       if (retval != 0) {
+               /* If we fail remove everything. */
+               EV_SET(&karray[0], source->fd, EVFILT_READ,
+                      EV_DELETE, 0, 0, source);
+               EV_SET(&karray[1], source->fd, EVFILT_WRITE,
+                      EV_DELETE, 0, 0, source);
+               kevent(loop->kqueue_fd, karray, 2, 0, 0, NULL);
+               close(source->fd);
+               free(source);
+               return NULL;
+       }
+#else
        memset(&ep, 0, sizeof ep);
        if (mask & WL_EVENT_READABLE)
                ep.events |= EPOLLIN;
@@ -143,6 +266,7 @@ add_source(struct wl_event_loop *loop,
                free(source);
                return NULL;
        }
+#endif
 
        return source;
 }
@@ -214,6 +338,9 @@ wl_event_loop_add_fd(struct wl_event_loop *loop,
 WL_EXPORT int
 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
 {
+#ifdef __USE_KQUEUE
+       return kq_modify_helper(source, mask);
+#else
        struct wl_event_loop *loop = source->loop;
        struct epoll_event ep;
 
@@ -225,6 +352,7 @@ wl_event_source_fd_update(struct wl_event_source *source, 
uint32_t mask)
        ep.data.ptr = source;
 
        return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
+#endif
 }
 
 /** \cond INTERNAL */
@@ -237,11 +365,19 @@ struct wl_event_source_timer {
        int heap_idx;
 };
 
+#ifdef __USE_KQUEUE
+static int
+noop_dispatch(struct wl_event_source *source,
+             struct kevent_pair *ep) {
+       return 0;
+}
+#else
 static int
 noop_dispatch(struct wl_event_source *source,
              struct epoll_event *ep) {
        return 0;
 }
+#endif
 
 struct wl_event_source_interface timer_heap_source_interface = {
        noop_dispatch,
@@ -256,6 +392,28 @@ time_lt(struct timespec ta, struct timespec tb)
        return ta.tv_nsec < tb.tv_nsec;
 }
 
+#ifdef __USE_KQUEUE
+static int
+set_timer(struct wl_timer_heap *timers, struct timespec deadline) {
+       struct kevent ke;
+       int retval;
+again:
+       EV_SET(&ke, timers->base.fd, EVFILT_TIMER, EV_ADD|EV_RECEIPT,
+           NOTE_ABSTIME|NOTE_NSECONDS,
+           deadline.tv_sec*1000*1000*1000 + deadline.tv_nsec, NULL);
+       retval = kevent(timers->base.loop->kqueue_fd, &ke, 1, &ke, 1, NULL);
+       if (retval == -1) {
+               if (errno == EINTR)
+                       goto again;
+               else
+                       return -1;
+       }
+       if (ke.data != 0)
+               return -1;
+
+       return 0;
+}
+#else
 static int
 set_timer(int timerfd, struct timespec deadline) {
        struct itimerspec its;
@@ -265,9 +423,32 @@ set_timer(int timerfd, struct timespec deadline) {
        its.it_value = deadline;
        return timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &its, NULL);
 }
+#endif
+
+#ifdef __USE_KQUEUE
+static int
+clear_timer(struct wl_timer_heap *timers)
+{
+       struct kevent ke;
+       int retval;
+again:
+       EV_SET(&ke, timers->base.fd, EVFILT_TIMER, EV_DELETE|EV_RECEIPT, 0, 0,
+           NULL);
+       retval = kevent(timers->base.loop->kqueue_fd, &ke, 1, &ke, 1, NULL);
+       if (retval == -1) {
+               if (errno == EINTR)
+                       goto again;
+               else
+                       return -1;
+       }
+       if (ke.data != 0 && ke.data != ENOENT)
+               return -1;
 
+       return 0;
+}
+#else
 static int
-clear_timer(int timerfd)
+clear_timer(struct wl_timer_heap *timers)
 {
        struct itimerspec its;
 
@@ -277,6 +458,7 @@ clear_timer(int timerfd)
        its.it_value.tv_nsec = 0;
        return timerfd_settime(timerfd, 0, &its, NULL);
 }
+#endif
 
 static void
 wl_timer_heap_init(struct wl_timer_heap *timers, struct wl_event_loop *loop)
@@ -296,15 +478,25 @@ wl_timer_heap_init(struct wl_timer_heap *timers, struct 
wl_event_loop *loop)
 static void
 wl_timer_heap_release(struct wl_timer_heap *timers)
 {
+#ifdef __USE_KQUEUE
+       clear_timer(timers);
+#else
        if (timers->base.fd != -1) {
                close(timers->base.fd);
        }
+#endif
        free(timers->data);
 }
 
 static int
 wl_timer_heap_ensure_timerfd(struct wl_timer_heap *timers)
 {
+#ifdef __USE_KQUEUE
+       if (timers->base.fd != -1)
+               return 0;
+       timers->base.fd = 37421; /* Just a random identifier. */
+       return 0;
+#else
        struct epoll_event ep;
        int timer_fd;
 
@@ -328,6 +520,7 @@ wl_timer_heap_ensure_timerfd(struct wl_timer_heap *timers)
 
        timers->base.fd = timer_fd;
        return 0;
+#endif
 }
 
 static int
@@ -512,6 +705,15 @@ wl_timer_heap_dispatch(struct wl_timer_heap *timers)
        if (list_tail)
                list_tail->next_due = NULL;
 
+#ifdef __USE_KQUEUE
+       if (timers->active > 0) {
+               if (set_timer(timers, timers->data[0]->deadline) < 0)
+                       return -1;
+       } else {
+               if (clear_timer(timers) < 0)
+                       return -1;
+       }
+#else
        if (timers->active > 0) {
                if (set_timer(timers->base.fd, timers->data[0]->deadline) < 0)
                        return -1;
@@ -519,6 +721,7 @@ wl_timer_heap_dispatch(struct wl_timer_heap *timers)
                if (clear_timer(timers->base.fd) < 0)
                        return -1;
        }
+#endif
 
        /* Execute precisely the functions for events before `now`, in order.
         * Because wl_event_loop_dispatch ignores return codes, do the same
@@ -531,9 +734,15 @@ wl_timer_heap_dispatch(struct wl_timer_heap *timers)
        return 0;
 }
 
+#ifdef __USE_KQUEUE
+static int
+wl_event_source_timer_dispatch(struct wl_event_source *source,
+                              struct kevent_pair *ep)
+#else
 static int
 wl_event_source_timer_dispatch(struct wl_event_source *source,
                               struct epoll_event *ep)
+#endif
 {
        struct wl_event_source_timer *timer;
 
@@ -641,8 +850,13 @@ wl_event_source_timer_update(struct wl_event_source 
*source, int ms_delay)
                if (tsource->heap_idx == 0) {
                        /* Only update the timerfd if the new deadline is
                         * the earliest */
+#ifdef __USE_KQUEUE
+                       if (set_timer(timers, deadline) < 0)
+                               return -1;
+#else
                        if (set_timer(timers->base.fd, deadline) < 0)
                                return -1;
+#endif
                }
        } else {
                if (tsource->heap_idx == -1)
@@ -652,8 +866,13 @@ wl_event_source_timer_update(struct wl_event_source 
*source, int ms_delay)
                if (timers->active == 0) {
                        /* Only update the timerfd if this was the last
                         * active timer */
+#ifdef __USE_KQUEUE
+                       if (clear_timer(timers) < 0)
+                               return -1;
+#else
                        if (clear_timer(timers->base.fd) < 0)
                                return -1;
+#endif
                }
        }
 
@@ -670,6 +889,18 @@ struct wl_event_source_signal {
 
 /** \endcond */
 
+#ifdef __USE_KQUEUE
+static int
+wl_event_source_signal_dispatch(struct wl_event_source *source,
+                               struct kevent_pair *unused)
+{
+       struct wl_event_source_signal *signal_source =
+           (struct wl_event_source_signal *)source;
+
+       return signal_source->func(signal_source->signal_number,
+           signal_source->base.data);
+}
+#else
 static int
 wl_event_source_signal_dispatch(struct wl_event_source *source,
                                struct epoll_event *ep)
@@ -687,6 +918,7 @@ wl_event_source_signal_dispatch(struct wl_event_source 
*source,
        return signal_source->func(signal_source->signal_number,
                                   signal_source->base.data);
 }
+#endif
 
 struct wl_event_source_interface signal_source_interface = {
        wl_event_source_signal_dispatch,
@@ -717,6 +949,10 @@ wl_event_loop_add_signal(struct wl_event_loop *loop,
                         wl_event_loop_signal_func_t func,
                         void *data)
 {
+#ifdef __USE_KQUEUE
+       struct kevent ke;
+       int retval;
+#endif
        struct wl_event_source_signal *source;
        sigset_t mask;
 
@@ -725,16 +961,35 @@ wl_event_loop_add_signal(struct wl_event_loop *loop,
                return NULL;
 
        source->base.interface = &signal_source_interface;
+       source->base.loop = loop;
+       wl_list_init(&source->base.link);
        source->signal_number = signal_number;
+       source->base.data = data;
 
        sigemptyset(&mask);
        sigaddset(&mask, signal_number);
+#ifdef __USE_KQUEUE
+       source->base.fd = signal_number;
+#else
        source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
+#endif
        sigprocmask(SIG_BLOCK, &mask, NULL);
 
        source->func = func;
 
+#ifdef __USE_KQUEUE
+again:
+       EV_SET(&ke, source->signal_number, EVFILT_SIGNAL, EV_ADD, 0, 0, data);
+       retval = kevent(loop->kqueue_fd, &ke, 1, &ke, 1, NULL);
+       if (retval == -1 && errno == EINTR)
+               goto again;
+       if (ke.data != 0)
+               return NULL;
+
+       return &source->base;
+#else
        return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+#endif
 }
 
 /** \cond INTERNAL */
@@ -832,6 +1087,60 @@ wl_event_source_remove(struct wl_event_source *source)
 {
        struct wl_event_loop *loop = source->loop;
 
+#ifdef __USE_KQUEUE
+       struct kevent kp[2];
+       int retval;
+
+       if (source->interface == &timer_source_interface &&
+           source->fd != TIMER_REMOVED) {
+               /* Disarm the timer (and the loop's timerfd, if necessary),
+                * before removing its space in the loop timer heap */
+               wl_event_source_timer_update(source, 0);
+               wl_timer_heap_unreserve(&loop->timers);
+               /* Set the fd field to to indicate that the timer should NOT
+                * be dispatched in `wl_event_loop_dispatch` */
+               source->fd = TIMER_REMOVED;
+       }
+
+again:
+       if (source->interface == &fd_source_interface) {
+               EV_SET(&kp[0], source->fd, EVFILT_READ, EV_DELETE|EV_RECEIPT,
+                   0, 0, source);
+               EV_SET(&kp[1], source->fd, EVFILT_WRITE, EV_DELETE|EV_RECEIPT,
+                   0, 0, source);
+               retval = kevent(loop->kqueue_fd, kp, 2, kp, 2, NULL);
+               if ((retval == -1 && errno == EAGAIN) || retval == 1)
+                       goto again;
+               if (!(kp[0].data == 0 || kp[0].data == ENOENT) ||
+                   !(kp[1].data == 0 || kp[1].data == ENOENT))
+                       goto again; /* Can this happen? */
+               close(source->fd);
+       }
+       if (source->interface == &timer_source_interface){
+               EV_SET(&kp[0], source->fd, EVFILT_TIMER, EV_DELETE|EV_RECEIPT,
+                   0, 0, source);
+               retval = kevent(loop->kqueue_fd, kp, 1, kp, 1, NULL);
+               if (retval == -1 && errno == EAGAIN)
+                       goto again;
+               if (kp[0].data != 0 && kp[0].data != ENOENT)
+                       goto again; /* Can this happen? */
+       }
+       if (source->interface == &signal_source_interface) {
+               EV_SET(&kp[0], source->fd, EVFILT_SIGNAL, EV_DELETE|EV_RECEIPT,
+                   0, 0, source);
+               retval = kevent(loop->kqueue_fd, kp, 1, kp, 1, NULL);
+               if (retval == -1 && errno == EAGAIN)
+                       goto again;
+
+               if (kp[0].data != 0 && kp[0].data != ENOENT)
+                       goto again; /* Can this happen? */
+       }
+
+       wl_list_remove(&source->link);
+       wl_list_insert(&loop->destroy_list, &source->link);
+
+       return 0;
+#else
        /* 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) {
@@ -855,6 +1164,7 @@ wl_event_source_remove(struct wl_event_source *source)
        wl_list_insert(&loop->destroy_list, &source->link);
 
        return 0;
+#endif
 }
 
 static void
@@ -891,11 +1201,19 @@ wl_event_loop_create(void)
        if (loop == NULL)
                return NULL;
 
+#ifdef __USE_KQUEUE
+       loop->kqueue_fd = kqueue();
+       if (loop->kqueue_fd < 0) {
+               free(loop);
+               return NULL;
+       }
+#else
        loop->epoll_fd = wl_os_epoll_create_cloexec();
        if (loop->epoll_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);
@@ -926,19 +1244,28 @@ wl_event_loop_destroy(struct wl_event_loop *loop)
        wl_priv_signal_final_emit(&loop->destroy_signal, loop);
 
        wl_event_loop_process_destroy_list(loop);
+#ifdef __USE_KQUEUE
+       wl_timer_heap_release(&loop->timers);
+       close(loop->kqueue_fd);
+#else
        wl_timer_heap_release(&loop->timers);
        close(loop->epoll_fd);
+#endif
        free(loop);
 }
 
 static bool
 post_dispatch_check(struct wl_event_loop *loop)
 {
+#ifdef __USE_KQUEUE
+       struct kevent_pair ep = { 0 };
+#else
        struct epoll_event ep;
+       ep.events = 0;
+#endif
        struct wl_event_source *source, *next;
        bool needs_recheck = false;
 
-       ep.events = 0;
        wl_list_for_each_safe(source, next, &loop->check_list, link) {
                int dispatch_result;
 
@@ -1047,7 +1374,14 @@ timespec_sub(struct timespec a, struct timespec b)
 WL_EXPORT int
 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
 {
+#ifdef __USE_KQUEUE
+       struct kevent ke[32];
+       struct kevent_pair kp;
+       struct timespec to;
+       int j;
+#else
        struct epoll_event ep[32];
+#endif
        struct wl_event_source *source;
        int i, count;
        bool has_timers = false;
@@ -1062,7 +1396,13 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int 
timeout)
        }
 
        while (true) {
+#ifdef __USE_KQUEUE
+               to = ms_to_timespec(timeout);
+               count = kevent(loop->kqueue_fd, NULL, 0, ke, ARRAY_LENGTH(ke),
+                   use_timeout ? &to : NULL);
+#else
                count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), 
timeout);
+#endif
                if (count >= 0)
                        break; /* have events or timeout */
                else if (count < 0 && errno != EINTR && errno != EAGAIN)
@@ -1083,11 +1423,18 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int 
timeout)
                return -1;
 
        for (i = 0; i < count; i++) {
+#ifdef __USE_KQUEUE
+               if (ke[i].filter == EVFILT_TIMER) {
+                       has_timers = true;
+                       break;
+               }
+#else
                source = ep[i].data.ptr;
                if (source == &loop->timers.base) {
                        has_timers = true;
                        break;
                }
+#endif
        }
 
        if (has_timers) {
@@ -1101,9 +1448,52 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int 
timeout)
        }
 
        for (i = 0; i < count; i++) {
+#ifdef __USE_KQUEUE
+               kp.mask = 0;
+               if (ke[i].filter == EVFILT_TIMER ||
+                   ke[i].filter == EVFILT_SYSCOUNT)
+                       continue;
+               if (ke[i].filter == EVFILT_SIGNAL) {
+                       source = ke[i].udata;
+                       source->interface->dispatch(source, NULL);
+                       continue;
+               }
+               if (ke[i].filter == EVFILT_READ) {
+                       kp.kqread = ke[i];
+                       kp.mask |= KEPM_READ;
+               }
+               if (ke[i].filter == EVFILT_WRITE) {
+                       kp.kqwrite = ke[i];
+                       kp.mask |= KEPM_WRITE;
+               }
+               if (kp.mask == 0) {
+                       wl_log("Unhandled filter");
+                       continue;
+               }
+               for (j = i + 1; j < count; j++) {
+                       if (ke[i].ident == ke[j].ident) {
+                               if (ke[j].filter == EVFILT_READ) {
+                                       kp.kqread = ke[j];
+                                       kp.mask |= KEPM_READ;
+                                       ke[j].filter = EVFILT_SYSCOUNT;
+                                       break;
+                               }
+                               if (ke[j].filter == EVFILT_WRITE) {
+                                       kp.kqwrite = ke[j];
+                                       kp.mask |= KEPM_READ;
+                                       ke[j].filter = EVFILT_SYSCOUNT;
+                                       break;
+                               }
+                               /* We get to here if signals and fds match. */
+                       }
+               }
+               source = ke[i].udata;
+               source->interface->dispatch(source, &kp);
+#else
                source = ep[i].data.ptr;
                if (source->fd != -1)
                        source->interface->dispatch(source, &ep[i]);
+#endif
        }
 
        wl_event_loop_process_destroy_list(loop);
@@ -1134,7 +1524,11 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int 
timeout)
 WL_EXPORT int
 wl_event_loop_get_fd(struct wl_event_loop *loop)
 {
+#ifdef __USE_KQUEUE
+       return loop->kqueue_fd;
+#else
        return loop->epoll_fd;
+#endif
 }
 
 /** Register a destroy listener for an event loop context
diff --git a/src/wayland-os.c b/src/wayland-os.c
index f00ead4..4d559e2 100644
--- a/src/wayland-os.c
+++ b/src/wayland-os.c
@@ -33,7 +33,15 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
+
+#ifdef __USE_KQUEUE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#else
 #include <sys/epoll.h>
+#endif
+
 #include <sys/mman.h>
 #include <sys/un.h>
 #ifdef HAVE_SYS_UCRED_H
@@ -46,7 +54,9 @@
 int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl;
 int (*wl_socket)(int domain, int type, int protocol) = socket;
 ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg;
+#ifndef __USE_KQUEUE
 int (*wl_epoll_create1)(int flags) = epoll_create1;
+#endif
 
 static int
 set_cloexec_or_close(int fd)
@@ -198,6 +208,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int 
flags)
        return recvmsg_cloexec_fallback(sockfd, msg, flags);
 }
 
+#ifndef __USE_KQUEUE
 int
 wl_os_epoll_create_cloexec(void)
 {
@@ -214,6 +225,7 @@ wl_os_epoll_create_cloexec(void)
        fd = epoll_create(1);
        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 068fd2f..c672d82 100644
--- a/src/wayland-os.h
+++ b/src/wayland-os.h
@@ -41,8 +41,10 @@ wl_os_dupfd_cloexec(int fd, int minfd);
 ssize_t
 wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
 
+#ifndef __USE_KQUEUE
 int
 wl_os_epoll_create_cloexec(void);
+#endif
 
 int
 wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 1d6be3e..d521b91 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -23,6 +23,7 @@
  * SOFTWARE.
  */
 
+#include "wayland-server-core.h"
 #define _GNU_SOURCE
 
 #include <stdbool.h>
@@ -39,7 +40,9 @@
 #include <dlfcn.h>
 #include <sys/time.h>
 #include <fcntl.h>
+#ifndef __USE_KQUEUE
 #include <sys/eventfd.h>
+#endif
 #include <sys/file.h>
 #include <sys/stat.h>
 
@@ -110,6 +113,9 @@ struct wl_display {
        void *global_filter_data;
 
        int terminate_efd;
+#ifdef __USE_KQUEUE
+       int terminate_efd_read;
+#endif
        struct wl_event_source *term_source;
 
        size_t max_buffer_size;
@@ -1155,6 +1161,10 @@ wl_display_create(void)
        struct wl_display *display;
        const char *debug;
 
+#ifdef __USE_KQUEUE
+       int termpipe[2];
+#endif
+
        debug = getenv("WAYLAND_DEBUG");
        if (debug && (strstr(debug, "server") || strstr(debug, "1")))
                debug_server = 1;
@@ -1169,6 +1179,14 @@ wl_display_create(void)
                return NULL;
        }
 
+#ifdef __USE_KQUEUE
+       if (pipe2(termpipe, O_CLOEXEC|O_NONBLOCK) == -1)
+               goto err_eventfd;
+       display->terminate_efd_read = termpipe[0];
+       display->term_source = wl_event_loop_add_fd(display->loop, termpipe[0],
+           WL_EVENT_READABLE, handle_display_terminate, NULL);
+       display->terminate_efd = termpipe[1];
+#else
        display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (display->terminate_efd < 0)
                goto err_eventfd;
@@ -1178,7 +1196,7 @@ wl_display_create(void)
                                                    WL_EVENT_READABLE,
                                                    handle_display_terminate,
                                                    NULL);
-
+#endif
        if (display->term_source == NULL)
                goto err_term_source;
 
@@ -1204,6 +1222,9 @@ wl_display_create(void)
 
 err_term_source:
        close(display->terminate_efd);
+#ifdef __USE_KQUEUE
+       close(display->terminate_efd_read);
+#endif
 err_eventfd:
        wl_event_loop_destroy(display->loop);
        free(display);
@@ -1268,6 +1289,9 @@ wl_display_destroy(struct wl_display *display)
        }
 
        close(display->terminate_efd);
+#ifdef __USE_KQUEUE
+       close(display->terminate_efd_read);
+#endif
        wl_event_source_remove(display->term_source);
 
        wl_event_loop_destroy(display->loop);

Reply via email to