Download raw body.
(no subject)
Posting here from misc (with whitespace issue hopefully resolved).
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..0105188 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..59af9fd 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);
(no subject)