• 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 <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