Drop libdrm CFLAGS where no longer necessary.
[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
346         return 0;
347 }
348
349 struct wl_event_source_interface idle_source_interface = {
350         wl_event_source_idle_dispatch,
351         wl_event_source_idle_remove
352 };
353
354 WL_EXPORT struct wl_event_source *
355 wl_event_loop_add_idle(struct wl_event_loop *loop,
356                        wl_event_loop_idle_func_t func,
357                        void *data)
358 {
359         struct wl_event_source_idle *source;
360
361         source = malloc(sizeof *source);
362         if (source == NULL)
363                 return NULL;
364
365         source->base.interface = &idle_source_interface;
366         source->base.loop = loop;
367
368         source->func = func;
369         source->data = data;
370         wl_list_insert(loop->idle_list.prev, &source->link);
371
372         return &source->base;
373 }
374
375 WL_EXPORT int
376 wl_event_source_remove(struct wl_event_source *source)
377 {
378         source->interface->remove(source);
379
380         return 0;
381 }
382
383 WL_EXPORT struct wl_event_loop *
384 wl_event_loop_create(void)
385 {
386         struct wl_event_loop *loop;
387
388         loop = malloc(sizeof *loop);
389         if (loop == NULL)
390                 return NULL;
391
392         loop->epoll_fd = epoll_create(16);
393         if (loop->epoll_fd < 0) {
394                 free(loop);
395                 return NULL;
396         }
397         wl_list_init(&loop->idle_list);
398
399         return loop;
400 }
401
402 WL_EXPORT void
403 wl_event_loop_destroy(struct wl_event_loop *loop)
404 {
405         close(loop->epoll_fd);
406         free(loop);
407 }
408
409 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
410
411 static void
412 dispatch_idles(struct wl_event_loop *loop)
413 {
414         struct wl_event_source_idle *source, *next;
415
416         source = container_of(loop->idle_list.next,
417                               struct wl_event_source_idle, link);
418
419         while (&source->link != &loop->idle_list) {
420                 source->func(source->data);
421                 next = container_of(source->link.next,
422                                     struct wl_event_source_idle, link);
423                 free(source);
424                 source = next;
425         }
426
427         wl_list_init(&loop->idle_list);
428 }
429
430 WL_EXPORT int
431 wl_event_loop_wait(struct wl_event_loop *loop)
432 {
433         struct epoll_event ep[32];
434         struct wl_event_source *source;
435         int i, count, timeout;
436
437         if (wl_list_empty(&loop->idle_list))
438                 timeout = -1;
439         else
440                 timeout = 0;
441
442         count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
443         if (count < 0)
444                 return -1;
445
446         for (i = 0; i < count; i++) {
447                 source = ep[i].data.ptr;
448                 source->interface->dispatch(source, &ep[i]);
449         }
450
451         if (count == 0)
452                 dispatch_idles(loop);
453
454         
455         return 0;
456 }