]> code.delx.au - pulseaudio/blob - src/pulse/glib-mainloop.c
bd24913b465cff0069ccf362fd897ac32e0a5c63
[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->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 }