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