mainloop, glib-mainloop: time_restart could cause incorrect event ordering
[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)
332         e->mainloop->cached_next_time_event = NULL;
333
334     if (e->mainloop->cached_next_time_event && e->enabled) {
335         g_assert(e->mainloop->cached_next_time_event->enabled);
336
337         if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
338             e->mainloop->cached_next_time_event = e;
339     }
340 }
341
342 static void glib_time_free(pa_time_event *e) {
343     g_assert(e);
344     g_assert(!e->dead);
345
346     e->dead = 1;
347     e->mainloop->time_events_please_scan++;
348
349     if (e->enabled)
350         e->mainloop->n_enabled_time_events--;
351
352     if (e->mainloop->cached_next_time_event == e)
353         e->mainloop->cached_next_time_event = NULL;
354 }
355
356 static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) {
357     g_assert(e);
358     g_assert(!e->dead);
359
360     e->destroy_callback = cb;
361 }
362
363 /* Deferred sources */
364
365 static pa_defer_event* glib_defer_new(
366         pa_mainloop_api*m,
367         pa_defer_event_cb_t cb,
368         void *userdata) {
369
370     pa_defer_event *e;
371     pa_glib_mainloop *g;
372
373     g_assert(m);
374     g_assert(m->userdata);
375     g_assert(cb);
376
377     g = m->userdata;
378
379     e = pa_xnew(pa_defer_event, 1);
380     e->mainloop = g;
381     e->dead = 0;
382
383     e->enabled = 1;
384     g->n_enabled_defer_events++;
385
386     e->callback = cb;
387     e->userdata = userdata;
388     e->destroy_callback = NULL;
389
390     PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e);
391     return e;
392 }
393
394 static void glib_defer_enable(pa_defer_event *e, int b) {
395     g_assert(e);
396     g_assert(!e->dead);
397
398     if (e->enabled && !b) {
399         g_assert(e->mainloop->n_enabled_defer_events > 0);
400         e->mainloop->n_enabled_defer_events--;
401     } else if (!e->enabled && b)
402         e->mainloop->n_enabled_defer_events++;
403
404     e->enabled = b;
405 }
406
407 static void glib_defer_free(pa_defer_event *e) {
408     g_assert(e);
409     g_assert(!e->dead);
410
411     e->dead = 1;
412     e->mainloop->defer_events_please_scan++;
413
414     if (e->enabled) {
415         g_assert(e->mainloop->n_enabled_defer_events > 0);
416         e->mainloop->n_enabled_defer_events--;
417     }
418 }
419
420 static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) {
421     g_assert(e);
422     g_assert(!e->dead);
423
424     e->destroy_callback = cb;
425 }
426
427 /* quit() */
428
429 static void glib_quit(pa_mainloop_api*a, int retval) {
430
431     g_warning("quit() ignored");
432
433     /* NOOP */
434 }
435
436 static pa_time_event* find_next_time_event(pa_glib_mainloop *g) {
437     pa_time_event *t, *n = NULL;
438     g_assert(g);
439
440     if (g->cached_next_time_event)
441         return g->cached_next_time_event;
442
443     for (t = g->time_events; t; t = t->next) {
444
445         if (t->dead || !t->enabled)
446             continue;
447
448         if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
449             n = t;
450
451             /* Shortcut for tv = { 0, 0 } */
452             if (n->timeval.tv_sec <= 0)
453                 break;
454         }
455     }
456
457     g->cached_next_time_event = n;
458     return n;
459 }
460
461 static void scan_dead(pa_glib_mainloop *g) {
462     g_assert(g);
463
464     if (g->io_events_please_scan)
465         cleanup_io_events(g, 0);
466
467     if (g->time_events_please_scan)
468         cleanup_time_events(g, 0);
469
470     if (g->defer_events_please_scan)
471         cleanup_defer_events(g, 0);
472 }
473
474 static gboolean prepare_func(GSource *source, gint *timeout) {
475     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
476
477     g_assert(g);
478     g_assert(timeout);
479
480     scan_dead(g);
481
482     if (g->n_enabled_defer_events) {
483         *timeout = 0;
484         return TRUE;
485     } else if (g->n_enabled_time_events) {
486         pa_time_event *t;
487         GTimeVal now;
488         struct timeval tvnow;
489         pa_usec_t usec;
490
491         t = find_next_time_event(g);
492         g_assert(t);
493
494         g_get_current_time(&now);
495         tvnow.tv_sec = now.tv_sec;
496         tvnow.tv_usec = now.tv_usec;
497
498         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
499             *timeout = 0;
500             return TRUE;
501         }
502         usec = pa_timeval_diff(&t->timeval, &tvnow);
503         *timeout = (gint) (usec / 1000);
504     } else
505         *timeout = -1;
506
507     return FALSE;
508 }
509 static gboolean check_func(GSource *source) {
510     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
511     pa_io_event *e;
512
513     g_assert(g);
514
515     if (g->n_enabled_defer_events)
516         return TRUE;
517     else if (g->n_enabled_time_events) {
518         pa_time_event *t;
519         GTimeVal now;
520         struct timeval tvnow;
521
522         t = find_next_time_event(g);
523         g_assert(t);
524
525         g_get_current_time(&now);
526         tvnow.tv_sec = now.tv_sec;
527         tvnow.tv_usec = now.tv_usec;
528
529         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0)
530             return TRUE;
531     }
532
533     for (e = g->io_events; e; e = e->next)
534         if (!e->dead && e->poll_fd.revents != 0)
535             return TRUE;
536
537     return FALSE;
538 }
539
540 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
541     pa_glib_mainloop *g = (pa_glib_mainloop*) source;
542     pa_io_event *e;
543
544     g_assert(g);
545
546     if (g->n_enabled_defer_events) {
547         pa_defer_event *d;
548
549         for (d = g->defer_events; d; d = d->next) {
550             if (d->dead || !d->enabled)
551                 continue;
552
553             break;
554         }
555
556         g_assert(d);
557
558         d->callback(&g->api, d, d->userdata);
559         return TRUE;
560     }
561
562     if (g->n_enabled_time_events) {
563         GTimeVal now;
564         struct timeval tvnow;
565         pa_time_event *t;
566
567         t = find_next_time_event(g);
568         g_assert(t);
569
570         g_get_current_time(&now);
571         tvnow.tv_sec = now.tv_sec;
572         tvnow.tv_usec = now.tv_usec;
573
574         if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
575
576             /* Disable time event */
577             glib_time_restart(t, NULL);
578
579             t->callback(&g->api, t, &t->timeval, t->userdata);
580             return TRUE;
581         }
582     }
583
584     for (e = g->io_events; e; e = e->next)
585         if (!e->dead && e->poll_fd.revents != 0) {
586             e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata);
587             e->poll_fd.revents = 0;
588             return TRUE;
589         }
590
591     return FALSE;
592 }
593
594 static const pa_mainloop_api vtable = {
595     .userdata = NULL,
596
597     .io_new = glib_io_new,
598     .io_enable = glib_io_enable,
599     .io_free = glib_io_free,
600     .io_set_destroy= glib_io_set_destroy,
601
602     .time_new = glib_time_new,
603     .time_restart = glib_time_restart,
604     .time_free = glib_time_free,
605     .time_set_destroy = glib_time_set_destroy,
606
607     .defer_new = glib_defer_new,
608     .defer_enable = glib_defer_enable,
609     .defer_free = glib_defer_free,
610     .defer_set_destroy = glib_defer_set_destroy,
611
612     .quit = glib_quit,
613 };
614
615 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {
616     pa_glib_mainloop *g;
617
618     static GSourceFuncs source_funcs = {
619         prepare_func,
620         check_func,
621         dispatch_func,
622         NULL,
623         NULL,
624         NULL
625     };
626
627     g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop));
628     g_main_context_ref(g->context = c ? c : g_main_context_default());
629
630     g->api = vtable;
631     g->api.userdata = g;
632
633     PA_LLIST_HEAD_INIT(pa_io_event, g->io_events);
634     PA_LLIST_HEAD_INIT(pa_time_event, g->time_events);
635     PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events);
636
637     g->n_enabled_defer_events = g->n_enabled_time_events = 0;
638     g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0;
639
640     g->cached_next_time_event = NULL;
641
642     g_source_attach(&g->source, g->context);
643     g_source_set_can_recurse(&g->source, FALSE);
644
645     return g;
646 }
647
648 void pa_glib_mainloop_free(pa_glib_mainloop* g) {
649     g_assert(g);
650
651     cleanup_io_events(g, 1);
652     cleanup_defer_events(g, 1);
653     cleanup_time_events(g, 1);
654
655     g_main_context_unref(g->context);
656     g_source_destroy(&g->source);
657     g_source_unref(&g->source);
658 }
659
660 pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) {
661     g_assert(g);
662
663     return &g->api;
664 }