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>
38 struct wl_event_loop {
40 struct wl_list idle_list;
43 struct wl_event_source_interface {
44 void (*dispatch)(struct wl_event_source *source,
45 struct epoll_event *ep);
46 int (*remove)(struct wl_event_source *source);
49 struct wl_event_source {
50 struct wl_event_source_interface *interface;
51 struct wl_event_loop *loop;
54 struct wl_event_source_fd {
55 struct wl_event_source base;
57 wl_event_loop_fd_func_t func;
62 wl_event_source_fd_dispatch(struct wl_event_source *source,
63 struct epoll_event *ep)
65 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
69 if (ep->events & EPOLLIN)
70 mask |= WL_EVENT_READABLE;
71 if (ep->events & EPOLLOUT)
72 mask |= WL_EVENT_WRITEABLE;
74 fd_source->func(fd_source->fd, mask, fd_source->data);
78 wl_event_source_fd_remove(struct wl_event_source *source)
80 struct wl_event_source_fd *fd_source =
81 (struct wl_event_source_fd *) source;
82 struct wl_event_loop *loop = source->loop;
88 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
91 struct wl_event_source_interface fd_source_interface = {
92 wl_event_source_fd_dispatch,
93 wl_event_source_fd_remove
96 WL_EXPORT struct wl_event_source *
97 wl_event_loop_add_fd(struct wl_event_loop *loop,
98 int fd, uint32_t mask,
99 wl_event_loop_fd_func_t func,
102 struct wl_event_source_fd *source;
103 struct epoll_event ep;
105 source = malloc(sizeof *source);
109 source->base.interface = &fd_source_interface;
110 source->base.loop = loop;
116 if (mask & WL_EVENT_READABLE)
117 ep.events |= EPOLLIN;
118 if (mask & WL_EVENT_WRITEABLE)
119 ep.events |= EPOLLOUT;
120 ep.data.ptr = source;
122 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
127 return &source->base;
131 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
133 struct wl_event_source_fd *fd_source =
134 (struct wl_event_source_fd *) source;
135 struct wl_event_loop *loop = source->loop;
136 struct epoll_event ep;
139 if (mask & WL_EVENT_READABLE)
140 ep.events |= EPOLLIN;
141 if (mask & WL_EVENT_WRITEABLE)
142 ep.events |= EPOLLOUT;
143 ep.data.ptr = source;
145 return epoll_ctl(loop->epoll_fd,
146 EPOLL_CTL_MOD, fd_source->fd, &ep);
149 struct wl_event_source_timer {
150 struct wl_event_source base;
152 wl_event_loop_timer_func_t func;
157 wl_event_source_timer_dispatch(struct wl_event_source *source,
158 struct epoll_event *ep)
160 struct wl_event_source_timer *timer_source =
161 (struct wl_event_source_timer *) source;
164 read(timer_source->fd, &expires, sizeof expires);
166 timer_source->func(timer_source->data);
170 wl_event_source_timer_remove(struct wl_event_source *source)
172 struct wl_event_source_timer *timer_source =
173 (struct wl_event_source_timer *) source;
174 struct wl_event_loop *loop = source->loop;
177 fd = timer_source->fd;
180 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
183 struct wl_event_source_interface timer_source_interface = {
184 wl_event_source_timer_dispatch,
185 wl_event_source_timer_remove
188 WL_EXPORT struct wl_event_source *
189 wl_event_loop_add_timer(struct wl_event_loop *loop,
190 wl_event_loop_timer_func_t func,
193 struct wl_event_source_timer *source;
194 struct epoll_event ep;
196 source = malloc(sizeof *source);
200 source->base.interface = &timer_source_interface;
201 source->base.loop = loop;
203 source->fd = timerfd_create(CLOCK_MONOTONIC, 0);
204 if (source->fd < 0) {
205 fprintf(stderr, "could not create timerfd\n: %m");
214 ep.data.ptr = source;
216 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
221 return &source->base;
225 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
227 struct wl_event_source_timer *timer_source =
228 (struct wl_event_source_timer *) source;
229 struct itimerspec its;
231 its.it_interval.tv_sec = 0;
232 its.it_interval.tv_nsec = 0;
233 its.it_value.tv_sec = 0;
234 its.it_value.tv_nsec = ms_delay * 1000 * 1000;
235 if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
236 fprintf(stderr, "could not set timerfd\n: %m");
243 struct wl_event_source_signal {
244 struct wl_event_source base;
247 wl_event_loop_signal_func_t func;
252 wl_event_source_signal_dispatch(struct wl_event_source *source,
253 struct epoll_event *ep)
255 struct wl_event_source_signal *signal_source =
256 (struct wl_event_source_signal *) source;
257 struct signalfd_siginfo signal_info;
259 read(signal_source->fd, &signal_info, sizeof signal_info);
261 signal_source->func(signal_source->signal_number, signal_source->data);
265 wl_event_source_signal_remove(struct wl_event_source *source)
267 struct wl_event_source_signal *signal_source =
268 (struct wl_event_source_signal *) source;
269 struct wl_event_loop *loop = source->loop;
272 fd = signal_source->fd;
275 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
278 struct wl_event_source_interface signal_source_interface = {
279 wl_event_source_signal_dispatch,
280 wl_event_source_signal_remove
283 WL_EXPORT struct wl_event_source *
284 wl_event_loop_add_signal(struct wl_event_loop *loop,
286 wl_event_loop_signal_func_t func,
289 struct wl_event_source_signal *source;
290 struct epoll_event ep;
293 source = malloc(sizeof *source);
297 source->base.interface = &signal_source_interface;
298 source->base.loop = loop;
301 sigaddset(&mask, signal_number);
302 source->fd = signalfd(-1, &mask, 0);
303 if (source->fd < 0) {
304 fprintf(stderr, "could not create fd to watch signal\n: %m");
308 sigprocmask(SIG_BLOCK, &mask, NULL);
314 ep.data.ptr = source;
316 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
321 return &source->base;
324 struct wl_event_source_idle {
325 struct wl_event_source base;
327 wl_event_loop_idle_func_t func;
332 wl_event_source_idle_dispatch(struct wl_event_source *source,
333 struct epoll_event *ep)
339 wl_event_source_idle_remove(struct wl_event_source *source)
341 struct wl_event_source_idle *idle_source =
342 (struct wl_event_source_idle *) source;
344 wl_list_remove(&idle_source->link);
350 struct wl_event_source_interface idle_source_interface = {
351 wl_event_source_idle_dispatch,
352 wl_event_source_idle_remove
355 WL_EXPORT struct wl_event_source *
356 wl_event_loop_add_idle(struct wl_event_loop *loop,
357 wl_event_loop_idle_func_t func,
360 struct wl_event_source_idle *source;
362 source = malloc(sizeof *source);
366 source->base.interface = &idle_source_interface;
367 source->base.loop = loop;
371 wl_list_insert(loop->idle_list.prev, &source->link);
373 return &source->base;
377 wl_event_source_remove(struct wl_event_source *source)
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_create(16);
394 if (loop->epoll_fd < 0) {
398 wl_list_init(&loop->idle_list);
404 wl_event_loop_destroy(struct wl_event_loop *loop)
406 close(loop->epoll_fd);
410 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
413 dispatch_idles(struct wl_event_loop *loop)
415 struct wl_event_source_idle *source, *next;
417 source = container_of(loop->idle_list.next,
418 struct wl_event_source_idle, link);
420 while (&source->link != &loop->idle_list) {
421 source->func(source->data);
422 next = container_of(source->link.next,
423 struct wl_event_source_idle, link);
428 wl_list_init(&loop->idle_list);
432 wl_event_loop_wait(struct wl_event_loop *loop)
434 struct epoll_event ep[32];
435 struct wl_event_source *source;
436 int i, count, timeout;
438 if (wl_list_empty(&loop->idle_list))
443 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
447 for (i = 0; i < count; i++) {
448 source = ep[i].data.ptr;
449 source->interface->dispatch(source, &ep[i]);
453 dispatch_idles(loop);