]> code.delx.au - pulseaudio/blob - src/pulse/glib-mainloop.c
add a few more g_assert()s and change all assert()s to g_assert()s
[pulseaudio] / src / pulse / glib-mainloop.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
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 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 <assert.h>
27
28 #include <pulse/xmalloc.h>
29 #include <pulse/timeval.h>
30
31 #include <pulsecore/idxset.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/log.h>
34 #include <pulsecore/llist.h>
35
36 #include <glib.h>
37 #include "glib-mainloop.h"
38
39 struct pa_io_event {
40 pa_glib_mainloop *mainloop;
41 int dead;
42
43 GPollFD poll_fd;
44 int poll_fd_added;
45
46 pa_io_event_cb_t callback;
47 void *userdata;
48 pa_io_event_destroy_cb_t destroy_callback;
49
50 PA_LLIST_FIELDS(pa_io_event);
51 };
52
53 struct pa_time_event {
54 pa_glib_mainloop *mainloop;
55 int dead;
56
57 int enabled;
58 struct timeval timeval;
59
60 pa_time_event_cb_t callback;
61 void *userdata;
62 pa_time_event_destroy_cb_t destroy_callback;
63
64 PA_LLIST_FIELDS(pa_time_event);
65 };
66
67 struct pa_defer_event {
68 pa_glib_mainloop *mainloop;
69 int dead;
70
71 int enabled;
72
73 pa_defer_event_cb_t callback;
74 void *userdata;
75 pa_defer_event_destroy_cb_t destroy_callback;
76
77 PA_LLIST_FIELDS(pa_defer_event);
78 };
79
80 struct pa_glib_mainloop {
81 GSource source;
82
83 pa_mainloop_api api;
84 GMainContext *context;
85
86 PA_LLIST_HEAD(pa_io_event, io_events);
87 PA_LLIST_HEAD(pa_time_event, time_events);
88 PA_LLIST_HEAD(pa_defer_event, defer_events);
89
90 int n_enabled_defer_events, n_enabled_time_events;
91 int io_events_please_scan, time_events_please_scan, defer_events_please_scan;
92
93 pa_time_event *cached_next_time_event;
94 };
95
96 static void cleanup_io_events(pa_glib_mainloop *g, int force) {
97 pa_io_event *e;
98
99 e = g->io_events;
100 while (e) {
101 pa_io_event *n = e->next;
102
103 if (!force && g->io_events_please_scan <= 0)
104 break;
105
106 if (force || e->dead) {
107 PA_LLIST_REMOVE(pa_io_event, g->io_events, e);
108
109 if (e->dead) {
110 g_assert(g->io_events_please_scan > 0);
111 g->io_events_please_scan--;
112 }
113
114 if (e->poll_fd_added)
115 g_source_remove_poll(&g->source, &e->poll_fd);
116
117 if (e->destroy_callback)
118 e->destroy_callback(&g->api, e, e->userdata);
119
120 pa_xfree(e);
121 }
122
123 e = n;
124 }
125
126 g_assert(g->io_events_please_scan == 0);
127 }
128
129 static void cleanup_time_events(pa_glib_mainloop *g, int force) {
130 pa_time_event *e;
131
132 e = g->time_events;
133 while (e) {
134 pa_time_event *n = e->next;
135
136 if (!force && g->time_events_please_scan <= 0)
137 break;
138
139 if (force || e->dead) {
140 PA_LLIST_REMOVE(pa_time_event, g->time_events, e);
141
142 if (e->dead) {
143 g_assert(g->time_events_please_scan > 0);
144 g->time_events_please_scan--;
145 }
146
147 if (!e->dead && e->enabled) {
148 g_assert(g->n_enabled_time_events > 0);
149 g->n_enabled_time_events--;
150 }
151
152 if (e->destroy_callback)
153 e->destroy_callback(&g->api, e, e->userdata);
154
155 pa_xfree(e);
156 }
157
158 e = n;
159 }
160
161 g_assert(g->time_events_please_scan == 0);
162 }
163
164 static void cleanup_defer_events(pa_glib_mainloop *g, int force) {
165 pa_defer_event *e;
166
167 e = g->defer_events;
168 while (e) {
169 pa_defer_event *n = e->next;
170
171 if (!force && g->defer_events_please_scan <= 0)
172 break;
173
174 if (force || e->dead) {
175 PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e);
176
177 if (e->dead) {
178 g_assert(g->defer_events_please_scan > 0);
179 g->defer_events_please_scan--;
180 }
181
182 if (!e->dead && e->enabled) {
183 g_assert(g->n_enabled_defer_events > 0);
184 g->n_enabled_defer_events--;
185 }
186
187 if (e->destroy_callback)
188 e->destroy_callback(&g->api, e, e->userdata);
189
190 pa_xfree(e);
191 }
192
193 e = n;
194 }
195
196 g_assert(g->defer_events_please_scan == 0);
197 }
198
199 static gushort map_flags_to_glib(pa_io_event_flags_t flags) {
200 return
201 (flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) |
202 (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) |
203 (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) |
204 (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0);
205 }
206
207 static pa_io_event_flags_t map_flags_from_glib(gushort flags) {
208 return
209 (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) |
210 (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) |
211 (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) |
212 (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0);
213 }
214
215 static pa_io_event* glib_io_new(
216 pa_mainloop_api*m,
217 int fd,
218 pa_io_event_flags_t f,
219 pa_io_event_cb_t cb,
220 void *userdata) {
221
222 pa_io_event *e;
223 pa_glib_mainloop *g;
224
225 g_assert(m);
226 g_assert(m->userdata);
227 g_assert(fd >= 0);
228 g_assert(cb);
229
230 g = m->userdata;
231
232 e = pa_xnew(pa_io_event, 1);
233 e->mainloop = g;
234 e->dead = 0;
235
236 e->poll_fd.fd = fd;
237 e->poll_fd.events = map_flags_to_glib(f);
238 e->poll_fd.revents = 0;
239
240 e->callback = cb;
241 e->userdata = userdata;
242 e->destroy_callback = NULL;
243
244 PA_LLIST_PREPEND(pa_io_event, g->io_events, e);
245
246 g_source_add_poll(&g->source, &e->poll_fd);
247 e->poll_fd_added = 1;
248
249 return e;
250 }
251
252 static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) {
253 g_assert(e);
254 g_assert(!e->dead);
255
256 e->poll_fd.events = map_flags_to_glib(f);
257 }
258
259 static void glib_io_free(pa_io_event*e) {
260 g_assert(e);
261 g_assert(!e->dead);
262
263 e->dead = 1;
264 e->mainloop->io_events_please_scan++;
265
266 if (e->poll_fd_added) {
267 g_source_remove_poll(&e->mainloop->source, &e->poll_fd);
268 e->poll_fd_added = 0;
269 }
270 }
271
272 static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) {
273 g_assert(e);
274 g_assert(!e->dead);
275
276 e->destroy_callback = cb;
277 }
278
279 /* Time sources */
280
281 static pa_time_event* glib_time_new(
282 pa_mainloop_api*m,
283 const struct timeval *tv,
284 pa_time_event_cb_t cb,
285 void *userdata) {
286
287 pa_glib_mainloop *g;
288 pa_time_event *e;
289
290 g_assert(m);
291 g_assert(m->userdata);
292 g_assert(cb);
293
294 g = m->userdata;
295
296 e = pa_xnew(pa_time_event, 1);
297 e->mainloop = g;
298 e->dead = 0;
299
300 if ((e->enabled = !!tv)) {
301 e->timeval = *tv;
302 g->n_enabled_time_events++;
303
304 if (g->cached_next_time_event) {
305 g_assert(g->cached_next_time_event->enabled);
306
307 if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0)
308 g->cached_next_time_event = e;
309 }
310 }
311
312 e->callback = cb;
313 e->userdata = userdata;
314 e->destroy_callback = NULL;
315
316 PA_LLIST_PREPEND(pa_time_event, g->time_events, e);
317
318 return e;
319 }
320
321 static void glib_time_restart(pa_time_event*e, const struct timeval *tv) {
322 g_assert(e);
323 g_assert(!e->dead);
324
325 if (e->enabled && !tv) {
326 g_assert(e->mainloop->n_enabled_time_events > 0);
327 e->mainloop->n_enabled_time_events--;
328 } else if (!e->enabled && tv)
329 e->mainloop->n_enabled_time_events++;
330
331 if ((e->enabled = !!tv))
332 e->timeval = *tv;
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 } else if (e->mainloop->cached_next_time_event == e)
340 e->mainloop->cached_next_time_event = NULL;
341 }
342
343 static void glib_time_free(pa_time_event *e) {
344 g_assert(e);
345 g_assert(!e->dead);
346
347 e->dead = 1;
348 e->mainloop->time_events_please_scan++;
349
350 if (e->enabled)
351 e->mainloop->n_enabled_time_events--;
352
353 if (e->mainloop->cached_next_time_event == e)
354 e->mainloop->cached_next_time_event = NULL;
355 }
356
357 static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) {
358 g_assert(e);
359 g_assert(!e->dead);
360
361 e->destroy_callback = cb;
362 }
363
364 /* Deferred sources */
365
366 static pa_defer_event* glib_defer_new(
367 pa_mainloop_api*m,
368 pa_defer_event_cb_t cb,
369 void *userdata) {
370
371 pa_defer_event *e;
372 pa_glib_mainloop *g;
373
374 g_assert(m);
375 g_assert(m->userdata);
376 g_assert(cb);
377
378 g = m->userdata;
379
380 e = pa_xnew(pa_defer_event, 1);
381 e->mainloop = g;
382 e->dead = 0;
383
384 e->enabled = 1;
385 g->n_enabled_defer_events++;
386
387 e->callback = cb;
388 e->userdata = userdata;
389 e->destroy_callback = NULL;
390
391 PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e);
392 return e;
393 }
394
395 static void glib_defer_enable(pa_defer_event *e, int b) {
396 g_assert(e);
397 g_assert(!e->dead);
398
399 if (e->enabled && !b) {
400 g_assert(e->mainloop->n_enabled_defer_events > 0);
401 e->mainloop->n_enabled_defer_events--;
402 } else if (!e->enabled && b)
403 e->mainloop->n_enabled_defer_events++;
404
405 e->enabled = b;
406 }
407
408 static void glib_defer_free(pa_defer_event *e) {
409 g_assert(e);
410 g_assert(!e->dead);
411
412 e->dead = 1;
413 e->mainloop->defer_events_please_scan++;
414
415 if (e->enabled) {
416 g_assert(e->mainloop->n_enabled_defer_events > 0);
417 e->mainloop->n_enabled_defer_events--;
418 }
419 }
420
421 static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) {
422 g_assert(e);
423 g_assert(!e->dead);
424
425 e->destroy_callback = cb;
426 }
427
428 /* quit() */
429
430 static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) {
431
432 g_warning("quit() ignored");
433
434 /* NOOP */
435 }
436
437 static pa_time_event* find_next_time_event(pa_glib_mainloop *g) {
438 pa_time_event *t, *n = NULL;
439 g_assert(g);
440
441 if (g->cached_next_time_event)
442 return g->cached_next_time_event;
443
444 for (t = g->time_events; t; t = t->next) {
445
446 if (t->dead || !t->enabled)
447 continue;
448
449 if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
450 n = t;
451
452 /* Shortcut for tv = { 0, 0 } */
453 if (n->timeval.tv_sec <= 0)
454 break;
455 }
456 }
457
458 g->cached_next_time_event = n;
459 return n;
460 }
461
462 static void scan_dead(pa_glib_mainloop *g) {
463 g_assert(g);
464
465 if (g->io_events_please_scan)
466 cleanup_io_events(g, 0);
467
468 if (g->time_events_please_scan)
469 cleanup_time_events(g, 0);
470
471 if (g->defer_events_please_scan)
472 cleanup_defer_events(g, 0);
473 }
474
475 static gboolean prepare_func(GSource *source, gint *timeout) {
476 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
477
478 g_assert(g);
479 g_assert(timeout);
480
481 scan_dead(g);
482
483 if (g->n_enabled_defer_events) {
484 *timeout = 0;
485 return TRUE;
486 } else if (g->n_enabled_time_events) {
487 pa_time_event *t;
488 GTimeVal now;
489 struct timeval tvnow;
490 pa_usec_t usec;
491
492 t = find_next_time_event(g);
493 g_assert(t);
494
495 g_source_get_current_time(source, &now);
496 tvnow.tv_sec = now.tv_sec;
497 tvnow.tv_usec = now.tv_usec;
498
499 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
500 *timeout = 0;
501 return TRUE;
502 }
503 usec = pa_timeval_diff(&t->timeval, &tvnow);
504 *timeout = (gint) (usec / 1000);
505 } else
506 *timeout = -1;
507
508 return FALSE;
509 }
510 static gboolean check_func(GSource *source) {
511 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
512 pa_io_event *e;
513
514 g_assert(g);
515
516 if (g->n_enabled_defer_events)
517 return TRUE;
518 else if (g->n_enabled_time_events) {
519 pa_time_event *t;
520 GTimeVal now;
521 struct timeval tvnow;
522
523 t = find_next_time_event(g);
524 g_assert(t);
525
526 g_source_get_current_time(source, &now);
527 tvnow.tv_sec = now.tv_sec;
528 tvnow.tv_usec = now.tv_usec;
529
530 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0)
531 return TRUE;
532 }
533
534 for (e = g->io_events; e; e = e->next)
535 if (!e->dead && e->poll_fd.revents != 0)
536 return TRUE;
537
538 return FALSE;
539 }
540
541 static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callback, PA_GCC_UNUSED gpointer userdata) {
542 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
543 pa_io_event *e;
544
545 g_assert(g);
546
547 if (g->n_enabled_defer_events) {
548 pa_defer_event *d;
549
550 for (d = g->defer_events; d; d = d->next) {
551 if (d->dead || !d->enabled)
552 continue;
553
554 break;
555 }
556
557 g_assert(d);
558
559 d->callback(&g->api, d, d->userdata);
560 return TRUE;
561 }
562
563 if (g->n_enabled_time_events) {
564 GTimeVal now;
565 struct timeval tvnow;
566 pa_time_event *t;
567
568 t = find_next_time_event(g);
569 g_assert(t);
570
571 g_source_get_current_time(source, &now);
572 tvnow.tv_sec = now.tv_sec;
573 tvnow.tv_usec = now.tv_usec;
574
575 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) {
576 t->enabled = 0;
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_source_attach(&g->source, g->context);
639 g_source_set_can_recurse(&g->source, FALSE);
640
641 return g;
642 }
643
644 void pa_glib_mainloop_free(pa_glib_mainloop* g) {
645 g_assert(g);
646
647 cleanup_io_events(g, 1);
648 cleanup_defer_events(g, 1);
649 cleanup_time_events(g, 1);
650
651 g_main_context_unref(g->context);
652 g_source_destroy(&g->source);
653 g_source_unref(&g->source);
654 }
655
656 pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) {
657 g_assert(g);
658
659 return &g->api;
660 }