8568f4077fca164c9b39aa7852e2380b41a6d629
[profile/ivi/wayland.git] / 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.h"
37
38 struct wl_event_loop {
39         int epoll_fd;
40         struct wl_list idle_list;
41 };
42
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);
47 };
48
49 struct wl_event_source {
50         struct wl_event_source_interface *interface;
51         struct wl_event_loop *loop;
52 };
53
54 struct wl_event_source_fd {
55         struct wl_event_source base;
56         int fd;
57         wl_event_loop_fd_func_t func;
58         void *data;
59 };
60
61 static void
62 wl_event_source_fd_dispatch(struct wl_event_source *source,
63                             struct epoll_event *ep)
64 {
65         struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
66         uint32_t mask;
67
68         mask = 0;
69         if (ep->events & EPOLLIN)
70                 mask |= WL_EVENT_READABLE;
71         if (ep->events & EPOLLOUT)
72                 mask |= WL_EVENT_WRITEABLE;
73
74         fd_source->func(fd_source->fd, mask, fd_source->data);
75 }
76
77 static int
78 wl_event_source_fd_remove(struct wl_event_source *source)
79 {
80         struct wl_event_source_fd *fd_source =
81                 (struct wl_event_source_fd *) source;
82         struct wl_event_loop *loop = source->loop;
83         int fd;
84
85         fd = fd_source->fd;
86         free(source);
87
88         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
89 }
90
91 struct wl_event_source_interface fd_source_interface = {
92         wl_event_source_fd_dispatch,
93         wl_event_source_fd_remove
94 };
95
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,
100                      void *data)
101 {
102         struct wl_event_source_fd *source;
103         struct epoll_event ep;
104
105         source = malloc(sizeof *source);
106         if (source == NULL)
107                 return NULL;
108
109         source->base.interface = &fd_source_interface;
110         source->base.loop = loop;
111         source->fd = fd;
112         source->func = func;
113         source->data = data;
114
115         ep.events = 0;
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;
121
122         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
123                 free(source);
124                 return NULL;
125         }
126
127         return &source->base;
128 }
129
130 WL_EXPORT int
131 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
132 {
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;
137
138         ep.events = 0;
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;
144
145         return epoll_ctl(loop->epoll_fd,
146                          EPOLL_CTL_MOD, fd_source->fd, &ep);
147 }
148
149 struct wl_event_source_timer {
150         struct wl_event_source base;
151         int fd;
152         wl_event_loop_timer_func_t func;
153         void *data;
154 };
155
156 static void
157 wl_event_source_timer_dispatch(struct wl_event_source *source,
158                                struct epoll_event *ep)
159 {
160         struct wl_event_source_timer *timer_source =
161                 (struct wl_event_source_timer *) source;
162         uint64_t expires;
163
164         read(timer_source->fd, &expires, sizeof expires);
165
166         timer_source->func(timer_source->data);
167 }
168
169 static int
170 wl_event_source_timer_remove(struct wl_event_source *source)
171 {
172         struct wl_event_source_timer *timer_source =
173                 (struct wl_event_source_timer *) source;
174         struct wl_event_loop *loop = source->loop;
175         int fd;
176
177         fd = timer_source->fd;
178         free(source);
179
180         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
181 }
182
183 struct wl_event_source_interface timer_source_interface = {
184         wl_event_source_timer_dispatch,
185         wl_event_source_timer_remove
186 };
187
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,
191                         void *data)
192 {
193         struct wl_event_source_timer *source;
194         struct epoll_event ep;
195
196         source = malloc(sizeof *source);
197         if (source == NULL)
198                 return NULL;
199
200         source->base.interface = &timer_source_interface;
201         source->base.loop = loop;
202
203         source->fd = timerfd_create(CLOCK_MONOTONIC, 0);
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->data = data;
212
213         ep.events = EPOLLIN;
214         ep.data.ptr = source;
215
216         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
217                 free(source);
218                 return NULL;
219         }
220
221         return &source->base;
222 }
223
224 WL_EXPORT int
225 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
226 {
227         struct wl_event_source_timer *timer_source =
228                 (struct wl_event_source_timer *) source;
229         struct itimerspec its;
230
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");
237                 return -1;
238         }
239
240         return 0;
241 }
242
243 struct wl_event_source_signal {
244         struct wl_event_source base;
245         int fd;
246         int signal_number;
247         wl_event_loop_signal_func_t func;
248         void *data;
249 };
250
251 static void
252 wl_event_source_signal_dispatch(struct wl_event_source *source,
253                                struct epoll_event *ep)
254 {
255         struct wl_event_source_signal *signal_source =
256                 (struct wl_event_source_signal *) source;
257         struct signalfd_siginfo signal_info;
258
259         read(signal_source->fd, &signal_info, sizeof signal_info);
260
261         signal_source->func(signal_source->signal_number, signal_source->data);
262 }
263
264 static int
265 wl_event_source_signal_remove(struct wl_event_source *source)
266 {
267         struct wl_event_source_signal *signal_source =
268                 (struct wl_event_source_signal *) source;
269         struct wl_event_loop *loop = source->loop;
270         int fd;
271
272         fd = signal_source->fd;
273         free(source);
274
275         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
276 }
277
278 struct wl_event_source_interface signal_source_interface = {
279         wl_event_source_signal_dispatch,
280         wl_event_source_signal_remove
281 };
282
283 WL_EXPORT struct wl_event_source *
284 wl_event_loop_add_signal(struct wl_event_loop *loop,
285                         int signal_number,
286                         wl_event_loop_signal_func_t func,
287                         void *data)
288 {
289         struct wl_event_source_signal *source;
290         struct epoll_event ep;
291         sigset_t mask;
292
293         source = malloc(sizeof *source);
294         if (source == NULL)
295                 return NULL;
296
297         source->base.interface = &signal_source_interface;
298         source->base.loop = loop;
299
300         sigemptyset(&mask);
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");
305                 free(source);
306                 return NULL;
307         }
308         sigprocmask(SIG_BLOCK, &mask, NULL);
309
310         source->func = func;
311         source->data = data;
312
313         ep.events = EPOLLIN;
314         ep.data.ptr = source;
315
316         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
317                 free(source);
318                 return NULL;
319         }
320
321         return &source->base;
322 }
323
324 struct wl_event_source_idle {
325         struct wl_event_source base;
326         struct wl_list link;
327         wl_event_loop_idle_func_t func;
328         void *data;
329 };
330
331 static void
332 wl_event_source_idle_dispatch(struct wl_event_source *source,
333                               struct epoll_event *ep)
334 {
335         assert(0);
336 }
337
338 static int
339 wl_event_source_idle_remove(struct wl_event_source *source)
340 {
341         struct wl_event_source_idle *idle_source =
342                 (struct wl_event_source_idle *) source;
343
344         wl_list_remove(&idle_source->link);
345         free(source);
346
347         return 0;
348 }
349
350 struct wl_event_source_interface idle_source_interface = {
351         wl_event_source_idle_dispatch,
352         wl_event_source_idle_remove
353 };
354
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,
358                        void *data)
359 {
360         struct wl_event_source_idle *source;
361
362         source = malloc(sizeof *source);
363         if (source == NULL)
364                 return NULL;
365
366         source->base.interface = &idle_source_interface;
367         source->base.loop = loop;
368
369         source->func = func;
370         source->data = data;
371         wl_list_insert(loop->idle_list.prev, &source->link);
372
373         return &source->base;
374 }
375
376 WL_EXPORT int
377 wl_event_source_remove(struct wl_event_source *source)
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_create(16);
394         if (loop->epoll_fd < 0) {
395                 free(loop);
396                 return NULL;
397         }
398         wl_list_init(&loop->idle_list);
399
400         return loop;
401 }
402
403 WL_EXPORT void
404 wl_event_loop_destroy(struct wl_event_loop *loop)
405 {
406         close(loop->epoll_fd);
407         free(loop);
408 }
409
410 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
411
412 static void
413 dispatch_idles(struct wl_event_loop *loop)
414 {
415         struct wl_event_source_idle *source, *next;
416
417         source = container_of(loop->idle_list.next,
418                               struct wl_event_source_idle, link);
419
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);
424                 free(source);
425                 source = next;
426         }
427
428         wl_list_init(&loop->idle_list);
429 }
430
431 WL_EXPORT int
432 wl_event_loop_wait(struct wl_event_loop *loop)
433 {
434         struct epoll_event ep[32];
435         struct wl_event_source *source;
436         int i, count, timeout;
437
438         if (wl_list_empty(&loop->idle_list))
439                 timeout = -1;
440         else
441                 timeout = 0;
442
443         count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
444         if (count < 0)
445                 return -1;
446
447         for (i = 0; i < count; i++) {
448                 source = ep[i].data.ptr;
449                 source->interface->dispatch(source, &ep[i]);
450         }
451
452         if (count == 0)
453                 dispatch_idles(loop);
454
455         
456         return 0;
457 }