client: Don't forget to init and destroy mutex
[profile/ivi/wayland.git] / src / 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 <fcntl.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/epoll.h>
33 #include <sys/signalfd.h>
34 #include <sys/timerfd.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include "wayland-server.h"
38 #include "wayland-os.h"
39
40 struct wl_event_loop {
41         int epoll_fd;
42         struct wl_list check_list;
43         struct wl_list idle_list;
44         struct wl_list destroy_list;
45 };
46
47 struct wl_event_source_interface {
48         int (*dispatch)(struct wl_event_source *source,
49                         struct epoll_event *ep);
50 };
51
52 struct wl_event_source {
53         struct wl_event_source_interface *interface;
54         struct wl_event_loop *loop;
55         struct wl_list link;
56         void *data;
57         int fd;
58 };
59
60 struct wl_event_source_fd {
61         struct wl_event_source base;
62         wl_event_loop_fd_func_t func;
63         int fd;
64 };
65
66 static int
67 wl_event_source_fd_dispatch(struct wl_event_source *source,
68                             struct epoll_event *ep)
69 {
70         struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
71         uint32_t mask;
72
73         mask = 0;
74         if (ep->events & EPOLLIN)
75                 mask |= WL_EVENT_READABLE;
76         if (ep->events & EPOLLOUT)
77                 mask |= WL_EVENT_WRITABLE;
78         if (ep->events & EPOLLHUP)
79                 mask |= WL_EVENT_HANGUP;
80         if (ep->events & EPOLLERR)
81                 mask |= WL_EVENT_ERROR;
82
83         return fd_source->func(fd_source->fd, mask, source->data);
84 }
85
86 struct wl_event_source_interface fd_source_interface = {
87         wl_event_source_fd_dispatch,
88 };
89
90 static struct wl_event_source *
91 add_source(struct wl_event_loop *loop,
92            struct wl_event_source *source, uint32_t mask, void *data)
93 {
94         struct epoll_event ep;
95
96         if (source->fd < 0) {
97                 fprintf(stderr, "could not add source\n: %m");
98                 free(source);
99                 return NULL;
100         }
101
102         source->loop = loop;
103         source->data = data;
104         wl_list_init(&source->link);
105
106         memset(&ep, 0, sizeof ep);
107         if (mask & WL_EVENT_READABLE)
108                 ep.events |= EPOLLIN;
109         if (mask & WL_EVENT_WRITABLE)
110                 ep.events |= EPOLLOUT;
111         ep.data.ptr = source;
112
113         if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
114                 close(source->fd);
115                 free(source);
116                 return NULL;
117         }
118
119         return source;
120 }
121
122 WL_EXPORT struct wl_event_source *
123 wl_event_loop_add_fd(struct wl_event_loop *loop,
124                      int fd, uint32_t mask,
125                      wl_event_loop_fd_func_t func,
126                      void *data)
127 {
128         struct wl_event_source_fd *source;
129
130         source = malloc(sizeof *source);
131         if (source == NULL)
132                 return NULL;
133
134         source->base.interface = &fd_source_interface;
135         source->base.fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
136         source->func = func;
137         source->fd = fd;
138
139         return add_source(loop, &source->base, mask, data);
140 }
141
142 WL_EXPORT int
143 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
144 {
145         struct wl_event_loop *loop = source->loop;
146         struct epoll_event ep;
147
148         memset(&ep, 0, sizeof ep);
149         if (mask & WL_EVENT_READABLE)
150                 ep.events |= EPOLLIN;
151         if (mask & WL_EVENT_WRITABLE)
152                 ep.events |= EPOLLOUT;
153         ep.data.ptr = source;
154
155         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
156 }
157
158 struct wl_event_source_timer {
159         struct wl_event_source base;
160         wl_event_loop_timer_func_t func;
161 };
162
163 static int
164 wl_event_source_timer_dispatch(struct wl_event_source *source,
165                                struct epoll_event *ep)
166 {
167         struct wl_event_source_timer *timer_source =
168                 (struct wl_event_source_timer *) source;
169         uint64_t expires;
170         int len;
171
172         len = read(source->fd, &expires, sizeof expires);
173         if (len != sizeof expires)
174                 /* Is there anything we can do here?  Will this ever happen? */
175                 fprintf(stderr, "timerfd read error: %m\n");
176
177         return timer_source->func(timer_source->base.data);
178 }
179
180 struct wl_event_source_interface timer_source_interface = {
181         wl_event_source_timer_dispatch,
182 };
183
184 WL_EXPORT struct wl_event_source *
185 wl_event_loop_add_timer(struct wl_event_loop *loop,
186                         wl_event_loop_timer_func_t func,
187                         void *data)
188 {
189         struct wl_event_source_timer *source;
190
191         source = malloc(sizeof *source);
192         if (source == NULL)
193                 return NULL;
194
195         source->base.interface = &timer_source_interface;
196         source->base.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
197         source->func = func;
198
199         return add_source(loop, &source->base, WL_EVENT_READABLE, data);
200 }
201
202 WL_EXPORT int
203 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
204 {
205         struct itimerspec its;
206
207         its.it_interval.tv_sec = 0;
208         its.it_interval.tv_nsec = 0;
209         its.it_value.tv_sec = ms_delay / 1000;
210         its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
211         if (timerfd_settime(source->fd, 0, &its, NULL) < 0) {
212                 fprintf(stderr, "could not set timerfd\n: %m");
213                 return -1;
214         }
215
216         return 0;
217 }
218
219 struct wl_event_source_signal {
220         struct wl_event_source base;
221         int signal_number;
222         wl_event_loop_signal_func_t func;
223 };
224
225 static int
226 wl_event_source_signal_dispatch(struct wl_event_source *source,
227                                struct epoll_event *ep)
228 {
229         struct wl_event_source_signal *signal_source =
230                 (struct wl_event_source_signal *) source;
231         struct signalfd_siginfo signal_info;
232         int len;
233
234         len = read(source->fd, &signal_info, sizeof signal_info);
235         if (len != sizeof signal_info)
236                 /* Is there anything we can do here?  Will this ever happen? */
237                 fprintf(stderr, "signalfd read error: %m\n");
238
239         return signal_source->func(signal_source->signal_number,
240                                    signal_source->base.data);
241 }
242
243 struct wl_event_source_interface signal_source_interface = {
244         wl_event_source_signal_dispatch,
245 };
246
247 WL_EXPORT struct wl_event_source *
248 wl_event_loop_add_signal(struct wl_event_loop *loop,
249                         int signal_number,
250                         wl_event_loop_signal_func_t func,
251                         void *data)
252 {
253         struct wl_event_source_signal *source;
254         sigset_t mask;
255
256         source = malloc(sizeof *source);
257         if (source == NULL)
258                 return NULL;
259
260         source->base.interface = &signal_source_interface;
261         source->signal_number = signal_number;
262
263         sigemptyset(&mask);
264         sigaddset(&mask, signal_number);
265         source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC);
266         sigprocmask(SIG_BLOCK, &mask, NULL);
267
268         source->func = func;
269
270         return add_source(loop, &source->base, WL_EVENT_READABLE, data);
271 }
272
273 struct wl_event_source_idle {
274         struct wl_event_source base;
275         wl_event_loop_idle_func_t func;
276 };
277
278 struct wl_event_source_interface idle_source_interface = {
279         NULL,
280 };
281
282 WL_EXPORT struct wl_event_source *
283 wl_event_loop_add_idle(struct wl_event_loop *loop,
284                        wl_event_loop_idle_func_t func,
285                        void *data)
286 {
287         struct wl_event_source_idle *source;
288
289         source = malloc(sizeof *source);
290         if (source == NULL)
291                 return NULL;
292
293         source->base.interface = &idle_source_interface;
294         source->base.loop = loop;
295         source->base.fd = -1;
296
297         source->func = func;
298         source->base.data = data;
299
300         wl_list_insert(loop->idle_list.prev, &source->base.link);
301
302         return &source->base;
303 }
304
305 WL_EXPORT void
306 wl_event_source_check(struct wl_event_source *source)
307 {
308         wl_list_insert(source->loop->check_list.prev, &source->link);
309 }
310
311 WL_EXPORT int
312 wl_event_source_remove(struct wl_event_source *source)
313 {
314         struct wl_event_loop *loop = source->loop;
315
316         /* We need to explicitly remove the fd, since closing the fd
317          * isn't enough in case we've dup'ed the fd. */
318         if (source->fd >= 0) {
319                 epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
320                 close(source->fd);
321                 source->fd = -1;
322         }
323
324         wl_list_remove(&source->link);
325         wl_list_insert(&loop->destroy_list, &source->link);
326
327         return 0;
328 }
329
330 static void
331 wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
332 {
333         struct wl_event_source *source, *next;
334
335         wl_list_for_each_safe(source, next, &loop->destroy_list, link)
336                 free(source);
337
338         wl_list_init(&loop->destroy_list);
339 }
340
341 WL_EXPORT struct wl_event_loop *
342 wl_event_loop_create(void)
343 {
344         struct wl_event_loop *loop;
345
346         loop = malloc(sizeof *loop);
347         if (loop == NULL)
348                 return NULL;
349
350         loop->epoll_fd = wl_os_epoll_create_cloexec();
351         if (loop->epoll_fd < 0) {
352                 free(loop);
353                 return NULL;
354         }
355         wl_list_init(&loop->check_list);
356         wl_list_init(&loop->idle_list);
357         wl_list_init(&loop->destroy_list);
358
359         return loop;
360 }
361
362 WL_EXPORT void
363 wl_event_loop_destroy(struct wl_event_loop *loop)
364 {
365         wl_event_loop_process_destroy_list(loop);
366         close(loop->epoll_fd);
367         free(loop);
368 }
369
370 static int
371 post_dispatch_check(struct wl_event_loop *loop)
372 {
373         struct epoll_event ep;
374         struct wl_event_source *source, *next;
375         int n;
376
377         ep.events = 0;
378         n = 0;
379         wl_list_for_each_safe(source, next, &loop->check_list, link)
380                 n += source->interface->dispatch(source, &ep);
381
382         return n;
383 }
384
385 WL_EXPORT void
386 wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
387 {
388         struct wl_event_source_idle *source;
389
390         while (!wl_list_empty(&loop->idle_list)) {
391                 source = container_of(loop->idle_list.next,
392                                       struct wl_event_source_idle, base.link);
393                 source->func(source->base.data);
394                 wl_event_source_remove(&source->base);
395         }
396 }
397
398 WL_EXPORT int
399 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
400 {
401         struct epoll_event ep[32];
402         struct wl_event_source *source;
403         int i, count, n;
404
405         wl_event_loop_dispatch_idle(loop);
406
407         count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
408         if (count < 0)
409                 return -1;
410
411         for (i = 0; i < count; i++) {
412                 source = ep[i].data.ptr;
413                 if (source->fd != -1)
414                         source->interface->dispatch(source, &ep[i]);
415         }
416
417         wl_event_loop_process_destroy_list(loop);
418
419         do {
420                 n = post_dispatch_check(loop);
421         } while (n > 0);
422                 
423         return 0;
424 }
425
426 WL_EXPORT int
427 wl_event_loop_get_fd(struct wl_event_loop *loop)
428 {
429         return loop->epoll_fd;
430 }