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
29 #include <sys/socket.h>
31 #include <sys/epoll.h>
32 #include <sys/signalfd.h>
33 #include <sys/timerfd.h>
36 #include "wayland-server.h"
38 struct wl_event_loop {
40 struct wl_list check_list;
41 struct wl_list idle_list;
44 struct wl_event_source_interface {
45 int (*dispatch)(struct wl_event_source *source,
46 struct epoll_event *ep);
47 int (*remove)(struct wl_event_source *source);
50 struct wl_event_source {
51 struct wl_event_source_interface *interface;
52 struct wl_event_loop *loop;
57 struct wl_event_source_fd {
58 struct wl_event_source base;
60 wl_event_loop_fd_func_t func;
64 wl_event_source_fd_dispatch(struct wl_event_source *source,
65 struct epoll_event *ep)
67 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
71 if (ep->events & EPOLLIN)
72 mask |= WL_EVENT_READABLE;
73 if (ep->events & EPOLLOUT)
74 mask |= WL_EVENT_WRITEABLE;
76 return fd_source->func(fd_source->fd, mask, fd_source->base.data);
80 wl_event_source_fd_remove(struct wl_event_source *source)
82 struct wl_event_source_fd *fd_source =
83 (struct wl_event_source_fd *) source;
84 struct wl_event_loop *loop = source->loop;
90 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
93 struct wl_event_source_interface fd_source_interface = {
94 wl_event_source_fd_dispatch,
95 wl_event_source_fd_remove
98 WL_EXPORT struct wl_event_source *
99 wl_event_loop_add_fd(struct wl_event_loop *loop,
100 int fd, uint32_t mask,
101 wl_event_loop_fd_func_t func,
104 struct wl_event_source_fd *source;
105 struct epoll_event ep;
107 source = malloc(sizeof *source);
111 source->base.interface = &fd_source_interface;
112 source->base.loop = loop;
113 wl_list_init(&source->base.link);
116 source->base.data = data;
118 memset(&ep, 0, sizeof ep);
119 if (mask & WL_EVENT_READABLE)
120 ep.events |= EPOLLIN;
121 if (mask & WL_EVENT_WRITEABLE)
122 ep.events |= EPOLLOUT;
123 ep.data.ptr = source;
125 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
130 return &source->base;
134 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
136 struct wl_event_source_fd *fd_source =
137 (struct wl_event_source_fd *) source;
138 struct wl_event_loop *loop = source->loop;
139 struct epoll_event ep;
141 memset(&ep, 0, sizeof ep);
142 if (mask & WL_EVENT_READABLE)
143 ep.events |= EPOLLIN;
144 if (mask & WL_EVENT_WRITEABLE)
145 ep.events |= EPOLLOUT;
146 ep.data.ptr = source;
148 return epoll_ctl(loop->epoll_fd,
149 EPOLL_CTL_MOD, fd_source->fd, &ep);
152 struct wl_event_source_timer {
153 struct wl_event_source base;
155 wl_event_loop_timer_func_t func;
159 wl_event_source_timer_dispatch(struct wl_event_source *source,
160 struct epoll_event *ep)
162 struct wl_event_source_timer *timer_source =
163 (struct wl_event_source_timer *) source;
166 read(timer_source->fd, &expires, sizeof expires);
168 return timer_source->func(timer_source->base.data);
172 wl_event_source_timer_remove(struct wl_event_source *source)
174 struct wl_event_source_timer *timer_source =
175 (struct wl_event_source_timer *) source;
177 close(timer_source->fd);
182 struct wl_event_source_interface timer_source_interface = {
183 wl_event_source_timer_dispatch,
184 wl_event_source_timer_remove
187 WL_EXPORT struct wl_event_source *
188 wl_event_loop_add_timer(struct wl_event_loop *loop,
189 wl_event_loop_timer_func_t func,
192 struct wl_event_source_timer *source;
193 struct epoll_event ep;
195 source = malloc(sizeof *source);
199 source->base.interface = &timer_source_interface;
200 source->base.loop = loop;
201 wl_list_init(&source->base.link);
203 source->fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
204 if (source->fd < 0) {
205 fprintf(stderr, "could not create timerfd\n: %m");
211 source->base.data = data;
213 memset(&ep, 0, sizeof ep);
215 ep.data.ptr = source;
217 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
223 return &source->base;
227 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
229 struct wl_event_source_timer *timer_source =
230 (struct wl_event_source_timer *) source;
231 struct itimerspec its;
233 its.it_interval.tv_sec = 0;
234 its.it_interval.tv_nsec = 0;
235 its.it_value.tv_sec = ms_delay / 1000;
236 its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
237 if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
238 fprintf(stderr, "could not set timerfd\n: %m");
245 struct wl_event_source_signal {
246 struct wl_event_source base;
249 wl_event_loop_signal_func_t func;
253 wl_event_source_signal_dispatch(struct wl_event_source *source,
254 struct epoll_event *ep)
256 struct wl_event_source_signal *signal_source =
257 (struct wl_event_source_signal *) source;
258 struct signalfd_siginfo signal_info;
260 read(signal_source->fd, &signal_info, sizeof signal_info);
262 return signal_source->func(signal_source->signal_number,
263 signal_source->base.data);
267 wl_event_source_signal_remove(struct wl_event_source *source)
269 struct wl_event_source_signal *signal_source =
270 (struct wl_event_source_signal *) source;
272 close(signal_source->fd);
277 struct wl_event_source_interface signal_source_interface = {
278 wl_event_source_signal_dispatch,
279 wl_event_source_signal_remove
282 WL_EXPORT struct wl_event_source *
283 wl_event_loop_add_signal(struct wl_event_loop *loop,
285 wl_event_loop_signal_func_t func,
288 struct wl_event_source_signal *source;
289 struct epoll_event ep;
292 source = malloc(sizeof *source);
296 source->base.interface = &signal_source_interface;
297 source->base.loop = loop;
298 wl_list_init(&source->base.link);
299 source->signal_number = signal_number;
302 sigaddset(&mask, signal_number);
303 source->fd = signalfd(-1, &mask, SFD_CLOEXEC);
304 if (source->fd < 0) {
305 fprintf(stderr, "could not create fd to watch signal\n: %m");
309 sigprocmask(SIG_BLOCK, &mask, NULL);
312 source->base.data = data;
314 memset(&ep, 0, sizeof ep);
316 ep.data.ptr = source;
318 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
324 return &source->base;
327 struct wl_event_source_idle {
328 struct wl_event_source base;
329 wl_event_loop_idle_func_t func;
333 wl_event_source_idle_remove(struct wl_event_source *source)
340 struct wl_event_source_interface idle_source_interface = {
342 wl_event_source_idle_remove
345 WL_EXPORT struct wl_event_source *
346 wl_event_loop_add_idle(struct wl_event_loop *loop,
347 wl_event_loop_idle_func_t func,
350 struct wl_event_source_idle *source;
352 source = malloc(sizeof *source);
356 source->base.interface = &idle_source_interface;
357 source->base.loop = loop;
360 source->base.data = data;
362 wl_list_insert(loop->idle_list.prev, &source->base.link);
364 return &source->base;
368 wl_event_source_check(struct wl_event_source *source)
370 wl_list_insert(source->loop->check_list.prev, &source->link);
374 wl_event_source_remove(struct wl_event_source *source)
376 if (!wl_list_empty(&source->link))
377 wl_list_remove(&source->link);
379 source->interface->remove(source);
384 WL_EXPORT struct wl_event_loop *
385 wl_event_loop_create(void)
387 struct wl_event_loop *loop;
389 loop = malloc(sizeof *loop);
393 loop->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
394 if (loop->epoll_fd < 0) {
398 wl_list_init(&loop->check_list);
399 wl_list_init(&loop->idle_list);
405 wl_event_loop_destroy(struct wl_event_loop *loop)
407 close(loop->epoll_fd);
412 post_dispatch_check(struct wl_event_loop *loop)
414 struct epoll_event ep;
415 struct wl_event_source *source, *next;
420 wl_list_for_each_safe(source, next, &loop->check_list, link)
421 n += source->interface->dispatch(source, &ep);
427 dispatch_idle_sources(struct wl_event_loop *loop)
429 struct wl_event_source_idle *source, *next;
431 wl_list_for_each_safe(source, next, &loop->idle_list, base.link) {
432 source->func(source->base.data);
433 wl_event_source_remove(&source->base);
438 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
440 struct epoll_event ep[32];
441 struct wl_event_source *source;
444 dispatch_idle_sources(loop);
446 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
450 for (i = 0; i < count; i++) {
451 source = ep[i].data.ptr;
452 n += source->interface->dispatch(source, &ep[i]);
456 n = post_dispatch_check(loop);
462 wl_event_loop_get_fd(struct wl_event_loop *loop)
464 return loop->epoll_fd;