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 <stdbool.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <sys/epoll.h>
38 #include <sys/signalfd.h>
39 #include <sys/timerfd.h>
40 #include <unistd.h>
41 #include "wayland-util.h"
42 #include "wayland-private.h"
43 #include "wayland-server-core.h"
44 #include "wayland-os.h"
45
46 /** \cond INTERNAL */
47
48 struct wl_event_loop {
49 int epoll_fd;
50 struct wl_list check_list;
51 struct wl_list idle_list;
52 struct wl_list destroy_list;
53
54 struct wl_signal destroy_signal;
55 };
56
57 struct wl_event_source_interface {
58 int (*dispatch)(struct wl_event_source *source,
59 struct epoll_event *ep);
60 };
61
62 struct wl_event_source {
63 struct wl_event_source_interface *interface;
64 struct wl_event_loop *loop;
65 struct wl_list link;
66 void *data;
67 int fd;
68 };
69
70 struct wl_event_source_fd {
71 struct wl_event_source base;
72 wl_event_loop_fd_func_t func;
73 int fd;
74 };
75
76 /** \endcond */
77
78 static int
wl_event_source_fd_dispatch(struct wl_event_source * source,struct epoll_event * ep)79 wl_event_source_fd_dispatch(struct wl_event_source *source,
80 struct epoll_event *ep)
81 {
82 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
83 uint32_t mask;
84
85 mask = 0;
86 if (ep->events & EPOLLIN)
87 mask |= WL_EVENT_READABLE;
88 if (ep->events & EPOLLOUT)
89 mask |= WL_EVENT_WRITABLE;
90 if (ep->events & EPOLLHUP)
91 mask |= WL_EVENT_HANGUP;
92 if (ep->events & EPOLLERR)
93 mask |= WL_EVENT_ERROR;
94
95 return fd_source->func(fd_source->fd, mask, source->data);
96 }
97
98 struct wl_event_source_interface fd_source_interface = {
99 wl_event_source_fd_dispatch,
100 };
101
102 static struct wl_event_source *
add_source(struct wl_event_loop * loop,struct wl_event_source * source,uint32_t mask,void * data)103 add_source(struct wl_event_loop *loop,
104 struct wl_event_source *source, uint32_t mask, void *data)
105 {
106 struct epoll_event ep;
107
108 if (source->fd < 0) {
109 free(source);
110 return NULL;
111 }
112
113 source->loop = loop;
114 source->data = data;
115 wl_list_init(&source->link);
116
117 memset(&ep, 0, sizeof ep);
118 if (mask & WL_EVENT_READABLE)
119 ep.events |= EPOLLIN;
120 if (mask & WL_EVENT_WRITABLE)
121 ep.events |= EPOLLOUT;
122 ep.data.ptr = source;
123
124 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
125 close(source->fd);
126 free(source);
127 return NULL;
128 }
129
130 return source;
131 }
132
133 /** Create a file descriptor event source
134 *
135 * \param loop The event loop that will process the new source.
136 * \param fd The file descriptor to watch.
137 * \param mask A bitwise-or of which events to watch for: \c WL_EVENT_READABLE,
138 * \c WL_EVENT_WRITABLE.
139 * \param func The file descriptor dispatch function.
140 * \param data User data.
141 * \return A new file descriptor event source.
142 *
143 * The given file descriptor is initially watched for the events given in
144 * \c mask. This can be changed as needed with wl_event_source_fd_update().
145 *
146 * If it is possible that program execution causes the file descriptor to be
147 * read while leaving the data in a buffer without actually processing it,
148 * it may be necessary to register the file descriptor source to be re-checked,
149 * see wl_event_source_check(). This will ensure that the dispatch function
150 * gets called even if the file descriptor is not readable or writable
151 * anymore. This is especially useful with IPC libraries that automatically
152 * buffer incoming data, possibly as a side-effect of other operations.
153 *
154 * \sa wl_event_loop_fd_func_t
155 * \memberof wl_event_source
156 */
157 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)158 wl_event_loop_add_fd(struct wl_event_loop *loop,
159 int fd, uint32_t mask,
160 wl_event_loop_fd_func_t func,
161 void *data)
162 {
163 struct wl_event_source_fd *source;
164
165 source = malloc(sizeof *source);
166 if (source == NULL)
167 return NULL;
168
169 source->base.interface = &fd_source_interface;
170 source->base.fd = wl_os_dupfd_cloexec(fd, 0);
171 source->func = func;
172 source->fd = fd;
173
174 return add_source(loop, &source->base, mask, data);
175 }
176
177 /** Update a file descriptor source's event mask
178 *
179 * \param source The file descriptor event source to update.
180 * \param mask The new mask, a bitwise-or of: \c WL_EVENT_READABLE,
181 * \c WL_EVENT_WRITABLE.
182 * \return 0 on success, -1 on failure.
183 *
184 * This changes which events, readable and/or writable, cause the dispatch
185 * callback to be called on.
186 *
187 * File descriptors are usually writable to begin with, so they do not need to
188 * be polled for writable until a write actually fails. When a write fails,
189 * the event mask can be changed to poll for readable and writable, delivering
190 * a dispatch callback when it is possible to write more. Once all data has
191 * been written, the mask can be changed to poll only for readable to avoid
192 * busy-looping on dispatch.
193 *
194 * \sa wl_event_loop_add_fd()
195 * \memberof wl_event_source
196 */
197 WL_EXPORT int
wl_event_source_fd_update(struct wl_event_source * source,uint32_t mask)198 wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
199 {
200 struct wl_event_loop *loop = source->loop;
201 struct epoll_event ep;
202
203 memset(&ep, 0, sizeof ep);
204 if (mask & WL_EVENT_READABLE)
205 ep.events |= EPOLLIN;
206 if (mask & WL_EVENT_WRITABLE)
207 ep.events |= EPOLLOUT;
208 ep.data.ptr = source;
209
210 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
211 }
212
213 /** \cond INTERNAL */
214
215 struct wl_event_source_timer {
216 struct wl_event_source base;
217 wl_event_loop_timer_func_t func;
218 };
219
220 /** \endcond */
221
222 static int
wl_event_source_timer_dispatch(struct wl_event_source * source,struct epoll_event * ep)223 wl_event_source_timer_dispatch(struct wl_event_source *source,
224 struct epoll_event *ep)
225 {
226 struct wl_event_source_timer *timer_source =
227 (struct wl_event_source_timer *) source;
228 uint64_t expires;
229 int len;
230
231 len = read(source->fd, &expires, sizeof expires);
232 if (!(len == -1 && errno == EAGAIN) && len != sizeof expires)
233 /* Is there anything we can do here? Will this ever happen? */
234 wl_log("timerfd read error: %m\n");
235
236 return timer_source->func(timer_source->base.data);
237 }
238
239 struct wl_event_source_interface timer_source_interface = {
240 wl_event_source_timer_dispatch,
241 };
242
243 /** Create a timer event source
244 *
245 * \param loop The event loop that will process the new source.
246 * \param func The timer dispatch function.
247 * \param data User data.
248 * \return A new timer event source.
249 *
250 * The timer is initially disarmed. It needs to be armed with a call to
251 * wl_event_source_timer_update() before it can trigger a dispatch call.
252 *
253 * \sa wl_event_loop_timer_func_t
254 * \memberof wl_event_source
255 */
256 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)257 wl_event_loop_add_timer(struct wl_event_loop *loop,
258 wl_event_loop_timer_func_t func,
259 void *data)
260 {
261 struct wl_event_source_timer *source;
262
263 source = malloc(sizeof *source);
264 if (source == NULL)
265 return NULL;
266
267 source->base.interface = &timer_source_interface;
268 source->base.fd = timerfd_create(CLOCK_MONOTONIC,
269 TFD_CLOEXEC | TFD_NONBLOCK);
270 source->func = func;
271
272 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
273 }
274
275 /** Arm or disarm a timer
276 *
277 * \param source The timer event source to modify.
278 * \param ms_delay The timeout in milliseconds.
279 * \return 0 on success, -1 on failure.
280 *
281 * If the timeout is zero, the timer is disarmed.
282 *
283 * If the timeout is non-zero, the timer is set to expire after the given
284 * timeout in milliseconds. When the timer expires, the dispatch function
285 * set with wl_event_loop_add_timer() is called once from
286 * wl_event_loop_dispatch(). If another dispatch is desired after another
287 * expiry, wl_event_source_timer_update() needs to be called again.
288 *
289 * \memberof wl_event_source
290 */
291 WL_EXPORT int
wl_event_source_timer_update(struct wl_event_source * source,int ms_delay)292 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
293 {
294 struct itimerspec its;
295
296 its.it_interval.tv_sec = 0;
297 its.it_interval.tv_nsec = 0;
298 its.it_value.tv_sec = ms_delay / 1000;
299 its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
300 if (timerfd_settime(source->fd, 0, &its, NULL) < 0)
301 return -1;
302
303 return 0;
304 }
305
306 /** \cond INTERNAL */
307
308 struct wl_event_source_signal {
309 struct wl_event_source base;
310 int signal_number;
311 wl_event_loop_signal_func_t func;
312 };
313
314 /** \endcond */
315
316 static int
wl_event_source_signal_dispatch(struct wl_event_source * source,struct epoll_event * ep)317 wl_event_source_signal_dispatch(struct wl_event_source *source,
318 struct epoll_event *ep)
319 {
320 struct wl_event_source_signal *signal_source =
321 (struct wl_event_source_signal *) source;
322 struct signalfd_siginfo signal_info;
323 int len;
324
325 len = read(source->fd, &signal_info, sizeof signal_info);
326 if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info)
327 /* Is there anything we can do here? Will this ever happen? */
328 wl_log("signalfd read error: %m\n");
329
330 return signal_source->func(signal_source->signal_number,
331 signal_source->base.data);
332 }
333
334 struct wl_event_source_interface signal_source_interface = {
335 wl_event_source_signal_dispatch,
336 };
337
338 /** Create a POSIX signal event source
339 *
340 * \param loop The event loop that will process the new source.
341 * \param signal_number Number of the signal to watch for.
342 * \param func The signal dispatch function.
343 * \param data User data.
344 * \return A new signal event source.
345 *
346 * This function blocks the normal delivery of the given signal in the calling
347 * thread, and creates a "watch" for it. Signal delivery no longer happens
348 * asynchronously, but by wl_event_loop_dispatch() calling the dispatch
349 * callback function \c func.
350 *
351 * It is the caller's responsibility to ensure that all other threads have
352 * also blocked the signal.
353 *
354 * \sa wl_event_loop_signal_func_t
355 * \memberof wl_event_source
356 */
357 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)358 wl_event_loop_add_signal(struct wl_event_loop *loop,
359 int signal_number,
360 wl_event_loop_signal_func_t func,
361 void *data)
362 {
363 struct wl_event_source_signal *source;
364 sigset_t mask;
365
366 source = malloc(sizeof *source);
367 if (source == NULL)
368 return NULL;
369
370 source->base.interface = &signal_source_interface;
371 source->signal_number = signal_number;
372
373 sigemptyset(&mask);
374 sigaddset(&mask, signal_number);
375 source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
376 sigprocmask(SIG_BLOCK, &mask, NULL);
377
378 source->func = func;
379
380 return add_source(loop, &source->base, WL_EVENT_READABLE, data);
381 }
382
383 /** \cond INTERNAL */
384
385 struct wl_event_source_idle {
386 struct wl_event_source base;
387 wl_event_loop_idle_func_t func;
388 };
389
390 /** \endcond */
391
392 struct wl_event_source_interface idle_source_interface = {
393 NULL,
394 };
395
396 /** Create an idle task
397 *
398 * \param loop The event loop that will process the new task.
399 * \param func The idle task dispatch function.
400 * \param data User data.
401 * \return A new idle task (an event source).
402 *
403 * Idle tasks are dispatched before wl_event_loop_dispatch() goes to sleep.
404 * See wl_event_loop_dispatch() for more details.
405 *
406 * Idle tasks fire once, and are automatically destroyed right after the
407 * callback function has been called.
408 *
409 * An idle task can be cancelled before the callback has been called by
410 * wl_event_source_remove(). Calling wl_event_source_remove() after or from
411 * within the callback results in undefined behaviour.
412 *
413 * \sa wl_event_loop_idle_func_t
414 * \memberof wl_event_source
415 */
416 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)417 wl_event_loop_add_idle(struct wl_event_loop *loop,
418 wl_event_loop_idle_func_t func,
419 void *data)
420 {
421 struct wl_event_source_idle *source;
422
423 source = malloc(sizeof *source);
424 if (source == NULL)
425 return NULL;
426
427 source->base.interface = &idle_source_interface;
428 source->base.loop = loop;
429 source->base.fd = -1;
430
431 source->func = func;
432 source->base.data = data;
433
434 wl_list_insert(loop->idle_list.prev, &source->base.link);
435
436 return &source->base;
437 }
438
439 /** Mark event source to be re-checked
440 *
441 * \param source The event source to be re-checked.
442 *
443 * This function permanently marks the event source to be re-checked after
444 * the normal dispatch of sources in wl_event_loop_dispatch(). Re-checking
445 * will keep iterating over all such event sources until the dispatch
446 * function for them all returns zero.
447 *
448 * Re-checking is used on sources that may become ready to dispatch as a
449 * side-effect of dispatching themselves or other event sources, including idle
450 * sources. Re-checking ensures all the incoming events have been fully drained
451 * before wl_event_loop_dispatch() returns.
452 *
453 * \memberof wl_event_source
454 */
455 WL_EXPORT void
wl_event_source_check(struct wl_event_source * source)456 wl_event_source_check(struct wl_event_source *source)
457 {
458 wl_list_insert(source->loop->check_list.prev, &source->link);
459 }
460
461 /** Remove an event source from its event loop
462 *
463 * \param source The event source to be removed.
464 * \return Zero.
465 *
466 * The event source is removed from the event loop it was created for,
467 * and is effectively destroyed. This invalidates \c source .
468 * The dispatch function of the source will no longer be called through this
469 * source.
470 *
471 * \memberof wl_event_source
472 */
473 WL_EXPORT int
wl_event_source_remove(struct wl_event_source * source)474 wl_event_source_remove(struct wl_event_source *source)
475 {
476 struct wl_event_loop *loop = source->loop;
477
478 /* We need to explicitly remove the fd, since closing the fd
479 * isn't enough in case we've dup'ed the fd. */
480 if (source->fd >= 0) {
481 epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
482 close(source->fd);
483 source->fd = -1;
484 }
485
486 wl_list_remove(&source->link);
487 wl_list_insert(&loop->destroy_list, &source->link);
488
489 return 0;
490 }
491
492 static void
wl_event_loop_process_destroy_list(struct wl_event_loop * loop)493 wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
494 {
495 struct wl_event_source *source, *next;
496
497 wl_list_for_each_safe(source, next, &loop->destroy_list, link)
498 free(source);
499
500 wl_list_init(&loop->destroy_list);
501 }
502
503 /** Create a new event loop context
504 *
505 * \return A new event loop context object.
506 *
507 * This creates a new event loop context. Initially this context is empty.
508 * Event sources need to be explicitly added to it.
509 *
510 * Normally the event loop is run by calling wl_event_loop_dispatch() in
511 * a loop until the program terminates. Alternatively, an event loop can be
512 * embedded in another event loop by its file descriptor, see
513 * wl_event_loop_get_fd().
514 *
515 * \memberof wl_event_loop
516 */
517 WL_EXPORT struct wl_event_loop *
wl_event_loop_create(void)518 wl_event_loop_create(void)
519 {
520 struct wl_event_loop *loop;
521
522 loop = malloc(sizeof *loop);
523 if (loop == NULL)
524 return NULL;
525
526 loop->epoll_fd = wl_os_epoll_create_cloexec();
527 if (loop->epoll_fd < 0) {
528 free(loop);
529 return NULL;
530 }
531 wl_list_init(&loop->check_list);
532 wl_list_init(&loop->idle_list);
533 wl_list_init(&loop->destroy_list);
534
535 wl_signal_init(&loop->destroy_signal);
536
537 return loop;
538 }
539
540 /** Destroy an event loop context
541 *
542 * \param loop The event loop to be destroyed.
543 *
544 * This emits the event loop destroy signal, closes the event loop file
545 * descriptor, and frees \c loop.
546 *
547 * If the event loop has existing sources, those cannot be safely removed
548 * afterwards. Therefore one must call wl_event_source_remove() on all
549 * event sources before destroying the event loop context.
550 *
551 * \memberof wl_event_loop
552 */
553 WL_EXPORT void
wl_event_loop_destroy(struct wl_event_loop * loop)554 wl_event_loop_destroy(struct wl_event_loop *loop)
555 {
556 wl_signal_emit(&loop->destroy_signal, loop);
557
558 wl_event_loop_process_destroy_list(loop);
559 close(loop->epoll_fd);
560 free(loop);
561 }
562
563 static bool
post_dispatch_check(struct wl_event_loop * loop)564 post_dispatch_check(struct wl_event_loop *loop)
565 {
566 struct epoll_event ep;
567 struct wl_event_source *source, *next;
568 bool needs_recheck = false;
569
570 ep.events = 0;
571 wl_list_for_each_safe(source, next, &loop->check_list, link) {
572 int dispatch_result;
573
574 dispatch_result = source->interface->dispatch(source, &ep);
575 if (dispatch_result < 0) {
576 wl_log("Source dispatch function returned negative value!");
577 wl_log("This would previously accidentally suppress a follow-up dispatch");
578 }
579 needs_recheck |= dispatch_result != 0;
580 }
581
582 return needs_recheck;
583 }
584
585 /** Dispatch the idle sources
586 *
587 * \param loop The event loop whose idle sources are dispatched.
588 *
589 * \sa wl_event_loop_add_idle()
590 * \memberof wl_event_loop
591 */
592 WL_EXPORT void
wl_event_loop_dispatch_idle(struct wl_event_loop * loop)593 wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
594 {
595 struct wl_event_source_idle *source;
596
597 while (!wl_list_empty(&loop->idle_list)) {
598 source = container_of(loop->idle_list.next,
599 struct wl_event_source_idle, base.link);
600 source->func(source->base.data);
601 wl_event_source_remove(&source->base);
602 }
603 }
604
605 /** Wait for events and dispatch them
606 *
607 * \param loop The event loop whose sources to wait for.
608 * \param timeout The polling timeout in milliseconds.
609 * \return 0 for success, -1 for polling error.
610 *
611 * All the associated event sources are polled. This function blocks until
612 * any event source delivers an event (idle sources excluded), or the timeout
613 * expires. A timeout of -1 disables the timeout, causing the function to block
614 * indefinitely. A timeout of zero causes the poll to always return immediately.
615 *
616 * All idle sources are dispatched before blocking. An idle source is destroyed
617 * when it is dispatched. After blocking, all other ready sources are
618 * dispatched. Then, idle sources are dispatched again, in case the dispatched
619 * events created idle sources. Finally, all sources marked with
620 * wl_event_source_check() are dispatched in a loop until their dispatch
621 * functions all return zero.
622 *
623 * \memberof wl_event_loop
624 */
625 WL_EXPORT int
wl_event_loop_dispatch(struct wl_event_loop * loop,int timeout)626 wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
627 {
628 struct epoll_event ep[32];
629 struct wl_event_source *source;
630 int i, count;
631
632 wl_event_loop_dispatch_idle(loop);
633
634 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
635 if (count < 0)
636 return -1;
637
638 for (i = 0; i < count; i++) {
639 source = ep[i].data.ptr;
640 if (source->fd != -1)
641 source->interface->dispatch(source, &ep[i]);
642 }
643
644 wl_event_loop_process_destroy_list(loop);
645
646 wl_event_loop_dispatch_idle(loop);
647
648 while (post_dispatch_check(loop));
649
650 return 0;
651 }
652
653 /** Get the event loop file descriptor
654 *
655 * \param loop The event loop context.
656 * \return The aggregate file descriptor.
657 *
658 * This function returns the aggregate file descriptor, that represents all
659 * the event sources (idle sources excluded) associated with the given event
660 * loop context. When any event source makes an event available, it will be
661 * reflected in the aggregate file descriptor.
662 *
663 * When the aggregate file descriptor delivers an event, one can call
664 * wl_event_loop_dispatch() on the event loop context to dispatch all the
665 * available events.
666 *
667 * \memberof wl_event_loop
668 */
669 WL_EXPORT int
wl_event_loop_get_fd(struct wl_event_loop * loop)670 wl_event_loop_get_fd(struct wl_event_loop *loop)
671 {
672 return loop->epoll_fd;
673 }
674
675 /** Register a destroy listener for an event loop context
676 *
677 * \param loop The event loop context whose destruction to listen for.
678 * \param listener The listener with the callback to be called.
679 *
680 * \sa wl_listener
681 * \memberof wl_event_loop
682 */
683 WL_EXPORT void
wl_event_loop_add_destroy_listener(struct wl_event_loop * loop,struct wl_listener * listener)684 wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
685 struct wl_listener *listener)
686 {
687 wl_signal_add(&loop->destroy_signal, listener);
688 }
689
690 /** Get the listener struct for the specified callback
691 *
692 * \param loop The event loop context to inspect.
693 * \param notify The destroy callback to find.
694 * \return The wl_listener registered to the event loop context with
695 * the given callback pointer.
696 *
697 * \memberof wl_event_loop
698 */
699 WL_EXPORT struct wl_listener *
wl_event_loop_get_destroy_listener(struct wl_event_loop * loop,wl_notify_func_t notify)700 wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
701 wl_notify_func_t notify)
702 {
703 return wl_signal_get(&loop->destroy_signal, notify);
704 }
705