blob: 8568f4077fca164c9b39aa7852e2380b41a6d629 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
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
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040023#include <stddef.h>
24#include <stdio.h>
25#include <errno.h>
Ray Strodefe573472008-12-19 00:22:18 -050026#include <signal.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040027#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <sys/epoll.h>
Ray Strodefe573472008-12-19 00:22:18 -050032#include <sys/signalfd.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050033#include <sys/timerfd.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040034#include <unistd.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050035#include <assert.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040036#include "wayland.h"
37
38struct wl_event_loop {
39 int epoll_fd;
Kristian Høgsberg4a298902008-11-28 18:35:25 -050040 struct wl_list idle_list;
41};
42
43struct 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);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040047};
48
49struct wl_event_source {
Kristian Høgsberg4a298902008-11-28 18:35:25 -050050 struct wl_event_source_interface *interface;
51 struct wl_event_loop *loop;
52};
53
54struct wl_event_source_fd {
55 struct wl_event_source base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040056 int fd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040057 wl_event_loop_fd_func_t func;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040058 void *data;
59};
60
Kristian Høgsberg4a298902008-11-28 18:35:25 -050061static void
62wl_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
77static int
78wl_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
91struct wl_event_source_interface fd_source_interface = {
92 wl_event_source_fd_dispatch,
93 wl_event_source_fd_remove
94};
95
Kristian Høgsbergb7a01922008-11-08 15:39:41 -050096WL_EXPORT struct wl_event_source *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040097wl_event_loop_add_fd(struct wl_event_loop *loop,
98 int fd, uint32_t mask,
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040099 wl_event_loop_fd_func_t func,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400100 void *data)
101{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500102 struct wl_event_source_fd *source;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400103 struct epoll_event ep;
104
105 source = malloc(sizeof *source);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500106 if (source == NULL)
107 return NULL;
108
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500109 source->base.interface = &fd_source_interface;
110 source->base.loop = loop;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400111 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
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500127 return &source->base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400128}
129
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500130WL_EXPORT int
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500131wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400132{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500133 struct wl_event_source_fd *fd_source =
134 (struct wl_event_source_fd *) source;
135 struct wl_event_loop *loop = source->loop;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400136 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,
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500146 EPOLL_CTL_MOD, fd_source->fd, &ep);
147}
148
149struct 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
156static void
157wl_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
169static int
170wl_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
183struct wl_event_source_interface timer_source_interface = {
184 wl_event_source_timer_dispatch,
185 wl_event_source_timer_remove
186};
187
188WL_EXPORT struct wl_event_source *
189wl_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
224WL_EXPORT int
225wl_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
Ray Strodefe573472008-12-19 00:22:18 -0500243struct 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
251static void
252wl_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
264static int
265wl_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
278struct wl_event_source_interface signal_source_interface = {
279 wl_event_source_signal_dispatch,
280 wl_event_source_signal_remove
281};
282
283WL_EXPORT struct wl_event_source *
284wl_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
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500324struct 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
331static void
332wl_event_source_idle_dispatch(struct wl_event_source *source,
333 struct epoll_event *ep)
334{
335 assert(0);
336}
337
338static int
339wl_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);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400345 free(source);
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500346
347 return 0;
348}
349
350struct wl_event_source_interface idle_source_interface = {
351 wl_event_source_idle_dispatch,
352 wl_event_source_idle_remove
353};
354
355WL_EXPORT struct wl_event_source *
356wl_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
376WL_EXPORT int
377wl_event_source_remove(struct wl_event_source *source)
378{
379 source->interface->remove(source);
380
381 return 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400382}
383
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500384WL_EXPORT struct wl_event_loop *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400385wl_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 }
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500398 wl_list_init(&loop->idle_list);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400399
400 return loop;
401}
402
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500403WL_EXPORT void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400404wl_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
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500412static void
413dispatch_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
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500431WL_EXPORT int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400432wl_event_loop_wait(struct wl_event_loop *loop)
433{
434 struct epoll_event ep[32];
435 struct wl_event_source *source;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400436 int i, count, timeout;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400437
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500438 if (wl_list_empty(&loop->idle_list))
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400439 timeout = -1;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500440 else
441 timeout = 0;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400442
443 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400444 if (count < 0)
445 return -1;
446
447 for (i = 0; i < count; i++) {
448 source = ep[i].data.ptr;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500449 source->interface->dispatch(source, &ep[i]);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400450 }
451
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500452 if (count == 0)
453 dispatch_idles(loop);
454
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400455
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400456 return 0;
457}