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);