• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5 
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10 
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <pulse/xmalloc.h>
25 #include <pulse/timeval.h>
26 
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/log.h>
29 #include <pulsecore/llist.h>
30 
31 #include <glib.h>
32 #include <gdatetime.h>
33 #include "glib-mainloop.h"
34 
35 struct pa_io_event {
36     pa_glib_mainloop *mainloop;
37     int dead;
38 
39     GPollFD poll_fd;
40     int poll_fd_added;
41 
42     pa_io_event_cb_t callback;
43     void *userdata;
44     pa_io_event_destroy_cb_t destroy_callback;
45 
46     PA_LLIST_FIELDS(pa_io_event);
47 };
48 
49 struct pa_time_event {
50     pa_glib_mainloop *mainloop;
51     int dead;
52 
53     int enabled;
54     struct timeval timeval;
55 
56     pa_time_event_cb_t callback;
57     void *userdata;
58     pa_time_event_destroy_cb_t destroy_callback;
59 
60     PA_LLIST_FIELDS(pa_time_event);
61 };
62 
63 struct pa_defer_event {
64     pa_glib_mainloop *mainloop;
65     int dead;
66 
67     int enabled;
68 
69     pa_defer_event_cb_t callback;
70     void *userdata;
71     pa_defer_event_destroy_cb_t destroy_callback;
72 
73     PA_LLIST_FIELDS(pa_defer_event);
74 };
75 
76 struct pa_glib_mainloop {
77     GSource source;
78 
79     pa_mainloop_api api;
80     GMainContext *context;
81 
82     PA_LLIST_HEAD(pa_io_event, io_events);
83     PA_LLIST_HEAD(pa_time_event, time_events);
84     PA_LLIST_HEAD(pa_defer_event, defer_events);
85 
86     int n_enabled_defer_events, n_enabled_time_events;
87     int io_events_please_scan, time_events_please_scan, defer_events_please_scan;
88 
89     pa_time_event *cached_next_time_event;
90 };
91 
cleanup_io_events(pa_glib_mainloop * g,int force)92 static void cleanup_io_events(pa_glib_mainloop *g, int force) {
93     pa_io_event *e;
94 
95     e = g->io_events;
96     while (e) {
97         pa_io_event *n = e->next;
98 
99         if (!force && g->io_events_please_scan <= 0)
100             break;
101 
102         if (force || e->dead) {
103             PA_LLIST_REMOVE(pa_io_event, g->io_events, e);
104 
105             if (e->dead) {
106                 g_assert(g->io_events_please_scan > 0);
107                 g->io_events_please_scan--;
108             }
109 
110             if (e->poll_fd_added)
111                 g_source_remove_poll(&g->source, &e->poll_fd);
112 
113             if (e->destroy_callback)
114                 e->destroy_callback(&g->api, e, e->userdata);
115 
116             pa_xfree(e);
117         }
118 
119         e = n;
120     }
121 
122     g_assert(g->io_events_please_scan == 0);
123 }
124 
cleanup_time_events(pa_glib_mainloop * g,int force)125 static void cleanup_time_events(pa_glib_mainloop *g, int force) {
126     pa_time_event *e;
127 
128     e = g->time_events;
129     while (e) {
130         pa_time_event *n = e->next;
131 
132         if (!force && g->time_events_please_scan <= 0)
133             break;
134 
135         if (force || e->dead) {
136             PA_LLIST_REMOVE(pa_time_event, g->time_events, e);
137 
138             if (e->dead) {
139                 g_assert(g->time_events_please_scan > 0);
140                 g->time_events_please_scan--;
141             }
142 
143             if (!e->dead && e->enabled) {
144                 g_assert(g->n_enabled_time_events > 0);
145                 g->n_enabled_time_events--;
146             }
147 
148             if (e->destroy_callback)
149                 e->destroy_callback(&g->api, e, e->userdata);
150 
151             pa_xfree(e);
152         }
153 
154         e = n;
155     }
156 
157     g_assert(g->time_events_please_scan == 0);
158 }
159 
cleanup_defer_events(pa_glib_mainloop * g,int force)160 static void cleanup_defer_events(pa_glib_mainloop *g, int force) {
161     pa_defer_event *e;
162 
163     e = g->defer_events;
164     while (e) {
165         pa_defer_event *n = e->next;
166 
167         if (!force && g->defer_events_please_scan <= 0)
168             break;
169 
170         if (force || e->dead) {
171             PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e);
172 
173             if (e->dead) {
174                 g_assert(g->defer_events_please_scan > 0);
175                 g->defer_events_please_scan--;
176             }
177 
178             if (!e->dead && e->enabled) {
179                 g_assert(g->n_enabled_defer_events > 0);
180                 g->n_enabled_defer_events--;
181             }
182 
183             if (e->destroy_callback)
184                 e->destroy_callback(&g->api, e, e->userdata);
185 
186             pa_xfree(e);
187         }
188 
189         e = n;
190     }
191 
192     g_assert(g->defer_events_please_scan == 0);
193 }
194 
map_flags_to_glib(pa_io_event_flags_t flags)195 static gushort map_flags_to_glib(pa_io_event_flags_t flags) {
196     return (gushort)
197         ((flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) |
198          (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) |
199          (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) |
200          (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0));
201 }
202 
map_flags_from_glib(gushort flags)203 static pa_io_event_flags_t map_flags_from_glib(gushort flags) {
204     return
205         (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) |
206         (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) |
207         (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) |
208         (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0);
209 }
210 
glib_io_new(pa_mainloop_api * m,int fd,pa_io_event_flags_t f,pa_io_event_cb_t cb,void * userdata)211 static pa_io_event* glib_io_new(
212         pa_mainloop_api*m,
213         int fd,
214         pa_io_event_flags_t f,
215         pa_io_event_cb_t cb,
216         void *userdata) {
217 
218     pa_io_event *e;
219     pa_glib_mainloop *g;
220 
221     g_assert(m);
222     g_assert(m->userdata);
223     g_assert(fd >= 0);
224     g_assert(cb);
225 
226     g = m->userdata;
227 
228     e = pa_xnew(pa_io_event, 1);
229     e->mainloop = g;
230     e->dead = 0;
231 
232     e->poll_fd.fd = fd;
233     e->poll_fd.events = map_flags_to_glib(f);
234     e->poll_fd.revents = 0;
235 
236     e->callback = cb;
237     e->userdata = userdata;
238     e->destroy_callback = NULL;
239 
240     PA_LLIST_PREPEND(pa_io_event, g->io_events, e);
241 
242     g_source_add_poll(&g->source, &e->poll_fd);
243     e->poll_fd_added = 1;
244 
245     return e;
246 }
247 
glib_io_enable(pa_io_event * e,pa_io_event_flags_t f)248 static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) {
249     g_assert(e);
250     g_assert(!e->dead);
251 
252     e->poll_fd.events = map_flags_to_glib(f);
253 }
254 
glib_io_free(pa_io_event * e)255 static void glib_io_free(pa_io_event*e) {
256     g_assert(e);
257     g_assert(!e->dead);
258 
259     e->dead = 1;
260     e->mainloop->io_events_please_scan++;
261 
262     if (e->poll_fd_added) {
263         g_source_remove_poll(&e->mainloop->source, &e->poll_fd);
264         e->poll_fd_added = 0;
265     }
266 }
267 
glib_io_set_destroy(pa_io_event * e,pa_io_event_destroy_cb_t cb)268 static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) {
269     g_assert(e);
270     g_assert(!e->dead);
271 
272     e->destroy_callback = cb;
273 }
274 
275 /* Time sources */
276 
glib_time_new(pa_mainloop_api * m,const struct timeval * tv,pa_time_event_cb_t cb,void * userdata)277 static pa_time_event* glib_time_new(
278         pa_mainloop_api*m,
279         const struct timeval *tv,
280         pa_time_event_cb_t cb,
281         void *userdata) {
282 
283     pa_glib_mainloop *g;
284     pa_time_event *e;
285 
286     g_assert(m);
287     g_assert(m->userdata);
288     g_assert(cb);
289 
290     g = m->userdata;
291 
292     e = pa_xnew(pa_time_event, 1);
293     e->mainloop = g;
294     e->dead = 0;
295 
296     if ((e->enabled = !!tv)) {
297         e->timeval = *tv;
298         g->n_enabled_time_events++;
299 
300         if (g->cached_next_time_event) {
301             g_assert(g->cached_next_time_event->enabled);
302 
303             if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0)
304                 g->cached_next_time_event = e;
305         }
306     }
307 
308     e->callback = cb;
309     e->userdata = userdata;
310     e->destroy_callback = NULL;
311 
312     PA_LLIST_PREPEND(pa_time_event, g->time_events, e);
313 
314     return e;
315 }
316 
glib_time_restart(pa_time_event * e,const struct timeval * tv)317 static void glib_time_restart(pa_time_event*e, const struct timeval *tv) {
318     g_assert(e);
319     g_assert(!e->dead);
320 
321     if (e->enabled && !tv) {
322         g_assert(e->mainloop->n_enabled_time_events > 0);
323         e->mainloop->n_enabled_time_events--;
324     } else if (!e->enabled && tv)
325         e->mainloop->n_enabled_time_events++;
326 
327     if ((e->enabled = !!tv))
328         e->timeval = *tv;
329 
330     if (e->mainloop->cached_next_time_event == e)
331         e->mainloop->cached_next_time_event = NULL;
332 
333     if (e->mainloop->cached_next_time_event && e->enabled) {
334         g_assert(e->mainloop->cached_next_time_event->enabled);
335 
336         if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
337             e->mainloop->cached_next_time_event = e;
338     }
339 }
340 
glib_time_free(pa_time_event * e)341 static void glib_time_free(pa_time_event *e) {
342     g_assert(e);
343     g_assert(!e->dead);
344 
345     e->dead = 1;
346     e->mainloop->time_events_please_scan++;
347 
348     if (e->enabled)
349         e->mainloop->n_enabled_time_events--;
350 
351     if (e->mainloop->cached_next_time_event == e)
352         e->mainloop->cached_next_time_event = NULL;
353 }
354 
glib_time_set_destroy(pa_time_event * e,pa_time_event_destroy_cb_t cb)355 static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) {
356     g_assert(e);
357     g_assert(!e->dead);
358 
359     e->destroy_callback = cb;
360 }
361 
362 /* Deferred sources */
363 
glib_defer_new(pa_mainloop_api * m,pa_defer_event_cb_t cb,void * userdata)364 static pa_defer_event* glib_defer_new(
365         pa_mainloop_api*m,
366         pa_defer_event_cb_t cb,
367         void *userdata) {
368 
369     pa_defer_event *e;
370     pa_glib_mainloop *g;
371 
372     g_assert(m);
373     g_assert(m->userdata);
374     g_assert(cb);
375 
376     g = m->userdata;
377 
378     e = pa_xnew(pa_defer_event, 1);
379     e->mainloop = g;
380     e->dead = 0;
381 
382     e->enabled = 1;
383     g->n_enabled_defer_events++;
384 
385     e->callback = cb;
386     e->userdata = userdata;
387     e->destroy_callback = NULL;
388 
389     PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e);
390     return e;
391 }
392 
glib_defer_enable(pa_defer_event * e,int b)393 static void glib_defer_enable(pa_defer_event *e, int b) {
394     g_assert(e);
395     g_assert(!e->dead);
396 
397     if (e->enabled && !b) {
398         g_assert(e->mainloop->n_enabled_defer_events > 0);
399         e->mainloop->n_enabled_defer_events--;
400     } else if (!e->enabled && b)
401         e->mainloop->n_enabled_defer_events++;
402 
403     e->enabled = b;
404 }
405 
glib_defer_free(pa_defer_event * e)406 static void glib_defer_free(pa_defer_event *e) {
407     g_assert(e);
408     g_assert(!e->dead);
409 
410     e->dead = 1;
411     e->mainloop->defer_events_please_scan++;
412 
413     if (e->enabled) {
414         g_assert(e->mainloop->n_enabled_defer_events > 0);
415         e->mainloop->n_enabled_defer_events--;
416     }
417 }
418 
glib_defer_set_destroy(pa_defer_event * e,pa_defer_event_destroy_cb_t cb)419 static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) {
420     g_assert(e);
421     g_assert(!e->dead);
422 
423     e->destroy_callback = cb;
424 }
425 
426 /* quit() */
427 
glib_quit(pa_mainloop_api * a,int retval)428 static void glib_quit(pa_mainloop_api*a, int retval) {
429 
430     g_warning("quit() ignored");
431 
432     /* NOOP */
433 }
434 
find_next_time_event(pa_glib_mainloop * g)435 static pa_time_event* find_next_time_event(pa_glib_mainloop *g) {
436     pa_time_event *t, *n = NULL;
437     g_assert(g);
438 
439     if (g->cached_next_time_event)
440         return g->cached_next_time_event;
441 
442     for (t = g->time_events; t; t = t->next) {
443 
444         if (t->dead || !t->enabled)
445             continue;
446 
447         if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
448             n = t;
449 
450             /* Shortcut for tv = { 0, 0 } */
451             if (n->timeval.tv_sec <= 0)
452                 break;
453         }
454     }
455 
456     g->cached_next_time_event = n;
457     return n;
458 }
459 
scan_dead(pa_glib_mainloop * g)460 static void scan_dead(pa_glib_mainloop *g) {
461     g_assert(g);
462 
463     if (g->io_events_please_scan)
464         cleanup_io_events(g, 0);
465 
466     if (g->time_events_please_scan)
467         cleanup_time_events(g, 0);
468 
469     if (g->defer_events_please_scan)
470         cleanup_defer_events(g, 0);
471 }
472 
prepare_func(GSource * source,gint * timeout)473 static gboolean prepare_func(GSource *source, gint *timeout) {
474     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
475 
476     g_assert(g);
477     g_assert(timeout);
478 
479     scan_dead(g);
480 
481     if (g->n_enabled_defer_events) {
482         *timeout = 0;
483         return TRUE;
484     } else if (g->n_enabled_time_events) {
485         pa_time_event *t;
486         gint64 now;
487         struct timeval tvnow;
488         pa_usec_t usec;
489 
490         t = find_next_time_event(g);
491         g_assert(t);
492 
493         now = g_get_real_time();
494         tvnow.tv_sec = now / 1000000;
495         tvnow.tv_usec = now % 1000000;
496 
497         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
498             *timeout = 0;
499             return TRUE;
500         }
501         usec = pa_timeval_diff(&t->timeval, &tvnow);
502         *timeout = (gint) (usec / 1000);
503     } else
504         *timeout = -1;
505 
506     return FALSE;
507 }
check_func(GSource * source)508 static gboolean check_func(GSource *source) {
509     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
510     pa_io_event *e;
511 
512     g_assert(g);
513 
514     if (g->n_enabled_defer_events)
515         return TRUE;
516     else if (g->n_enabled_time_events) {
517         pa_time_event *t;
518         gint64 now;
519         struct timeval tvnow;
520 
521         t = find_next_time_event(g);
522         g_assert(t);
523         now = g_get_real_time();
524         tvnow.tv_sec = now / 1000000;
525         tvnow.tv_usec = now % 1000000;
526 
527         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0)
528             return TRUE;
529     }
530 
531     for (e = g->io_events; e; e = e->next)
532         if (!e->dead && e->poll_fd.revents != 0)
533             return TRUE;
534 
535     return FALSE;
536 }
537 
dispatch_func(GSource * source,GSourceFunc callback,gpointer userdata)538 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
539     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
540     pa_io_event *e;
541 
542     g_assert(g);
543 
544     if (g->n_enabled_defer_events) {
545         pa_defer_event *d;
546 
547         for (d = g->defer_events; d; d = d->next) {
548             if (d->dead || !d->enabled)
549                 continue;
550 
551             break;
552         }
553 
554         g_assert(d);
555 
556         d->callback(&g->api, d, d->userdata);
557         return TRUE;
558     }
559 
560     if (g->n_enabled_time_events) {
561         gint64 now;
562         struct timeval tvnow;
563         pa_time_event *t;
564 
565         t = find_next_time_event(g);
566         g_assert(t);
567         now = g_get_real_time();
568         tvnow.tv_sec = now / 1000000;
569         tvnow.tv_usec = now % 1000000;
570 
571         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
572 
573             /* Disable time event */
574             glib_time_restart(t, NULL);
575 
576             t->callback(&g->api, t, &t->timeval, t->userdata);
577             return TRUE;
578         }
579     }
580 
581     for (e = g->io_events; e; e = e->next)
582         if (!e->dead && e->poll_fd.revents != 0) {
583             e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata);
584             e->poll_fd.revents = 0;
585             return TRUE;
586         }
587 
588     return FALSE;
589 }
590 
591 static const pa_mainloop_api vtable = {
592     .userdata = NULL,
593 
594     .io_new = glib_io_new,
595     .io_enable = glib_io_enable,
596     .io_free = glib_io_free,
597     .io_set_destroy = glib_io_set_destroy,
598 
599     .time_new = glib_time_new,
600     .time_restart = glib_time_restart,
601     .time_free = glib_time_free,
602     .time_set_destroy = glib_time_set_destroy,
603 
604     .defer_new = glib_defer_new,
605     .defer_enable = glib_defer_enable,
606     .defer_free = glib_defer_free,
607     .defer_set_destroy = glib_defer_set_destroy,
608 
609     .quit = glib_quit,
610 };
611 
pa_glib_mainloop_new(GMainContext * c)612 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {
613     pa_glib_mainloop *g;
614 
615     static GSourceFuncs source_funcs = {
616         prepare_func,
617         check_func,
618         dispatch_func,
619         NULL,
620         NULL,
621         NULL
622     };
623 
624     g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop));
625     g_main_context_ref(g->context = c ? c : g_main_context_default());
626 
627     g->api = vtable;
628     g->api.userdata = g;
629 
630     PA_LLIST_HEAD_INIT(pa_io_event, g->io_events);
631     PA_LLIST_HEAD_INIT(pa_time_event, g->time_events);
632     PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events);
633 
634     g->n_enabled_defer_events = g->n_enabled_time_events = 0;
635     g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0;
636 
637     g->cached_next_time_event = NULL;
638 
639     g_source_attach(&g->source, g->context);
640     g_source_set_can_recurse(&g->source, FALSE);
641 
642     return g;
643 }
644 
pa_glib_mainloop_free(pa_glib_mainloop * g)645 void pa_glib_mainloop_free(pa_glib_mainloop* g) {
646     g_assert(g);
647 
648     cleanup_io_events(g, 1);
649     cleanup_defer_events(g, 1);
650     cleanup_time_events(g, 1);
651 
652     g_main_context_unref(g->context);
653     g_source_destroy(&g->source);
654     g_source_unref(&g->source);
655 }
656 
pa_glib_mainloop_get_api(pa_glib_mainloop * g)657 pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) {
658     g_assert(g);
659 
660     return &g->api;
661 }
662