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