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