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 "glib-mainloop.h"
33
34 struct pa_io_event {
35 pa_glib_mainloop *mainloop;
36 int dead;
37
38 GPollFD poll_fd;
39 int poll_fd_added;
40
41 pa_io_event_cb_t callback;
42 void *userdata;
43 pa_io_event_destroy_cb_t destroy_callback;
44
45 PA_LLIST_FIELDS(pa_io_event);
46 };
47
48 struct pa_time_event {
49 pa_glib_mainloop *mainloop;
50 int dead;
51
52 int enabled;
53 struct timeval timeval;
54
55 pa_time_event_cb_t callback;
56 void *userdata;
57 pa_time_event_destroy_cb_t destroy_callback;
58
59 PA_LLIST_FIELDS(pa_time_event);
60 };
61
62 struct pa_defer_event {
63 pa_glib_mainloop *mainloop;
64 int dead;
65
66 int enabled;
67
68 pa_defer_event_cb_t callback;
69 void *userdata;
70 pa_defer_event_destroy_cb_t destroy_callback;
71
72 PA_LLIST_FIELDS(pa_defer_event);
73 };
74
75 struct pa_glib_mainloop {
76 GSource source;
77
78 pa_mainloop_api api;
79 GMainContext *context;
80
81 PA_LLIST_HEAD(pa_io_event, io_events);
82 PA_LLIST_HEAD(pa_time_event, time_events);
83 PA_LLIST_HEAD(pa_defer_event, defer_events);
84
85 int n_enabled_defer_events, n_enabled_time_events;
86 int io_events_please_scan, time_events_please_scan, defer_events_please_scan;
87
88 pa_time_event *cached_next_time_event;
89 };
90
cleanup_io_events(pa_glib_mainloop * g,int force)91 static void cleanup_io_events(pa_glib_mainloop *g, int force) {
92 pa_io_event *e;
93
94 e = g->io_events;
95 while (e) {
96 pa_io_event *n = e->next;
97
98 if (!force && g->io_events_please_scan <= 0)
99 break;
100
101 if (force || e->dead) {
102 PA_LLIST_REMOVE(pa_io_event, g->io_events, e);
103
104 if (e->dead) {
105 g_assert(g->io_events_please_scan > 0);
106 g->io_events_please_scan--;
107 }
108
109 if (e->poll_fd_added)
110 g_source_remove_poll(&g->source, &e->poll_fd);
111
112 if (e->destroy_callback)
113 e->destroy_callback(&g->api, e, e->userdata);
114
115 pa_xfree(e);
116 }
117
118 e = n;
119 }
120
121 g_assert(g->io_events_please_scan == 0);
122 }
123
cleanup_time_events(pa_glib_mainloop * g,int force)124 static void cleanup_time_events(pa_glib_mainloop *g, int force) {
125 pa_time_event *e;
126
127 e = g->time_events;
128 while (e) {
129 pa_time_event *n = e->next;
130
131 if (!force && g->time_events_please_scan <= 0)
132 break;
133
134 if (force || e->dead) {
135 PA_LLIST_REMOVE(pa_time_event, g->time_events, e);
136
137 if (e->dead) {
138 g_assert(g->time_events_please_scan > 0);
139 g->time_events_please_scan--;
140 }
141
142 if (!e->dead && e->enabled) {
143 g_assert(g->n_enabled_time_events > 0);
144 g->n_enabled_time_events--;
145 }
146
147 if (e->destroy_callback)
148 e->destroy_callback(&g->api, e, e->userdata);
149
150 pa_xfree(e);
151 }
152
153 e = n;
154 }
155
156 g_assert(g->time_events_please_scan == 0);
157 }
158
cleanup_defer_events(pa_glib_mainloop * g,int force)159 static void cleanup_defer_events(pa_glib_mainloop *g, int force) {
160 pa_defer_event *e;
161
162 e = g->defer_events;
163 while (e) {
164 pa_defer_event *n = e->next;
165
166 if (!force && g->defer_events_please_scan <= 0)
167 break;
168
169 if (force || e->dead) {
170 PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e);
171
172 if (e->dead) {
173 g_assert(g->defer_events_please_scan > 0);
174 g->defer_events_please_scan--;
175 }
176
177 if (!e->dead && e->enabled) {
178 g_assert(g->n_enabled_defer_events > 0);
179 g->n_enabled_defer_events--;
180 }
181
182 if (e->destroy_callback)
183 e->destroy_callback(&g->api, e, e->userdata);
184
185 pa_xfree(e);
186 }
187
188 e = n;
189 }
190
191 g_assert(g->defer_events_please_scan == 0);
192 }
193
map_flags_to_glib(pa_io_event_flags_t flags)194 static gushort map_flags_to_glib(pa_io_event_flags_t flags) {
195 return (gushort)
196 ((flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) |
197 (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) |
198 (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) |
199 (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0));
200 }
201
map_flags_from_glib(gushort flags)202 static pa_io_event_flags_t map_flags_from_glib(gushort flags) {
203 return
204 (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) |
205 (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) |
206 (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) |
207 (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0);
208 }
209
glib_io_new(pa_mainloop_api * m,int fd,pa_io_event_flags_t f,pa_io_event_cb_t cb,void * userdata)210 static pa_io_event* glib_io_new(
211 pa_mainloop_api*m,
212 int fd,
213 pa_io_event_flags_t f,
214 pa_io_event_cb_t cb,
215 void *userdata) {
216
217 pa_io_event *e;
218 pa_glib_mainloop *g;
219
220 g_assert(m);
221 g_assert(m->userdata);
222 g_assert(fd >= 0);
223 g_assert(cb);
224
225 g = m->userdata;
226
227 e = pa_xnew(pa_io_event, 1);
228 e->mainloop = g;
229 e->dead = 0;
230
231 e->poll_fd.fd = fd;
232 e->poll_fd.events = map_flags_to_glib(f);
233 e->poll_fd.revents = 0;
234
235 e->callback = cb;
236 e->userdata = userdata;
237 e->destroy_callback = NULL;
238
239 PA_LLIST_PREPEND(pa_io_event, g->io_events, e);
240
241 g_source_add_poll(&g->source, &e->poll_fd);
242 e->poll_fd_added = 1;
243
244 return e;
245 }
246
glib_io_enable(pa_io_event * e,pa_io_event_flags_t f)247 static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) {
248 g_assert(e);
249 g_assert(!e->dead);
250
251 e->poll_fd.events = map_flags_to_glib(f);
252 }
253
glib_io_free(pa_io_event * e)254 static void glib_io_free(pa_io_event*e) {
255 g_assert(e);
256 g_assert(!e->dead);
257
258 e->dead = 1;
259 e->mainloop->io_events_please_scan++;
260
261 if (e->poll_fd_added) {
262 g_source_remove_poll(&e->mainloop->source, &e->poll_fd);
263 e->poll_fd_added = 0;
264 }
265 }
266
glib_io_set_destroy(pa_io_event * e,pa_io_event_destroy_cb_t cb)267 static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) {
268 g_assert(e);
269 g_assert(!e->dead);
270
271 e->destroy_callback = cb;
272 }
273
274 /* Time sources */
275
glib_time_new(pa_mainloop_api * m,const struct timeval * tv,pa_time_event_cb_t cb,void * userdata)276 static pa_time_event* glib_time_new(
277 pa_mainloop_api*m,
278 const struct timeval *tv,
279 pa_time_event_cb_t cb,
280 void *userdata) {
281
282 pa_glib_mainloop *g;
283 pa_time_event *e;
284
285 g_assert(m);
286 g_assert(m->userdata);
287 g_assert(cb);
288
289 g = m->userdata;
290
291 e = pa_xnew(pa_time_event, 1);
292 e->mainloop = g;
293 e->dead = 0;
294
295 if ((e->enabled = !!tv)) {
296 e->timeval = *tv;
297 g->n_enabled_time_events++;
298
299 if (g->cached_next_time_event) {
300 g_assert(g->cached_next_time_event->enabled);
301
302 if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0)
303 g->cached_next_time_event = e;
304 }
305 }
306
307 e->callback = cb;
308 e->userdata = userdata;
309 e->destroy_callback = NULL;
310
311 PA_LLIST_PREPEND(pa_time_event, g->time_events, e);
312
313 return e;
314 }
315
glib_time_restart(pa_time_event * e,const struct timeval * tv)316 static void glib_time_restart(pa_time_event*e, const struct timeval *tv) {
317 g_assert(e);
318 g_assert(!e->dead);
319
320 if (e->enabled && !tv) {
321 g_assert(e->mainloop->n_enabled_time_events > 0);
322 e->mainloop->n_enabled_time_events--;
323 } else if (!e->enabled && tv)
324 e->mainloop->n_enabled_time_events++;
325
326 if ((e->enabled = !!tv))
327 e->timeval = *tv;
328
329 if (e->mainloop->cached_next_time_event == e)
330 e->mainloop->cached_next_time_event = NULL;
331
332 if (e->mainloop->cached_next_time_event && e->enabled) {
333 g_assert(e->mainloop->cached_next_time_event->enabled);
334
335 if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
336 e->mainloop->cached_next_time_event = e;
337 }
338 }
339
glib_time_free(pa_time_event * e)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
glib_time_set_destroy(pa_time_event * e,pa_time_event_destroy_cb_t cb)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
glib_defer_new(pa_mainloop_api * m,pa_defer_event_cb_t cb,void * userdata)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
glib_defer_enable(pa_defer_event * e,int b)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
glib_defer_free(pa_defer_event * e)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
glib_defer_set_destroy(pa_defer_event * e,pa_defer_event_destroy_cb_t cb)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
glib_quit(pa_mainloop_api * a,int retval)427 static void glib_quit(pa_mainloop_api*a, int retval) {
428
429 g_warning("quit() ignored");
430
431 /* NOOP */
432 }
433
find_next_time_event(pa_glib_mainloop * g)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
scan_dead(pa_glib_mainloop * g)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
prepare_func(GSource * source,gint * timeout)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 gint64 now;
486 struct timeval tvnow;
487 pa_usec_t usec;
488
489 t = find_next_time_event(g);
490 g_assert(t);
491
492 now = g_get_real_time();
493 pa_timeval_store(&tvnow, now);
494
495 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
496 *timeout = 0;
497 return TRUE;
498 }
499 usec = pa_timeval_diff(&t->timeval, &tvnow);
500 *timeout = (gint) (usec / 1000);
501 } else
502 *timeout = -1;
503
504 return FALSE;
505 }
check_func(GSource * source)506 static gboolean check_func(GSource *source) {
507 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
508 pa_io_event *e;
509
510 g_assert(g);
511
512 if (g->n_enabled_defer_events)
513 return TRUE;
514 else if (g->n_enabled_time_events) {
515 pa_time_event *t;
516 gint64 now;
517 struct timeval tvnow;
518
519 t = find_next_time_event(g);
520 g_assert(t);
521
522 now = g_get_real_time();
523 pa_timeval_store(&tvnow, now);
524
525 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0)
526 return TRUE;
527 }
528
529 for (e = g->io_events; e; e = e->next)
530 if (!e->dead && e->poll_fd.revents != 0)
531 return TRUE;
532
533 return FALSE;
534 }
535
dispatch_func(GSource * source,GSourceFunc callback,gpointer userdata)536 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
537 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
538 pa_io_event *e;
539
540 g_assert(g);
541
542 if (g->n_enabled_defer_events) {
543 pa_defer_event *d;
544
545 for (d = g->defer_events; d; d = d->next) {
546 if (d->dead || !d->enabled)
547 continue;
548
549 break;
550 }
551
552 g_assert(d);
553
554 d->callback(&g->api, d, d->userdata);
555 return TRUE;
556 }
557
558 if (g->n_enabled_time_events) {
559 gint64 now;
560 struct timeval tvnow;
561 pa_time_event *t;
562
563 t = find_next_time_event(g);
564 g_assert(t);
565
566 now = g_get_real_time();
567 pa_timeval_store(&tvnow, now);
568
569 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
570
571 /* Disable time event */
572 glib_time_restart(t, NULL);
573
574 t->callback(&g->api, t, &t->timeval, t->userdata);
575 return TRUE;
576 }
577 }
578
579 for (e = g->io_events; e; e = e->next)
580 if (!e->dead && e->poll_fd.revents != 0) {
581 e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata);
582 e->poll_fd.revents = 0;
583 return TRUE;
584 }
585
586 return FALSE;
587 }
588
589 static const pa_mainloop_api vtable = {
590 .userdata = NULL,
591
592 .io_new = glib_io_new,
593 .io_enable = glib_io_enable,
594 .io_free = glib_io_free,
595 .io_set_destroy = glib_io_set_destroy,
596
597 .time_new = glib_time_new,
598 .time_restart = glib_time_restart,
599 .time_free = glib_time_free,
600 .time_set_destroy = glib_time_set_destroy,
601
602 .defer_new = glib_defer_new,
603 .defer_enable = glib_defer_enable,
604 .defer_free = glib_defer_free,
605 .defer_set_destroy = glib_defer_set_destroy,
606
607 .quit = glib_quit,
608 };
609
pa_glib_mainloop_new(GMainContext * c)610 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {
611 pa_glib_mainloop *g;
612
613 static GSourceFuncs source_funcs = {
614 prepare_func,
615 check_func,
616 dispatch_func,
617 NULL,
618 NULL,
619 NULL
620 };
621
622 g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop));
623 g_main_context_ref(g->context = c ? c : g_main_context_default());
624
625 g->api = vtable;
626 g->api.userdata = g;
627
628 PA_LLIST_HEAD_INIT(pa_io_event, g->io_events);
629 PA_LLIST_HEAD_INIT(pa_time_event, g->time_events);
630 PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events);
631
632 g->n_enabled_defer_events = g->n_enabled_time_events = 0;
633 g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0;
634
635 g->cached_next_time_event = NULL;
636
637 g_source_attach(&g->source, g->context);
638 g_source_set_can_recurse(&g->source, FALSE);
639
640 return g;
641 }
642
pa_glib_mainloop_free(pa_glib_mainloop * g)643 void pa_glib_mainloop_free(pa_glib_mainloop* g) {
644 g_assert(g);
645
646 cleanup_io_events(g, 1);
647 cleanup_defer_events(g, 1);
648 cleanup_time_events(g, 1);
649
650 g_main_context_unref(g->context);
651 g_source_destroy(&g->source);
652 g_source_unref(&g->source);
653 }
654
pa_glib_mainloop_get_api(pa_glib_mainloop * g)655 pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) {
656 g_assert(g);
657
658 return &g->api;
659 }
660