Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2008 Kristian Hgsberg
      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
     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 *
     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 *
    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
    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
    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 *
    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
    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
    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 *
    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 *
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    438 wl_event_loop_get_fd(struct wl_event_loop *loop)
    439 {
    440 	return loop->epoll_fd;
    441 }
    442 
    443 WL_EXPORT void
    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 *
    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