• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 
31 #ifndef HAVE_PIPE
32 #include <pulsecore/pipe.h>
33 #endif
34 
35 #include <pulse/rtclock.h>
36 #include <pulse/timeval.h>
37 #include <pulse/xmalloc.h>
38 
39 #include <pulsecore/poll.h>
40 #include <pulsecore/core-rtclock.h>
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/i18n.h>
43 #include <pulsecore/llist.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/socket.h>
47 #include <pulsecore/macro.h>
48 
49 #include "mainloop.h"
50 #include "internal.h"
51 
52 struct pa_io_event {
53     pa_mainloop *mainloop;
54     bool dead:1;
55 
56     int fd;
57     pa_io_event_flags_t events;
58     struct pollfd *pollfd;
59 
60     pa_io_event_cb_t callback;
61     void *userdata;
62     pa_io_event_destroy_cb_t destroy_callback;
63 
64     PA_LLIST_FIELDS(pa_io_event);
65 };
66 
67 struct pa_time_event {
68     pa_mainloop *mainloop;
69     bool dead:1;
70 
71     bool enabled:1;
72     bool use_rtclock:1;
73     pa_usec_t time;
74 
75     pa_time_event_cb_t callback;
76     void *userdata;
77     pa_time_event_destroy_cb_t destroy_callback;
78 
79     PA_LLIST_FIELDS(pa_time_event);
80 };
81 
82 struct pa_defer_event {
83     pa_mainloop *mainloop;
84     bool dead:1;
85 
86     bool enabled:1;
87 
88     pa_defer_event_cb_t callback;
89     void *userdata;
90     pa_defer_event_destroy_cb_t destroy_callback;
91 
92     PA_LLIST_FIELDS(pa_defer_event);
93 };
94 
95 struct pa_mainloop {
96     PA_LLIST_HEAD(pa_io_event, io_events);
97     PA_LLIST_HEAD(pa_time_event, time_events);
98     PA_LLIST_HEAD(pa_defer_event, defer_events);
99 
100     unsigned n_enabled_defer_events, n_enabled_time_events, n_io_events;
101     unsigned io_events_please_scan, time_events_please_scan, defer_events_please_scan;
102 
103     bool rebuild_pollfds:1;
104     struct pollfd *pollfds;
105     unsigned max_pollfds, n_pollfds;
106 
107     pa_usec_t prepared_timeout;
108     pa_time_event *cached_next_time_event;
109 
110     pa_mainloop_api api;
111 
112     int retval;
113     bool quit:1;
114 
115     int wakeup_pipe[2];
116     int wakeup_pipe_type;
117 
118     enum {
119         STATE_PASSIVE,
120         STATE_PREPARED,
121         STATE_POLLING,
122         STATE_POLLED,
123         STATE_QUIT
124     } state;
125 
126     pa_poll_func poll_func;
127     void *poll_func_userdata;
128     int poll_func_ret;
129 };
130 
map_flags_to_libc(pa_io_event_flags_t flags)131 static short map_flags_to_libc(pa_io_event_flags_t flags) {
132     return (short)
133         ((flags & PA_IO_EVENT_INPUT ? POLLIN : 0) |
134          (flags & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) |
135          (flags & PA_IO_EVENT_ERROR ? POLLERR : 0) |
136          (flags & PA_IO_EVENT_HANGUP ? POLLHUP : 0));
137 }
138 
map_flags_from_libc(short flags)139 static pa_io_event_flags_t map_flags_from_libc(short flags) {
140     return
141         (flags & POLLIN ? PA_IO_EVENT_INPUT : 0) |
142         (flags & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) |
143         (flags & POLLERR ? PA_IO_EVENT_ERROR : 0) |
144         (flags & POLLHUP ? PA_IO_EVENT_HANGUP : 0);
145 }
146 
147 /* IO events */
mainloop_io_new(pa_mainloop_api * a,int fd,pa_io_event_flags_t events,pa_io_event_cb_t callback,void * userdata)148 static pa_io_event* mainloop_io_new(
149         pa_mainloop_api *a,
150         int fd,
151         pa_io_event_flags_t events,
152         pa_io_event_cb_t callback,
153         void *userdata) {
154 
155     pa_mainloop *m;
156     pa_io_event *e;
157 
158     pa_assert(a);
159     pa_assert(a->userdata);
160     pa_assert(fd >= 0);
161     pa_assert(callback);
162 
163     m = a->userdata;
164     pa_assert(a == &m->api);
165 
166     e = pa_xnew0(pa_io_event, 1);
167     e->mainloop = m;
168 
169     e->fd = fd;
170     e->events = events;
171 
172     e->callback = callback;
173     e->userdata = userdata;
174 
175     PA_LLIST_PREPEND(pa_io_event, m->io_events, e);
176     m->rebuild_pollfds = true;
177     m->n_io_events ++;
178 
179     pa_mainloop_wakeup(m);
180 
181     return e;
182 }
183 
mainloop_io_enable(pa_io_event * e,pa_io_event_flags_t events)184 static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) {
185     pa_assert(e);
186     pa_assert(!e->dead);
187 
188     if (e->events == events)
189         return;
190 
191     e->events = events;
192 
193     if (e->pollfd)
194         e->pollfd->events = map_flags_to_libc(events);
195     else
196         e->mainloop->rebuild_pollfds = true;
197 
198     pa_mainloop_wakeup(e->mainloop);
199 }
200 
mainloop_io_free(pa_io_event * e)201 static void mainloop_io_free(pa_io_event *e) {
202     pa_assert(e);
203     pa_assert(!e->dead);
204 
205     e->dead = true;
206     e->mainloop->io_events_please_scan ++;
207 
208     e->mainloop->n_io_events --;
209     e->mainloop->rebuild_pollfds = true;
210 
211     pa_mainloop_wakeup(e->mainloop);
212 }
213 
mainloop_io_set_destroy(pa_io_event * e,pa_io_event_destroy_cb_t callback)214 static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) {
215     pa_assert(e);
216 
217     e->destroy_callback = callback;
218 }
219 
220 /* Defer events */
mainloop_defer_new(pa_mainloop_api * a,pa_defer_event_cb_t callback,void * userdata)221 static pa_defer_event* mainloop_defer_new(
222         pa_mainloop_api *a,
223         pa_defer_event_cb_t callback,
224         void *userdata) {
225 
226     pa_mainloop *m;
227     pa_defer_event *e;
228 
229     pa_assert(a);
230     pa_assert(a->userdata);
231     pa_assert(callback);
232 
233     m = a->userdata;
234     pa_assert(a == &m->api);
235 
236     e = pa_xnew0(pa_defer_event, 1);
237     e->mainloop = m;
238 
239     e->enabled = true;
240     m->n_enabled_defer_events++;
241 
242     e->callback = callback;
243     e->userdata = userdata;
244 
245     PA_LLIST_PREPEND(pa_defer_event, m->defer_events, e);
246 
247     pa_mainloop_wakeup(e->mainloop);
248 
249     return e;
250 }
251 
mainloop_defer_enable(pa_defer_event * e,int b)252 static void mainloop_defer_enable(pa_defer_event *e, int b) {
253     pa_assert(e);
254     pa_assert(!e->dead);
255 
256     if (e->enabled && !b) {
257         pa_assert(e->mainloop->n_enabled_defer_events > 0);
258         e->mainloop->n_enabled_defer_events--;
259     } else if (!e->enabled && b) {
260         e->mainloop->n_enabled_defer_events++;
261         pa_mainloop_wakeup(e->mainloop);
262     }
263 
264     e->enabled = b;
265 }
266 
mainloop_defer_free(pa_defer_event * e)267 static void mainloop_defer_free(pa_defer_event *e) {
268     pa_assert(e);
269     pa_assert(!e->dead);
270 
271     e->dead = true;
272     e->mainloop->defer_events_please_scan ++;
273 
274     if (e->enabled) {
275         pa_assert(e->mainloop->n_enabled_defer_events > 0);
276         e->mainloop->n_enabled_defer_events--;
277         e->enabled = false;
278     }
279 }
280 
mainloop_defer_set_destroy(pa_defer_event * e,pa_defer_event_destroy_cb_t callback)281 static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) {
282     pa_assert(e);
283     pa_assert(!e->dead);
284 
285     e->destroy_callback = callback;
286 }
287 
288 /* Time events */
make_rt(const struct timeval * tv,bool * use_rtclock)289 static pa_usec_t make_rt(const struct timeval *tv, bool *use_rtclock) {
290     struct timeval ttv;
291 
292     if (!tv) {
293         *use_rtclock = false;
294         return PA_USEC_INVALID;
295     }
296 
297     ttv = *tv;
298     *use_rtclock = !!(ttv.tv_usec & PA_TIMEVAL_RTCLOCK);
299 
300     if (*use_rtclock)
301         ttv.tv_usec &= ~PA_TIMEVAL_RTCLOCK;
302     else
303         pa_rtclock_from_wallclock(&ttv);
304 
305     return pa_timeval_load(&ttv);
306 }
307 
mainloop_time_new(pa_mainloop_api * a,const struct timeval * tv,pa_time_event_cb_t callback,void * userdata)308 static pa_time_event* mainloop_time_new(
309         pa_mainloop_api *a,
310         const struct timeval *tv,
311         pa_time_event_cb_t callback,
312         void *userdata) {
313 
314     pa_mainloop *m;
315     pa_time_event *e;
316     pa_usec_t t;
317     bool use_rtclock = false;
318 
319     pa_assert(a);
320     pa_assert(a->userdata);
321     pa_assert(callback);
322 
323     t = make_rt(tv, &use_rtclock);
324 
325     m = a->userdata;
326     pa_assert(a == &m->api);
327 
328     e = pa_xnew0(pa_time_event, 1);
329     e->mainloop = m;
330 
331     if ((e->enabled = (t != PA_USEC_INVALID))) {
332         e->time = t;
333         e->use_rtclock = use_rtclock;
334 
335         m->n_enabled_time_events++;
336 
337         if (m->cached_next_time_event) {
338             pa_assert(m->cached_next_time_event->enabled);
339 
340             if (t < m->cached_next_time_event->time)
341                 m->cached_next_time_event = e;
342         }
343     }
344 
345     e->callback = callback;
346     e->userdata = userdata;
347 
348     PA_LLIST_PREPEND(pa_time_event, m->time_events, e);
349 
350     if (e->enabled)
351         pa_mainloop_wakeup(m);
352 
353     return e;
354 }
355 
mainloop_time_restart(pa_time_event * e,const struct timeval * tv)356 static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) {
357     bool valid;
358     pa_usec_t t;
359     bool use_rtclock = false;
360 
361     pa_assert(e);
362     pa_assert(!e->dead);
363 
364     t = make_rt(tv, &use_rtclock);
365 
366     valid = (t != PA_USEC_INVALID);
367     if (e->enabled && !valid) {
368         pa_assert(e->mainloop->n_enabled_time_events > 0);
369         e->mainloop->n_enabled_time_events--;
370     } else if (!e->enabled && valid)
371         e->mainloop->n_enabled_time_events++;
372 
373     if ((e->enabled = valid)) {
374         e->time = t;
375         e->use_rtclock = use_rtclock;
376         pa_mainloop_wakeup(e->mainloop);
377     }
378 
379     if (e->mainloop->cached_next_time_event == e)
380         e->mainloop->cached_next_time_event = NULL;
381 
382     if (e->mainloop->cached_next_time_event && e->enabled) {
383         pa_assert(e->mainloop->cached_next_time_event->enabled);
384 
385         if (t < e->mainloop->cached_next_time_event->time)
386             e->mainloop->cached_next_time_event = e;
387     }
388 }
389 
mainloop_time_free(pa_time_event * e)390 static void mainloop_time_free(pa_time_event *e) {
391     pa_assert(e);
392     pa_assert(!e->dead);
393 
394     e->dead = true;
395     e->mainloop->time_events_please_scan ++;
396 
397     if (e->enabled) {
398         pa_assert(e->mainloop->n_enabled_time_events > 0);
399         e->mainloop->n_enabled_time_events--;
400         e->enabled = false;
401     }
402 
403     if (e->mainloop->cached_next_time_event == e)
404         e->mainloop->cached_next_time_event = NULL;
405 
406     /* no wakeup needed here. Think about it! */
407 }
408 
mainloop_time_set_destroy(pa_time_event * e,pa_time_event_destroy_cb_t callback)409 static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) {
410     pa_assert(e);
411     pa_assert(!e->dead);
412 
413     e->destroy_callback = callback;
414 }
415 
416 /* quit() */
417 
mainloop_quit(pa_mainloop_api * a,int retval)418 static void mainloop_quit(pa_mainloop_api *a, int retval) {
419     pa_mainloop *m;
420 
421     pa_assert(a);
422     pa_assert(a->userdata);
423     m = a->userdata;
424     pa_assert(a == &m->api);
425 
426     pa_mainloop_quit(m, retval);
427 }
428 
429 static const pa_mainloop_api vtable = {
430     .userdata = NULL,
431 
432     .io_new = mainloop_io_new,
433     .io_enable = mainloop_io_enable,
434     .io_free = mainloop_io_free,
435     .io_set_destroy = mainloop_io_set_destroy,
436 
437     .time_new = mainloop_time_new,
438     .time_restart = mainloop_time_restart,
439     .time_free = mainloop_time_free,
440     .time_set_destroy = mainloop_time_set_destroy,
441 
442     .defer_new = mainloop_defer_new,
443     .defer_enable = mainloop_defer_enable,
444     .defer_free = mainloop_defer_free,
445     .defer_set_destroy = mainloop_defer_set_destroy,
446 
447     .quit = mainloop_quit,
448 };
449 
pa_mainloop_new(void)450 pa_mainloop *pa_mainloop_new(void) {
451     pa_mainloop *m;
452 
453     pa_init_i18n();
454 
455     m = pa_xnew0(pa_mainloop, 1);
456 
457     if (pa_pipe_cloexec(m->wakeup_pipe) < 0) {
458         pa_log_error("ERROR: cannot create wakeup pipe");
459         pa_xfree(m);
460         return NULL;
461     }
462 
463     pa_make_fd_nonblock(m->wakeup_pipe[0]);
464     pa_make_fd_nonblock(m->wakeup_pipe[1]);
465 
466     m->rebuild_pollfds = true;
467 
468     m->api = vtable;
469     m->api.userdata = m;
470 
471     m->state = STATE_PASSIVE;
472 
473     m->poll_func_ret = -1;
474 
475     return m;
476 }
477 
cleanup_io_events(pa_mainloop * m,bool force)478 static void cleanup_io_events(pa_mainloop *m, bool force) {
479     pa_io_event *e, *n;
480 
481     PA_LLIST_FOREACH_SAFE(e, n, m->io_events) {
482 
483         if (!force && m->io_events_please_scan <= 0)
484             break;
485 
486         if (force || e->dead) {
487             PA_LLIST_REMOVE(pa_io_event, m->io_events, e);
488 
489             if (e->dead) {
490                 pa_assert(m->io_events_please_scan > 0);
491                 m->io_events_please_scan--;
492             }
493 
494             if (e->destroy_callback)
495                 e->destroy_callback(&m->api, e, e->userdata);
496 
497             pa_xfree(e);
498 
499             m->rebuild_pollfds = true;
500         }
501     }
502 
503     pa_assert(m->io_events_please_scan == 0);
504 }
505 
cleanup_time_events(pa_mainloop * m,bool force)506 static void cleanup_time_events(pa_mainloop *m, bool force) {
507     pa_time_event *e, *n;
508 
509     PA_LLIST_FOREACH_SAFE(e, n, m->time_events) {
510 
511         if (!force && m->time_events_please_scan <= 0)
512             break;
513 
514         if (force || e->dead) {
515             PA_LLIST_REMOVE(pa_time_event, m->time_events, e);
516 
517             if (e->dead) {
518                 pa_assert(m->time_events_please_scan > 0);
519                 m->time_events_please_scan--;
520             }
521 
522             if (!e->dead && e->enabled) {
523                 pa_assert(m->n_enabled_time_events > 0);
524                 m->n_enabled_time_events--;
525                 e->enabled = false;
526             }
527 
528             if (e->destroy_callback)
529                 e->destroy_callback(&m->api, e, e->userdata);
530 
531             pa_xfree(e);
532         }
533     }
534 
535     pa_assert(m->time_events_please_scan == 0);
536 }
537 
cleanup_defer_events(pa_mainloop * m,bool force)538 static void cleanup_defer_events(pa_mainloop *m, bool force) {
539     pa_defer_event *e, *n;
540 
541     PA_LLIST_FOREACH_SAFE(e, n, m->defer_events) {
542 
543         if (!force && m->defer_events_please_scan <= 0)
544             break;
545 
546         if (force || e->dead) {
547             PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e);
548 
549             if (e->dead) {
550                 pa_assert(m->defer_events_please_scan > 0);
551                 m->defer_events_please_scan--;
552             }
553 
554             if (!e->dead && e->enabled) {
555                 pa_assert(m->n_enabled_defer_events > 0);
556                 m->n_enabled_defer_events--;
557                 e->enabled = false;
558             }
559 
560             if (e->destroy_callback)
561                 e->destroy_callback(&m->api, e, e->userdata);
562 
563             pa_xfree(e);
564         }
565     }
566 
567     pa_assert(m->defer_events_please_scan == 0);
568 }
569 
pa_mainloop_free(pa_mainloop * m)570 void pa_mainloop_free(pa_mainloop *m) {
571     pa_assert(m);
572 
573     cleanup_io_events(m, true);
574     cleanup_defer_events(m, true);
575     cleanup_time_events(m, true);
576 
577     pa_xfree(m->pollfds);
578 
579     pa_close_pipe(m->wakeup_pipe);
580 
581     pa_xfree(m);
582 }
583 
scan_dead(pa_mainloop * m)584 static void scan_dead(pa_mainloop *m) {
585     pa_assert(m);
586 
587     if (m->io_events_please_scan)
588         cleanup_io_events(m, false);
589 
590     if (m->time_events_please_scan)
591         cleanup_time_events(m, false);
592 
593     if (m->defer_events_please_scan)
594         cleanup_defer_events(m, false);
595 }
596 
rebuild_pollfds(pa_mainloop * m)597 static void rebuild_pollfds(pa_mainloop *m) {
598     pa_io_event*e;
599     struct pollfd *p;
600     unsigned l;
601 
602     l = m->n_io_events + 1;
603     if (m->max_pollfds < l) {
604         l *= 2;
605         m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l);
606         m->max_pollfds = l;
607     }
608 
609     m->n_pollfds = 0;
610     p = m->pollfds;
611 
612     m->pollfds[0].fd = m->wakeup_pipe[0];
613     m->pollfds[0].events = POLLIN;
614     m->pollfds[0].revents = 0;
615     p++;
616     m->n_pollfds++;
617 
618     PA_LLIST_FOREACH(e, m->io_events) {
619         if (e->dead) {
620             e->pollfd = NULL;
621             continue;
622         }
623 
624         e->pollfd = p;
625         p->fd = e->fd;
626         p->events = map_flags_to_libc(e->events);
627         p->revents = 0;
628 
629         p++;
630         m->n_pollfds++;
631     }
632 
633     m->rebuild_pollfds = false;
634 }
635 
dispatch_pollfds(pa_mainloop * m)636 static unsigned dispatch_pollfds(pa_mainloop *m) {
637     pa_io_event *e;
638     unsigned r = 0, k;
639 
640     pa_assert(m->poll_func_ret > 0);
641 
642     k = m->poll_func_ret;
643 
644     PA_LLIST_FOREACH(e, m->io_events) {
645 
646         if (k <= 0 || m->quit)
647             break;
648 
649         if (e->dead || !e->pollfd || !e->pollfd->revents)
650             continue;
651 
652         pa_assert(e->pollfd->fd == e->fd);
653         pa_assert(e->callback);
654 
655         e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata);
656         e->pollfd->revents = 0;
657         r++;
658         k--;
659     }
660 
661     return r;
662 }
663 
dispatch_defer(pa_mainloop * m)664 static unsigned dispatch_defer(pa_mainloop *m) {
665     pa_defer_event *e;
666     unsigned r = 0;
667 
668     if (m->n_enabled_defer_events <= 0)
669         return 0;
670 
671     PA_LLIST_FOREACH(e, m->defer_events) {
672 
673         if (m->quit)
674             break;
675 
676         if (e->dead || !e->enabled)
677             continue;
678 
679         pa_assert(e->callback);
680         e->callback(&m->api, e, e->userdata);
681         r++;
682     }
683 
684     return r;
685 }
686 
find_next_time_event(pa_mainloop * m)687 static pa_time_event* find_next_time_event(pa_mainloop *m) {
688     pa_time_event *t, *n = NULL;
689     pa_assert(m);
690 
691     if (m->cached_next_time_event)
692         return m->cached_next_time_event;
693 
694     PA_LLIST_FOREACH(t, m->time_events) {
695 
696         if (t->dead || !t->enabled)
697             continue;
698 
699         if (!n || t->time < n->time) {
700             n = t;
701 
702             /* Shortcut for time == 0 */
703             if (n->time == 0)
704                 break;
705         }
706     }
707 
708     m->cached_next_time_event = n;
709     return n;
710 }
711 
calc_next_timeout(pa_mainloop * m)712 static pa_usec_t calc_next_timeout(pa_mainloop *m) {
713     pa_time_event *t;
714     pa_usec_t clock_now;
715 
716     if (m->n_enabled_time_events <= 0)
717         return PA_USEC_INVALID;
718 
719     pa_assert_se(t = find_next_time_event(m));
720 
721     if (t->time <= 0)
722         return 0;
723 
724     clock_now = pa_rtclock_now();
725 
726     if (t->time <= clock_now)
727         return 0;
728 
729     return t->time - clock_now;
730 }
731 
dispatch_timeout(pa_mainloop * m)732 static unsigned dispatch_timeout(pa_mainloop *m) {
733     pa_time_event *e;
734     pa_usec_t now;
735     unsigned r = 0;
736     pa_assert(m);
737 
738     if (m->n_enabled_time_events <= 0)
739         return 0;
740 
741     now = pa_rtclock_now();
742 
743     PA_LLIST_FOREACH(e, m->time_events) {
744 
745         if (m->quit)
746             break;
747 
748         if (e->dead || !e->enabled)
749             continue;
750 
751         if (e->time <= now) {
752             struct timeval tv;
753             pa_assert(e->callback);
754 
755             /* Disable time event */
756             mainloop_time_restart(e, NULL);
757 
758             e->callback(&m->api, e, pa_timeval_rtstore(&tv, e->time, e->use_rtclock), e->userdata);
759 
760             r++;
761         }
762     }
763 
764     return r;
765 }
766 
pa_mainloop_wakeup(pa_mainloop * m)767 void pa_mainloop_wakeup(pa_mainloop *m) {
768     char c = 'W';
769     pa_assert(m);
770 
771     if (pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type) < 0)
772         /* Not many options for recovering from the error. Let's at least log something. */
773         pa_log("pa_write() failed while trying to wake up the mainloop: %s", pa_cstrerror(errno));
774 }
775 
clear_wakeup(pa_mainloop * m)776 static void clear_wakeup(pa_mainloop *m) {
777     char c[10];
778 
779     pa_assert(m);
780 
781     while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c))
782         ;
783 }
784 
pa_mainloop_prepare(pa_mainloop * m,int timeout)785 int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
786     pa_assert(m);
787     pa_assert(m->state == STATE_PASSIVE);
788 
789     clear_wakeup(m);
790     scan_dead(m);
791 
792     if (m->quit)
793         goto quit;
794 
795     if (m->n_enabled_defer_events <= 0) {
796 
797         if (m->rebuild_pollfds)
798             rebuild_pollfds(m);
799 
800         m->prepared_timeout = calc_next_timeout(m);
801         if (timeout >= 0) {
802             if (timeout < m->prepared_timeout || m->prepared_timeout == PA_USEC_INVALID)
803                 m->prepared_timeout = timeout;
804         }
805     }
806 
807     m->state = STATE_PREPARED;
808     return 0;
809 
810 quit:
811     m->state = STATE_QUIT;
812     return -2;
813 }
814 
usec_to_timeout(pa_usec_t u)815 static int usec_to_timeout(pa_usec_t u) {
816     int timeout;
817 
818     if (u == PA_USEC_INVALID)
819         return -1;
820 
821     timeout = (u + PA_USEC_PER_MSEC - 1) / PA_USEC_PER_MSEC;
822     pa_assert(timeout >= 0);
823 
824     return timeout;
825 }
826 
pa_mainloop_poll(pa_mainloop * m)827 int pa_mainloop_poll(pa_mainloop *m) {
828     pa_assert(m);
829     pa_assert(m->state == STATE_PREPARED);
830 
831     if (m->quit)
832         goto quit;
833 
834     m->state = STATE_POLLING;
835 
836     if (m->n_enabled_defer_events)
837         m->poll_func_ret = 0;
838     else {
839         pa_assert(!m->rebuild_pollfds);
840 
841         if (m->poll_func)
842             m->poll_func_ret = m->poll_func(
843                     m->pollfds, m->n_pollfds,
844                     usec_to_timeout(m->prepared_timeout),
845                     m->poll_func_userdata);
846         else {
847 #ifdef HAVE_PPOLL
848             struct timespec ts;
849 
850             m->poll_func_ret = ppoll(
851                     m->pollfds, m->n_pollfds,
852                     m->prepared_timeout == PA_USEC_INVALID ? NULL : pa_timespec_store(&ts, m->prepared_timeout),
853                     NULL);
854 #else
855             m->poll_func_ret = pa_poll(
856                     m->pollfds, m->n_pollfds,
857                     usec_to_timeout(m->prepared_timeout));
858 #endif
859         }
860 
861         if (m->poll_func_ret < 0) {
862             if (errno == EINTR)
863                 m->poll_func_ret = 0;
864             else
865                 pa_log("poll(): %s", pa_cstrerror(errno));
866         }
867     }
868 
869     m->state = m->poll_func_ret < 0 ? STATE_PASSIVE : STATE_POLLED;
870     return m->poll_func_ret;
871 
872 quit:
873     m->state = STATE_QUIT;
874     return -2;
875 }
876 
pa_mainloop_dispatch(pa_mainloop * m)877 int pa_mainloop_dispatch(pa_mainloop *m) {
878     unsigned dispatched = 0;
879 
880     pa_assert(m);
881     pa_assert(m->state == STATE_POLLED);
882 
883     if (m->quit)
884         goto quit;
885 
886     if (m->n_enabled_defer_events)
887         dispatched += dispatch_defer(m);
888     else {
889         if (m->n_enabled_time_events)
890             dispatched += dispatch_timeout(m);
891 
892         if (m->quit)
893             goto quit;
894 
895         if (m->poll_func_ret > 0)
896             dispatched += dispatch_pollfds(m);
897     }
898 
899     if (m->quit)
900         goto quit;
901 
902     m->state = STATE_PASSIVE;
903 
904     return (int) dispatched;
905 
906 quit:
907     m->state = STATE_QUIT;
908     return -2;
909 }
910 
pa_mainloop_get_retval(const pa_mainloop * m)911 int pa_mainloop_get_retval(const pa_mainloop *m) {
912     pa_assert(m);
913 
914     return m->retval;
915 }
916 
pa_mainloop_iterate(pa_mainloop * m,int block,int * retval)917 int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
918     int r;
919     pa_assert(m);
920 
921     if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0)
922         goto quit;
923 
924     if ((r = pa_mainloop_poll(m)) < 0)
925         goto quit;
926 
927     if ((r = pa_mainloop_dispatch(m)) < 0)
928         goto quit;
929 
930     return r;
931 
932 quit:
933 
934     if ((r == -2) && retval)
935         *retval = pa_mainloop_get_retval(m);
936     return r;
937 }
938 
pa_mainloop_run(pa_mainloop * m,int * retval)939 int pa_mainloop_run(pa_mainloop *m, int *retval) {
940     int r;
941 
942     while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0)
943         ;
944 
945     if (r == -2)
946         return 1;
947     else
948         return -1;
949 }
950 
pa_mainloop_quit(pa_mainloop * m,int retval)951 void pa_mainloop_quit(pa_mainloop *m, int retval) {
952     pa_assert(m);
953 
954     m->quit = true;
955     m->retval = retval;
956     pa_mainloop_wakeup(m);
957 }
958 
pa_mainloop_get_api(pa_mainloop * m)959 pa_mainloop_api* pa_mainloop_get_api(pa_mainloop *m) {
960     pa_assert(m);
961 
962     return &m->api;
963 }
964 
pa_mainloop_set_poll_func(pa_mainloop * m,pa_poll_func poll_func,void * userdata)965 void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
966     pa_assert(m);
967 
968     m->poll_func = poll_func;
969     m->poll_func_userdata = userdata;
970 }
971 
pa_mainloop_is_our_api(const pa_mainloop_api * m)972 bool pa_mainloop_is_our_api(const pa_mainloop_api *m) {
973     pa_assert(m);
974 
975     return m->io_new == mainloop_io_new;
976 }
977