2 * Copyright © 2008 Kristian Høgsberg
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
30 #include <sys/socket.h>
32 #include <sys/epoll.h>
33 #include <sys/signalfd.h>
34 #include <sys/timerfd.h>
37 #include "wayland-server.h"
38 #include "wayland-os.h"
40 struct wl_event_loop {
42 struct wl_list check_list;
43 struct wl_list idle_list;
44 struct wl_list destroy_list;
47 struct wl_event_source_interface {
48 int (*dispatch)(struct wl_event_source *source,
49 struct epoll_event *ep);
52 struct wl_event_source {
53 struct wl_event_source_interface *interface;
54 struct wl_event_loop *loop;
60 struct wl_event_source_fd {
61 struct wl_event_source base;
62 wl_event_loop_fd_func_t func;
67 wl_event_source_fd_dispatch(struct wl_event_source *source,
68 struct epoll_event *ep)
70 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
74 if (ep->events & EPOLLIN)
75 mask |= WL_EVENT_READABLE;
76 if (ep->events & EPOLLOUT)
77 mask |= WL_EVENT_WRITABLE;
78 if (ep->events & EPOLLHUP)
79 mask |= WL_EVENT_HANGUP;
80 if (ep->events & EPOLLERR)
81 mask |= WL_EVENT_ERROR;
83 return fd_source->func(fd_source->fd, mask, source->data);
86 struct wl_event_source_interface fd_source_interface = {
87 wl_event_source_fd_dispatch,
90 static struct wl_event_source *
91 add_source(struct wl_event_loop *loop,
92 struct wl_event_source *source, uint32_t mask, void *data)
94 struct epoll_event ep;
97 fprintf(stderr, "could not add source\n: %m");
104 wl_list_init(&source->link);
106 memset(&ep, 0, sizeof ep);
107 if (mask & WL_EVENT_READABLE)
108 ep.events |= EPOLLIN;
109 if (mask & WL_EVENT_WRITABLE)
110 ep.events |= EPOLLOUT;
111 ep.data.ptr = source;
113 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
122 WL_EXPORT struct wl_event_source *
123 wl_event_loop_add_fd(struct wl_event_loop *loop,
124 int fd, uint32_t mask,
125 wl_event_loop_fd_func_t func,
128 struct wl_event_source_fd *source;
130 source = malloc(sizeof *source);
134 source->base.interface = &fd_source_interface;
135 source->base.fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
139 return add_source(loop, &source->base, mask, data);
143 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
145 struct wl_event_loop *loop = source->loop;
146 struct epoll_event ep;
148 memset(&ep, 0, sizeof ep);
149 if (mask & WL_EVENT_READABLE)
150 ep.events |= EPOLLIN;
151 if (mask & WL_EVENT_WRITABLE)
152 ep.events |= EPOLLOUT;
153 ep.data.ptr = source;
155 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
158 struct wl_event_source_timer {
159 struct wl_event_source base;
160 wl_event_loop_timer_func_t func;
164 wl_event_source_timer_dispatch(struct wl_event_source *source,
165 struct epoll_event *ep)
167 struct wl_event_source_timer *timer_source =
168 (struct wl_event_source_timer *) source;
172 len = read(source->fd, &expires, sizeof expires);
173 if (len != sizeof expires)
174 /* Is there anything we can do here? Will this ever happen? */
175 fprintf(stderr, "timerfd read error: %m\n");
177 return timer_source->func(timer_source->base.data);
180 struct wl_event_source_interface timer_source_interface = {
181 wl_event_source_timer_dispatch,
184 WL_EXPORT struct wl_event_source *
185 wl_event_loop_add_timer(struct wl_event_loop *loop,
186 wl_event_loop_timer_func_t func,
189 struct wl_event_source_timer *source;
191 source = malloc(sizeof *source);
195 source->base.interface = &timer_source_interface;
196 source->base.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
199 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
203 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
205 struct itimerspec its;
207 its.it_interval.tv_sec = 0;
208 its.it_interval.tv_nsec = 0;
209 its.it_value.tv_sec = ms_delay / 1000;
210 its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
211 if (timerfd_settime(source->fd, 0, &its, NULL) < 0) {
212 fprintf(stderr, "could not set timerfd\n: %m");
219 struct wl_event_source_signal {
220 struct wl_event_source base;
222 wl_event_loop_signal_func_t func;
226 wl_event_source_signal_dispatch(struct wl_event_source *source,
227 struct epoll_event *ep)
229 struct wl_event_source_signal *signal_source =
230 (struct wl_event_source_signal *) source;
231 struct signalfd_siginfo signal_info;
234 len = read(source->fd, &signal_info, sizeof signal_info);
235 if (len != sizeof signal_info)
236 /* Is there anything we can do here? Will this ever happen? */
237 fprintf(stderr, "signalfd read error: %m\n");
239 return signal_source->func(signal_source->signal_number,
240 signal_source->base.data);
243 struct wl_event_source_interface signal_source_interface = {
244 wl_event_source_signal_dispatch,
247 WL_EXPORT struct wl_event_source *
248 wl_event_loop_add_signal(struct wl_event_loop *loop,
250 wl_event_loop_signal_func_t func,
253 struct wl_event_source_signal *source;
256 source = malloc(sizeof *source);
260 source->base.interface = &signal_source_interface;
261 source->signal_number = signal_number;
264 sigaddset(&mask, signal_number);
265 source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC);
266 sigprocmask(SIG_BLOCK, &mask, NULL);
270 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
273 struct wl_event_source_idle {
274 struct wl_event_source base;
275 wl_event_loop_idle_func_t func;
278 struct wl_event_source_interface idle_source_interface = {
282 WL_EXPORT struct wl_event_source *
283 wl_event_loop_add_idle(struct wl_event_loop *loop,
284 wl_event_loop_idle_func_t func,
287 struct wl_event_source_idle *source;
289 source = malloc(sizeof *source);
293 source->base.interface = &idle_source_interface;
294 source->base.loop = loop;
295 source->base.fd = -1;
298 source->base.data = data;
300 wl_list_insert(loop->idle_list.prev, &source->base.link);
302 return &source->base;
306 wl_event_source_check(struct wl_event_source *source)
308 wl_list_insert(source->loop->check_list.prev, &source->link);
312 wl_event_source_remove(struct wl_event_source *source)
314 struct wl_event_loop *loop = source->loop;
316 /* We need to explicitly remove the fd, since closing the fd
317 * isn't enough in case we've dup'ed the fd. */
318 if (source->fd >= 0) {
319 epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
324 wl_list_remove(&source->link);
325 wl_list_insert(&loop->destroy_list, &source->link);
331 wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
333 struct wl_event_source *source, *next;
335 wl_list_for_each_safe(source, next, &loop->destroy_list, link)
338 wl_list_init(&loop->destroy_list);
341 WL_EXPORT struct wl_event_loop *
342 wl_event_loop_create(void)
344 struct wl_event_loop *loop;
346 loop = malloc(sizeof *loop);
350 loop->epoll_fd = wl_os_epoll_create_cloexec();
351 if (loop->epoll_fd < 0) {
355 wl_list_init(&loop->check_list);
356 wl_list_init(&loop->idle_list);
357 wl_list_init(&loop->destroy_list);
363 wl_event_loop_destroy(struct wl_event_loop *loop)
365 wl_event_loop_process_destroy_list(loop);
366 close(loop->epoll_fd);
371 post_dispatch_check(struct wl_event_loop *loop)
373 struct epoll_event ep;
374 struct wl_event_source *source, *next;
379 wl_list_for_each_safe(source, next, &loop->check_list, link)
380 n += source->interface->dispatch(source, &ep);
386 wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
388 struct wl_event_source_idle *source;
390 while (!wl_list_empty(&loop->idle_list)) {
391 source = container_of(loop->idle_list.next,
392 struct wl_event_source_idle, base.link);
393 source->func(source->base.data);
394 wl_event_source_remove(&source->base);
399 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
401 struct epoll_event ep[32];
402 struct wl_event_source *source;
405 wl_event_loop_dispatch_idle(loop);
407 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
411 for (i = 0; i < count; i++) {
412 source = ep[i].data.ptr;
413 if (source->fd != -1)
414 source->interface->dispatch(source, &ep[i]);
417 wl_event_loop_process_destroy_list(loop);
420 n = post_dispatch_check(loop);
427 wl_event_loop_get_fd(struct wl_event_loop *loop)
429 return loop->epoll_fd;