1 /*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/epoll.h>
37 #include <sys/signalfd.h>
38 #include <sys/timerfd.h>
39 #include <unistd.h>
40 #include "wayland-util.h"
41 #include "wayland-private.h"
42 #include "wayland-server-core.h"
43 #include "wayland-os.h"
44
45 struct wl_event_loop {
46 int epoll_fd;
47 struct wl_list check_list;
48 struct wl_list idle_list;
49 struct wl_list destroy_list;
50
51 struct wl_signal destroy_signal;
52 };
53
54 struct wl_event_source_interface {
55 int (*dispatch)(struct wl_event_source *source,
56 struct epoll_event *ep);
57 };
58
59 struct wl_event_source {
60 struct wl_event_source_interface *interface;
61 struct wl_event_loop *loop;
62 struct wl_list link;
63 void *data;
64 int fd;
65 };
66
67 struct wl_event_source_fd {
68 struct wl_event_source base;
69 wl_event_loop_fd_func_t func;
70 int fd;
71 };
72
73 static int
wl_event_source_fd_dispatch(struct wl_event_source * source,struct epoll_event * ep)74 wl_event_source_fd_dispatch(struct wl_event_source *source,
75 struct epoll_event *ep)
76 {
77 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
78 uint32_t mask;
79
80 mask = 0;
81 if (ep->events & EPOLLIN)
82 mask |= WL_EVENT_READABLE;
83 if (ep->events & EPOLLOUT)
84 mask |= WL_EVENT_WRITABLE;
85 if (ep->events & EPOLLHUP)
86 mask |= WL_EVENT_HANGUP;
87 if (ep->events & EPOLLERR)
88 mask |= WL_EVENT_ERROR;
89
90 return fd_source->func(fd_source->fd, mask, source->data);
91 }
92
93 struct wl_event_source_interface fd_source_interface = {
94 wl_event_source_fd_dispatch,
95 };
96
97 static struct wl_event_source *
add_source(struct wl_event_loop * loop,struct wl_event_source * source,uint32_t mask,void * data)98 add_source(struct wl_event_loop *loop,
99 struct wl_event_source *source, uint32_t mask, void *data)
100 {
101 struct epoll_event ep;
102
103 if (source->fd < 0) {
104 free(source);
105 return NULL;
106 }
107
108 source->loop = loop;
109 source->data = data;
110 wl_list_init(&source->link);
111
112 memset(&ep, 0, sizeof ep);
113 if (mask & WL_EVENT_READABLE)
114 ep.events |= EPOLLIN;
115 if (mask & WL_EVENT_WRITABLE)
116 ep.events |= EPOLLOUT;
117 ep.data.ptr = source;
118
119 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
120 close(source->fd);
121 free(source);
122 return NULL;
123 }
124
125 return source;
126 }
127
128 WL_EXPORT struct wl_event_source *
wl_event_loop_add_fd(struct wl_event_loop * loop,int fd,uint32_t mask,wl_event_loop_fd_func_t func,void * data)129 wl_event_loop_add_fd(struct wl_event_loop *loop,
130 int fd, uint32_t mask,
131 wl_event_loop_fd_func_t func,
132 void *data)
133 {
134 struct wl_event_source_fd *source;
135
136 source = malloc(sizeof *source);
137 if (source == NULL)
138 return NULL;
139
140 source->base.interface = &fd_source_interface;
141 source->base.fd = wl_os_dupfd_cloexec(fd, 0);
142 source->func = func;
143 source->fd = fd;
144
145 return add_source(loop, &source->base, mask, data);
146 }
147
148 WL_EXPORT int
wl_event_source_fd_update(struct wl_event_source * source,uint32_t mask)149 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
150 {
151 struct wl_event_loop *loop = source->loop;
152 struct epoll_event ep;
153
154 memset(&ep, 0, sizeof ep);
155 if (mask & WL_EVENT_READABLE)
156 ep.events |= EPOLLIN;
157 if (mask & WL_EVENT_WRITABLE)
158 ep.events |= EPOLLOUT;
159 ep.data.ptr = source;
160
161 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
162 }
163
164 struct wl_event_source_timer {
165 struct wl_event_source base;
166 wl_event_loop_timer_func_t func;
167 };
168
169 static int
wl_event_source_timer_dispatch(struct wl_event_source * source,struct epoll_event * ep)170 wl_event_source_timer_dispatch(struct wl_event_source *source,
171 struct epoll_event *ep)
172 {
173 struct wl_event_source_timer *timer_source =
174 (struct wl_event_source_timer *) source;
175 uint64_t expires;
176 int len;
177
178 len = read(source->fd, &expires, sizeof expires);
179 if (!(len == -1 && errno == EAGAIN) && len != sizeof expires)
180 /* Is there anything we can do here? Will this ever happen? */
181 wl_log("timerfd read error: %m\n");
182
183 return timer_source->func(timer_source->base.data);
184 }
185
186 struct wl_event_source_interface timer_source_interface = {
187 wl_event_source_timer_dispatch,
188 };
189
190 WL_EXPORT struct wl_event_source *
wl_event_loop_add_timer(struct wl_event_loop * loop,wl_event_loop_timer_func_t func,void * data)191 wl_event_loop_add_timer(struct wl_event_loop *loop,
192 wl_event_loop_timer_func_t func,
193 void *data)
194 {
195 struct wl_event_source_timer *source;
196
197 source = malloc(sizeof *source);
198 if (source == NULL)
199 return NULL;
200
201 source->base.interface = &timer_source_interface;
202 source->base.fd = timerfd_create(CLOCK_MONOTONIC,
203 TFD_CLOEXEC | TFD_NONBLOCK);
204 source->func = func;
205
206 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
207 }
208
209 WL_EXPORT int
wl_event_source_timer_update(struct wl_event_source * source,int ms_delay)210 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
211 {
212 struct itimerspec its;
213
214 its.it_interval.tv_sec = 0;
215 its.it_interval.tv_nsec = 0;
216 its.it_value.tv_sec = ms_delay / 1000;
217 its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
218 if (timerfd_settime(source->fd, 0, &its, NULL) < 0)
219 return -1;
220
221 return 0;
222 }
223
224 struct wl_event_source_signal {
225 struct wl_event_source base;
226 int signal_number;
227 wl_event_loop_signal_func_t func;
228 };
229
230 static int
wl_event_source_signal_dispatch(struct wl_event_source * source,struct epoll_event * ep)231 wl_event_source_signal_dispatch(struct wl_event_source *source,
232 struct epoll_event *ep)
233 {
234 struct wl_event_source_signal *signal_source =
235 (struct wl_event_source_signal *) source;
236 struct signalfd_siginfo signal_info;
237 int len;
238
239 len = read(source->fd, &signal_info, sizeof signal_info);
240 if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info)
241 /* Is there anything we can do here? Will this ever happen? */
242 wl_log("signalfd read error: %m\n");
243
244 return signal_source->func(signal_source->signal_number,
245 signal_source->base.data);
246 }
247
248 struct wl_event_source_interface signal_source_interface = {
249 wl_event_source_signal_dispatch,
250 };
251
252 WL_EXPORT struct wl_event_source *
wl_event_loop_add_signal(struct wl_event_loop * loop,int signal_number,wl_event_loop_signal_func_t func,void * data)253 wl_event_loop_add_signal(struct wl_event_loop *loop,
254 int signal_number,
255 wl_event_loop_signal_func_t func,
256 void *data)
257 {
258 struct wl_event_source_signal *source;
259 sigset_t mask;
260
261 source = malloc(sizeof *source);
262 if (source == NULL)
263 return NULL;
264
265 source->base.interface = &signal_source_interface;
266 source->signal_number = signal_number;
267
268 sigemptyset(&mask);
269 sigaddset(&mask, signal_number);
270 source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
271 sigprocmask(SIG_BLOCK, &mask, NULL);
272
273 source->func = func;
274
275 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
276 }
277
278 struct wl_event_source_idle {
279 struct wl_event_source base;
280 wl_event_loop_idle_func_t func;
281 };
282
283 struct wl_event_source_interface idle_source_interface = {
284 NULL,
285 };
286
287 WL_EXPORT struct wl_event_source *
wl_event_loop_add_idle(struct wl_event_loop * loop,wl_event_loop_idle_func_t func,void * data)288 wl_event_loop_add_idle(struct wl_event_loop *loop,
289 wl_event_loop_idle_func_t func,
290 void *data)
291 {
292 struct wl_event_source_idle *source;
293
294 source = malloc(sizeof *source);
295 if (source == NULL)
296 return NULL;
297
298 source->base.interface = &idle_source_interface;
299 source->base.loop = loop;
300 source->base.fd = -1;
301
302 source->func = func;
303 source->base.data = data;
304
305 wl_list_insert(loop->idle_list.prev, &source->base.link);
306
307 return &source->base;
308 }
309
310 WL_EXPORT void
wl_event_source_check(struct wl_event_source * source)311 wl_event_source_check(struct wl_event_source *source)
312 {
313 wl_list_insert(source->loop->check_list.prev, &source->link);
314 }
315
316 WL_EXPORT int
wl_event_source_remove(struct wl_event_source * source)317 wl_event_source_remove(struct wl_event_source *source)
318 {
319 struct wl_event_loop *loop = source->loop;
320
321 /* We need to explicitly remove the fd, since closing the fd
322 * isn't enough in case we've dup'ed the fd. */
323 if (source->fd >= 0) {
324 epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
325 close(source->fd);
326 source->fd = -1;
327 }
328
329 wl_list_remove(&source->link);
330 wl_list_insert(&loop->destroy_list, &source->link);
331
332 return 0;
333 }
334
335 static void
wl_event_loop_process_destroy_list(struct wl_event_loop * loop)336 wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
337 {
338 struct wl_event_source *source, *next;
339
340 wl_list_for_each_safe(source, next, &loop->destroy_list, link)
341 free(source);
342
343 wl_list_init(&loop->destroy_list);
344 }
345
346 WL_EXPORT struct wl_event_loop *
wl_event_loop_create(void)347 wl_event_loop_create(void)
348 {
349 struct wl_event_loop *loop;
350
351 loop = malloc(sizeof *loop);
352 if (loop == NULL)
353 return NULL;
354
355 loop->epoll_fd = wl_os_epoll_create_cloexec();
356 if (loop->epoll_fd < 0) {
357 free(loop);
358 return NULL;
359 }
360 wl_list_init(&loop->check_list);
361 wl_list_init(&loop->idle_list);
362 wl_list_init(&loop->destroy_list);
363
364 wl_signal_init(&loop->destroy_signal);
365
366 return loop;
367 }
368
369 WL_EXPORT void
wl_event_loop_destroy(struct wl_event_loop * loop)370 wl_event_loop_destroy(struct wl_event_loop *loop)
371 {
372 wl_signal_emit(&loop->destroy_signal, loop);
373
374 wl_event_loop_process_destroy_list(loop);
375 close(loop->epoll_fd);
376 free(loop);
377 }
378
379 static int
post_dispatch_check(struct wl_event_loop * loop)380 post_dispatch_check(struct wl_event_loop *loop)
381 {
382 struct epoll_event ep;
383 struct wl_event_source *source, *next;
384 int n;
385
386 ep.events = 0;
387 n = 0;
388 wl_list_for_each_safe(source, next, &loop->check_list, link)
389 n += source->interface->dispatch(source, &ep);
390
391 return n;
392 }
393
394 WL_EXPORT void
wl_event_loop_dispatch_idle(struct wl_event_loop * loop)395 wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
396 {
397 struct wl_event_source_idle *source;
398
399 while (!wl_list_empty(&loop->idle_list)) {
400 source = container_of(loop->idle_list.next,
401 struct wl_event_source_idle, base.link);
402 source->func(source->base.data);
403 wl_event_source_remove(&source->base);
404 }
405 }
406
407 WL_EXPORT int
wl_event_loop_dispatch(struct wl_event_loop * loop,int timeout)408 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
409 {
410 struct epoll_event ep[32];
411 struct wl_event_source *source;
412 int i, count, n;
413
414 wl_event_loop_dispatch_idle(loop);
415
416 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
417 if (count < 0)
418 return -1;
419
420 for (i = 0; i < count; i++) {
421 source = ep[i].data.ptr;
422 if (source->fd != -1)
423 source->interface->dispatch(source, &ep[i]);
424 }
425
426 wl_event_loop_process_destroy_list(loop);
427
428 wl_event_loop_dispatch_idle(loop);
429
430 do {
431 n = post_dispatch_check(loop);
432 } while (n > 0);
433
434 return 0;
435 }
436
437 WL_EXPORT int
wl_event_loop_get_fd(struct wl_event_loop * loop)438 wl_event_loop_get_fd(struct wl_event_loop *loop)
439 {
440 return loop->epoll_fd;
441 }
442
443 WL_EXPORT void
wl_event_loop_add_destroy_listener(struct wl_event_loop * loop,struct wl_listener * listener)444 wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
445 struct wl_listener *listener)
446 {
447 wl_signal_add(&loop->destroy_signal, listener);
448 }
449
450 WL_EXPORT struct wl_listener *
wl_event_loop_get_destroy_listener(struct wl_event_loop * loop,wl_notify_func_t notify)451 wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
452 wl_notify_func_t notify)
453 {
454 return wl_signal_get(&loop->destroy_signal, notify);
455 }
456
457