Move marshal/demarshal buffer into struct wl_closure
[platform/upstream/weston.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-server.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         memset(&ep, 0, sizeof ep);
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         memset(&ep, 0, sizeof 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;
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         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                 free(source);
219                 return NULL;
220         }
221
222         return &source->base;
223 }
224
225 WL_EXPORT int
226 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
227 {
228         struct wl_event_source_timer *timer_source =
229                 (struct wl_event_source_timer *) source;
230         struct itimerspec its;
231
232         its.it_interval.tv_sec = 0;
233         its.it_interval.tv_nsec = 0;
234         its.it_value.tv_sec = 0;
235         its.it_value.tv_nsec = ms_delay * 1000 * 1000;
236         if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
237                 fprintf(stderr, "could not set timerfd\n: %m");
238                 return -1;
239         }
240
241         return 0;
242 }
243
244 struct wl_event_source_signal {
245         struct wl_event_source base;
246         int fd;
247         int signal_number;
248         wl_event_loop_signal_func_t func;
249         void *data;
250 };
251
252 static void
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         signal_source->func(signal_source->signal_number, signal_source->data);
263 }
264
265 static int
266 wl_event_source_signal_remove(struct wl_event_source *source)
267 {
268         struct wl_event_source_signal *signal_source =
269                 (struct wl_event_source_signal *) source;
270         struct wl_event_loop *loop = source->loop;
271         int fd;
272
273         fd = signal_source->fd;
274         free(source);
275
276         return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
277 }
278
279 struct wl_event_source_interface signal_source_interface = {
280         wl_event_source_signal_dispatch,
281         wl_event_source_signal_remove
282 };
283
284 WL_EXPORT struct wl_event_source *
285 wl_event_loop_add_signal(struct wl_event_loop *loop,
286                         int signal_number,
287                         wl_event_loop_signal_func_t func,
288                         void *data)
289 {
290         struct wl_event_source_signal *source;
291         struct epoll_event ep;
292         sigset_t mask;
293
294         source = malloc(sizeof *source);
295         if (source == NULL)
296                 return NULL;
297
298         source->base.interface = &signal_source_interface;
299         source->base.loop = loop;
300
301         sigemptyset(&mask);
302         sigaddset(&mask, signal_number);
303         source->fd = signalfd(-1, &mask, 0);
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->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                 free(source);
320                 return NULL;
321         }
322
323         return &source->base;
324 }
325
326 struct wl_event_source_idle {
327         struct wl_event_source base;
328         struct wl_list link;
329         wl_event_loop_idle_func_t func;
330         void *data;
331 };
332
333 static void
334 wl_event_source_idle_dispatch(struct wl_event_source *source,
335                               struct epoll_event *ep)
336 {
337         assert(0);
338 }
339
340 static int
341 wl_event_source_idle_remove(struct wl_event_source *source)
342 {
343         struct wl_event_source_idle *idle_source =
344                 (struct wl_event_source_idle *) source;
345
346         wl_list_remove(&idle_source->link);
347         free(source);
348
349         return 0;
350 }
351
352 struct wl_event_source_interface idle_source_interface = {
353         wl_event_source_idle_dispatch,
354         wl_event_source_idle_remove
355 };
356
357 WL_EXPORT struct wl_event_source *
358 wl_event_loop_add_idle(struct wl_event_loop *loop,
359                        wl_event_loop_idle_func_t func,
360                        void *data)
361 {
362         struct wl_event_source_idle *source;
363
364         source = malloc(sizeof *source);
365         if (source == NULL)
366                 return NULL;
367
368         source->base.interface = &idle_source_interface;
369         source->base.loop = loop;
370
371         source->func = func;
372         source->data = data;
373         wl_list_insert(loop->idle_list.prev, &source->link);
374
375         return &source->base;
376 }
377
378 WL_EXPORT int
379 wl_event_source_remove(struct wl_event_source *source)
380 {
381         source->interface->remove(source);
382
383         return 0;
384 }
385
386 WL_EXPORT struct wl_event_loop *
387 wl_event_loop_create(void)
388 {
389         struct wl_event_loop *loop;
390
391         loop = malloc(sizeof *loop);
392         if (loop == NULL)
393                 return NULL;
394
395         loop->epoll_fd = epoll_create(16);
396         if (loop->epoll_fd < 0) {
397                 free(loop);
398                 return NULL;
399         }
400         wl_list_init(&loop->idle_list);
401
402         return loop;
403 }
404
405 WL_EXPORT void
406 wl_event_loop_destroy(struct wl_event_loop *loop)
407 {
408         close(loop->epoll_fd);
409         free(loop);
410 }
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 }