• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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