]> code.delx.au - pulseaudio/blob - src/pulse/glib-mainloop.c
alsa-mixer: Add surround 2.1 profile
[pulseaudio] / 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 }