]> code.delx.au - pulseaudio/blob - src/pulse/glib-mainloop.c
turn the glib adapter into a single GSource instead of creating a bunch of seperate...
[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->io_events_please_scan--;
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 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->time_events_please_scan--;
142
143 if (!e->dead && e->enabled)
144 g->n_enabled_time_events--;
145
146 if (e->destroy_callback)
147 e->destroy_callback(&g->api, e, e->userdata);
148
149 pa_xfree(e);
150 }
151
152 e = n;
153 }
154
155 assert(g->time_events_please_scan == 0);
156 }
157
158 static void cleanup_defer_events(pa_glib_mainloop *g, int force) {
159 pa_defer_event *e;
160
161 e = g->defer_events;
162 while (e) {
163 pa_defer_event *n = e->next;
164
165 if (!force && g->defer_events_please_scan <= 0)
166 break;
167
168 if (force || e->dead) {
169 PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e);
170
171 if (e->dead)
172 g->defer_events_please_scan--;
173
174 if (!e->dead && e->enabled)
175 g->n_enabled_defer_events--;
176
177 if (e->destroy_callback)
178 e->destroy_callback(&g->api, e, e->userdata);
179
180 pa_xfree(e);
181 }
182
183 e = n;
184 }
185
186 assert(g->defer_events_please_scan == 0);
187 }
188
189 static gushort map_flags_to_glib(pa_io_event_flags_t flags) {
190 return
191 (flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) |
192 (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) |
193 (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) |
194 (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0);
195 }
196
197 static pa_io_event_flags_t map_flags_from_glib(gushort flags) {
198 return
199 (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) |
200 (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) |
201 (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) |
202 (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0);
203 }
204
205 static pa_io_event* glib_io_new(
206 pa_mainloop_api*m,
207 int fd,
208 pa_io_event_flags_t f,
209 pa_io_event_cb_t cb,
210 void *userdata) {
211
212 pa_io_event *e;
213 pa_glib_mainloop *g;
214
215 assert(m);
216 assert(m->userdata);
217 assert(fd >= 0);
218 assert(cb);
219
220 g = m->userdata;
221
222 e = pa_xnew(pa_io_event, 1);
223 e->mainloop = g;
224 e->dead = 0;
225
226 e->poll_fd.fd = fd;
227 e->poll_fd.events = map_flags_to_glib(f);
228 e->poll_fd.revents = 0;
229
230 e->callback = cb;
231 e->userdata = userdata;
232 e->destroy_callback = NULL;
233
234 PA_LLIST_PREPEND(pa_io_event, g->io_events, e);
235
236 g_source_add_poll(&g->source, &e->poll_fd);
237 e->poll_fd_added = 1;
238
239 return e;
240 }
241
242 static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) {
243 assert(e);
244 assert(!e->dead);
245
246 e->poll_fd.events = map_flags_to_glib(f);
247 }
248
249 static void glib_io_free(pa_io_event*e) {
250 assert(e);
251 assert(!e->dead);
252
253 e->dead = 1;
254 e->mainloop->io_events_please_scan++;
255
256 if (e->poll_fd_added) {
257 g_source_remove_poll(&e->mainloop->source, &e->poll_fd);
258 e->poll_fd_added = 0;
259 }
260 }
261
262 static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) {
263 assert(e);
264 assert(!e->dead);
265
266 e->destroy_callback = cb;
267 }
268
269 /* Time sources */
270
271 static pa_time_event* glib_time_new(
272 pa_mainloop_api*m,
273 const struct timeval *tv,
274 pa_time_event_cb_t cb,
275 void *userdata) {
276
277 pa_glib_mainloop *g;
278 pa_time_event *e;
279
280 assert(m);
281 assert(m->userdata);
282 assert(cb);
283
284 g = m->userdata;
285
286 e = pa_xnew(pa_time_event, 1);
287 e->mainloop = g;
288 e->dead = 0;
289
290 if ((e->enabled = !!tv)) {
291 e->timeval = *tv;
292 g->n_enabled_time_events++;
293
294 if (g->cached_next_time_event) {
295 g_assert(g->cached_next_time_event->enabled);
296
297 if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0)
298 g->cached_next_time_event = e;
299 }
300 }
301
302 e->callback = cb;
303 e->userdata = userdata;
304 e->destroy_callback = NULL;
305
306 PA_LLIST_PREPEND(pa_time_event, g->time_events, e);
307
308 return e;
309 }
310
311 static void glib_time_restart(pa_time_event*e, const struct timeval *tv) {
312 assert(e);
313 assert(!e->dead);
314
315 if (e->enabled && !!tv)
316 e->mainloop->n_enabled_time_events--;
317 else if (!e->enabled && tv)
318 e->mainloop->n_enabled_time_events++;
319
320 if ((e->enabled = !!tv))
321 e->timeval = *tv;
322
323 if (e->mainloop->cached_next_time_event && e->enabled) {
324 g_assert(e->mainloop->cached_next_time_event->enabled);
325
326 if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
327 e->mainloop->cached_next_time_event = e;
328 } else if (e->mainloop->cached_next_time_event == e)
329 e->mainloop->cached_next_time_event = NULL;
330 }
331
332 static void glib_time_free(pa_time_event *e) {
333 assert(e);
334 assert(!e->dead);
335
336 e->dead = 1;
337 e->mainloop->time_events_please_scan++;
338
339 if (e->enabled)
340 e->mainloop->n_enabled_time_events--;
341
342 if (e->mainloop->cached_next_time_event == e)
343 e->mainloop->cached_next_time_event = NULL;
344 }
345
346 static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) {
347 assert(e);
348 assert(!e->dead);
349
350 e->destroy_callback = cb;
351 }
352
353 /* Deferred sources */
354
355 static pa_defer_event* glib_defer_new(
356 pa_mainloop_api*m,
357 pa_defer_event_cb_t cb,
358 void *userdata) {
359
360 pa_defer_event *e;
361 pa_glib_mainloop *g;
362
363 assert(m);
364 assert(m->userdata);
365 assert(cb);
366
367 g = m->userdata;
368
369 e = pa_xnew(pa_defer_event, 1);
370 e->mainloop = g;
371 e->dead = 0;
372
373 e->enabled = 1;
374 g->n_enabled_defer_events++;
375
376 e->callback = cb;
377 e->userdata = userdata;
378 e->destroy_callback = NULL;
379
380 PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e);
381 return e;
382 }
383
384 static void glib_defer_enable(pa_defer_event *e, int b) {
385 assert(e);
386 assert(!e->dead);
387
388 if (e->enabled && !b)
389 e->mainloop->n_enabled_defer_events--;
390 else if (!e->enabled && b)
391 e->mainloop->n_enabled_defer_events++;
392
393 e->enabled = b;
394 }
395
396 static void glib_defer_free(pa_defer_event *e) {
397 assert(e);
398 assert(!e->dead);
399
400 e->dead = 1;
401 e->mainloop->defer_events_please_scan++;
402
403 if (e->enabled)
404 e->mainloop->n_enabled_defer_events--;
405 }
406
407 static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) {
408 assert(e);
409 assert(!e->dead);
410
411 e->destroy_callback = cb;
412 }
413
414 /* quit() */
415
416 static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) {
417
418 g_warning("quit() ignored");
419
420 /* NOOP */
421 }
422
423 static pa_time_event* find_next_time_event(pa_glib_mainloop *g) {
424 pa_time_event *t, *n = NULL;
425 assert(g);
426
427 if (g->cached_next_time_event)
428 return g->cached_next_time_event;
429
430 for (t = g->time_events; t; t = t->next) {
431
432 if (t->dead || !t->enabled)
433 continue;
434
435 if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
436 n = t;
437
438 /* Shortcut for tv = { 0, 0 } */
439 if (n->timeval.tv_sec <= 0)
440 break;
441 }
442 }
443
444 g->cached_next_time_event = n;
445 return n;
446 }
447
448 static gboolean prepare_func(GSource *source, gint *timeout) {
449 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
450
451 g_assert(g);
452 g_assert(timeout);
453
454 if (g->io_events_please_scan)
455 cleanup_io_events(g, 0);
456
457 if (g->time_events_please_scan)
458 cleanup_time_events(g, 0);
459
460 if (g->defer_events_please_scan)
461 cleanup_defer_events(g, 0);
462
463 if (g->n_enabled_defer_events) {
464 *timeout = 0;
465 return TRUE;
466 } else if (g->n_enabled_time_events) {
467 pa_time_event *t;
468 GTimeVal now;
469 struct timeval tvnow;
470 pa_usec_t usec;
471
472 t = find_next_time_event(g);
473 g_assert(t);
474
475 g_source_get_current_time(source, &now);
476 tvnow.tv_sec = now.tv_sec;
477 tvnow.tv_usec = now.tv_usec;
478
479 usec = pa_timeval_diff(&t->timeval, &tvnow);
480
481 if (usec <= 0) {
482 *timeout = 0;
483 return TRUE;
484 }
485
486 *timeout = (gint) (usec / 1000);
487 } else
488 *timeout = -1;
489
490 return FALSE;
491 }
492 static gboolean check_func(GSource *source) {
493 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
494 pa_io_event *e;
495
496 g_assert(g);
497
498 if (g->n_enabled_defer_events)
499 return TRUE;
500 else if (g->n_enabled_time_events) {
501 pa_time_event *t;
502 GTimeVal now;
503 struct timeval tvnow;
504
505 t = find_next_time_event(g);
506 g_assert(t);
507
508 g_source_get_current_time(source, &now);
509 tvnow.tv_sec = now.tv_sec;
510 tvnow.tv_usec = now.tv_usec;
511
512 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0)
513 return TRUE;
514 }
515
516 for (e = g->io_events; e; e = e->next)
517 if (!e->dead && e->poll_fd.revents != 0)
518 return TRUE;
519
520 return FALSE;
521 }
522
523 static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callback, PA_GCC_UNUSED gpointer userdata) {
524 pa_glib_mainloop *g = (pa_glib_mainloop*) source;
525 pa_io_event *e;
526
527 g_assert(g);
528
529 if (g->n_enabled_defer_events) {
530 pa_defer_event *d;
531
532 for (d = g->defer_events; d; d = d->next) {
533 if (d->dead || !d->enabled)
534 continue;
535
536 break;
537 }
538
539 assert(d);
540
541 d->callback(&g->api, d, d->userdata);
542 return TRUE;
543 }
544
545 if (g->n_enabled_time_events) {
546 GTimeVal now;
547 struct timeval tvnow;
548 pa_time_event *t;
549
550 t = find_next_time_event(g);
551 g_assert(t);
552
553 g_source_get_current_time(source, &now);
554 tvnow.tv_sec = now.tv_sec;
555 tvnow.tv_usec = now.tv_usec;
556
557 if (pa_timeval_cmp(&t->timeval, &tvnow) < 0) {
558 t->callback(&g->api, t, &t->timeval, t->userdata);
559 return TRUE;
560 }
561 }
562
563 for (e = g->io_events; e; e = e->next)
564 if (!e->dead && e->poll_fd.revents != 0) {
565 e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata);
566 e->poll_fd.revents = 0;
567 return TRUE;
568 }
569
570 return FALSE;
571 }
572
573 static const pa_mainloop_api vtable = {
574 .userdata = NULL,
575
576 .io_new = glib_io_new,
577 .io_enable = glib_io_enable,
578 .io_free = glib_io_free,
579 .io_set_destroy= glib_io_set_destroy,
580
581 .time_new = glib_time_new,
582 .time_restart = glib_time_restart,
583 .time_free = glib_time_free,
584 .time_set_destroy = glib_time_set_destroy,
585
586 .defer_new = glib_defer_new,
587 .defer_enable = glib_defer_enable,
588 .defer_free = glib_defer_free,
589 .defer_set_destroy = glib_defer_set_destroy,
590
591 .quit = glib_quit,
592 };
593
594 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {
595 pa_glib_mainloop *g;
596
597 static GSourceFuncs source_funcs = {
598 prepare_func,
599 check_func,
600 dispatch_func,
601 NULL,
602 NULL,
603 NULL
604 };
605
606 g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop));
607 g_main_context_ref(g->context = c ? c : g_main_context_default());
608
609 g->api = vtable;
610 g->api.userdata = g;
611
612 PA_LLIST_HEAD_INIT(pa_io_event, g->io_events);
613 PA_LLIST_HEAD_INIT(pa_time_event, g->time_events);
614 PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events);
615
616 g->n_enabled_defer_events = g->n_enabled_time_events = 0;
617 g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0;
618
619 g_source_attach(&g->source, g->context);
620 g_source_set_can_recurse(&g->source, FALSE);
621
622 return g;
623 }
624
625 void pa_glib_mainloop_free(pa_glib_mainloop* g) {
626 assert(g);
627
628 cleanup_io_events(g, 1);
629 cleanup_defer_events(g, 1);
630 cleanup_time_events(g, 1);
631
632 g_main_context_unref(g->context);
633 g_source_destroy(&g->source);
634 g_source_unref(&g->source);
635 }
636
637 pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) {
638 assert(g);
639
640 return &g->api;
641 }