615ec1d263165425abc6c1f62651ad172acbaf47
[profile/ivi/wayland.git] / wayland / event-loop.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  *
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.
13  *
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
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/epoll.h>
32 #include <sys/signalfd.h>
33 #include <sys/timerfd.h>
34 #include <unistd.h>
35 #include <assert.h>
36 #include "wayland-server.h"
37
38 struct wl_event_loop {
39         int epoll_fd;
40         struct wl_list check_list;
41         struct wl_list idle_list;
42 };
43
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);
48 };
49
50 struct wl_event_source {
51         struct wl_event_source_interface *interface;
52         struct wl_event_loop *loop;
53         struct wl_list link;
54         void *data;
55 };
56
57 struct wl_event_source_fd {
58         struct wl_event_source base;
59         int fd;
60         wl_event_loop_fd_func_t func;
61 };
62
63 static int
64 wl_event_source_fd_dispatch(struct wl_event_source *source,
65                             struct epoll_event *ep)
66 {
67         struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
68         uint32_t mask;
69
70         mask = 0;
71         if (ep->events & EPOLLIN)
72                 mask |= WL_EVENT_READABLE;
73         if (ep->events & EPOLLOUT)
74                 mask |= WL_EVENT_WRITEABLE;
75
76         return fd_source->func(fd_source->fd, mask, fd_source->base.data);
77 }
78
79 static int
80 wl_event_source_fd_remove(struct wl_event_source *source)
81 {
82         struct wl_event_source_fd *fd_source =
83                 (struct wl_event_source_fd *) source;
84         struct wl_event_loop *loop = source->loop;
85         int fd;
86
87         fd = fd_source->fd;
88         free(source);
89
90         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
91 }
92
93 struct wl_event_source_interface fd_source_interface = {
94         wl_event_source_fd_dispatch,
95         wl_event_source_fd_remove
96 };
97
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,
102                      void *data)
103 {
104         struct wl_event_source_fd *source;
105         struct epoll_event ep;
106
107         source = malloc(sizeof *source);
108         if (source == NULL)
109                 return NULL;
110
111         source->base.interface = &fd_source_interface;
112         source->base.loop = loop;
113         wl_list_init(&source->base.link);
114         source->fd = fd;
115         source->func = func;
116         source->base.data = data;
117
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;
124
125         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
126                 free(source);
127                 return NULL;
128         }
129
130         return &source->base;
131 }
132
133 WL_EXPORT int
134 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
135 {
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;
140
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;
147
148         return epoll_ctl(loop->epoll_fd,
149                          EPOLL_CTL_MOD, fd_source->fd, &ep);
150 }
151
152 struct wl_event_source_timer {
153         struct wl_event_source base;
154         int fd;
155         wl_event_loop_timer_func_t func;
156 };
157
158 static int
159 wl_event_source_timer_dispatch(struct wl_event_source *source,
160                                struct epoll_event *ep)
161 {
162         struct wl_event_source_timer *timer_source =
163                 (struct wl_event_source_timer *) source;
164         uint64_t expires;
165
166         read(timer_source->fd, &expires, sizeof expires);
167
168         return timer_source->func(timer_source->base.data);
169 }
170
171 static int
172 wl_event_source_timer_remove(struct wl_event_source *source)
173 {
174         struct wl_event_source_timer *timer_source =
175                 (struct wl_event_source_timer *) source;
176
177         close(timer_source->fd);
178         free(source);
179         return 0;
180 }
181
182 struct wl_event_source_interface timer_source_interface = {
183         wl_event_source_timer_dispatch,
184         wl_event_source_timer_remove
185 };
186
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,
190                         void *data)
191 {
192         struct wl_event_source_timer *source;
193         struct epoll_event ep;
194
195         source = malloc(sizeof *source);
196         if (source == NULL)
197                 return NULL;
198
199         source->base.interface = &timer_source_interface;
200         source->base.loop = loop;
201         wl_list_init(&source->base.link);
202
203         source->fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
204         if (source->fd < 0) {
205                 fprintf(stderr, "could not create timerfd\n: %m");
206                 free(source);
207                 return NULL;
208         }
209
210         source->func = func;
211         source->base.data = data;
212
213         memset(&ep, 0, sizeof ep);
214         ep.events = EPOLLIN;
215         ep.data.ptr = source;
216
217         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
218                 close(source->fd);
219                 free(source);
220                 return NULL;
221         }
222
223         return &source->base;
224 }
225
226 WL_EXPORT int
227 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
228 {
229         struct wl_event_source_timer *timer_source =
230                 (struct wl_event_source_timer *) source;
231         struct itimerspec its;
232
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");
239                 return -1;
240         }
241
242         return 0;
243 }
244
245 struct wl_event_source_signal {
246         struct wl_event_source base;
247         int fd;
248         int signal_number;
249         wl_event_loop_signal_func_t func;
250 };
251
252 static int
253 wl_event_source_signal_dispatch(struct wl_event_source *source,
254                                struct epoll_event *ep)
255 {
256         struct wl_event_source_signal *signal_source =
257                 (struct wl_event_source_signal *) source;
258         struct signalfd_siginfo signal_info;
259
260         read(signal_source->fd, &signal_info, sizeof signal_info);
261
262         return signal_source->func(signal_source->signal_number,
263                                    signal_source->base.data);
264 }
265
266 static int
267 wl_event_source_signal_remove(struct wl_event_source *source)
268 {
269         struct wl_event_source_signal *signal_source =
270                 (struct wl_event_source_signal *) source;
271
272         close(signal_source->fd);
273         free(source);
274         return 0;
275 }
276
277 struct wl_event_source_interface signal_source_interface = {
278         wl_event_source_signal_dispatch,
279         wl_event_source_signal_remove
280 };
281
282 WL_EXPORT struct wl_event_source *
283 wl_event_loop_add_signal(struct wl_event_loop *loop,
284                         int signal_number,
285                         wl_event_loop_signal_func_t func,
286                         void *data)
287 {
288         struct wl_event_source_signal *source;
289         struct epoll_event ep;
290         sigset_t mask;
291
292         source = malloc(sizeof *source);
293         if (source == NULL)
294                 return NULL;
295
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;
300
301         sigemptyset(&mask);
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");
306                 free(source);
307                 return NULL;
308         }
309         sigprocmask(SIG_BLOCK, &mask, NULL);
310
311         source->func = func;
312         source->base.data = data;
313
314         memset(&ep, 0, sizeof ep);
315         ep.events = EPOLLIN;
316         ep.data.ptr = source;
317
318         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
319                 close(source->fd);
320                 free(source);
321                 return NULL;
322         }
323
324         return &source->base;
325 }
326
327 struct wl_event_source_idle {
328         struct wl_event_source base;
329         wl_event_loop_idle_func_t func;
330 };
331
332 static int
333 wl_event_source_idle_remove(struct wl_event_source *source)
334 {
335         free(source);
336
337         return 0;
338 }
339
340 struct wl_event_source_interface idle_source_interface = {
341         NULL,
342         wl_event_source_idle_remove
343 };
344
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,
348                        void *data)
349 {
350         struct wl_event_source_idle *source;
351
352         source = malloc(sizeof *source);
353         if (source == NULL)
354                 return NULL;
355
356         source->base.interface = &idle_source_interface;
357         source->base.loop = loop;
358
359         source->func = func;
360         source->base.data = data;
361
362         wl_list_insert(loop->idle_list.prev, &source->base.link);
363
364         return &source->base;
365 }
366
367 WL_EXPORT void
368 wl_event_source_check(struct wl_event_source *source)
369 {
370         wl_list_insert(source->loop->check_list.prev, &source->link);
371 }
372
373 WL_EXPORT int
374 wl_event_source_remove(struct wl_event_source *source)
375 {
376         if (!wl_list_empty(&source->link))
377                 wl_list_remove(&source->link);
378
379         source->interface->remove(source);
380
381         return 0;
382 }
383
384 WL_EXPORT struct wl_event_loop *
385 wl_event_loop_create(void)
386 {
387         struct wl_event_loop *loop;
388
389         loop = malloc(sizeof *loop);
390         if (loop == NULL)
391                 return NULL;
392
393         loop->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
394         if (loop->epoll_fd < 0) {
395                 free(loop);
396                 return NULL;
397         }
398         wl_list_init(&loop->check_list);
399         wl_list_init(&loop->idle_list);
400
401         return loop;
402 }
403
404 WL_EXPORT void
405 wl_event_loop_destroy(struct wl_event_loop *loop)
406 {
407         close(loop->epoll_fd);
408         free(loop);
409 }
410
411 static int
412 post_dispatch_check(struct wl_event_loop *loop)
413 {
414         struct epoll_event ep;
415         struct wl_event_source *source, *next;
416         int n;
417
418         ep.events = 0;
419         n = 0;
420         wl_list_for_each_safe(source, next, &loop->check_list, link)
421                 n += source->interface->dispatch(source, &ep);
422
423         return n;
424 }
425
426 static void
427 dispatch_idle_sources(struct wl_event_loop *loop)
428 {
429         struct wl_event_source_idle *source, *next;
430
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);
434         }
435 }
436
437 WL_EXPORT int
438 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
439 {
440         struct epoll_event ep[32];
441         struct wl_event_source *source;
442         int i, count, n;
443
444         dispatch_idle_sources(loop);
445
446         count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
447         if (count < 0)
448                 return -1;
449         n = 0;
450         for (i = 0; i < count; i++) {
451                 source = ep[i].data.ptr;
452                 n += source->interface->dispatch(source, &ep[i]);
453         }
454
455         while (n > 0)
456                 n = post_dispatch_check(loop);
457                 
458         return 0;
459 }
460
461 WL_EXPORT int
462 wl_event_loop_get_fd(struct wl_event_loop *loop)
463 {
464         return loop->epoll_fd;
465 }