]> code.delx.au - pulseaudio/blob - polyp/glib-mainloop.c
add initial glib mainloop adapter
[pulseaudio] / polyp / glib-mainloop.c
1 #include <assert.h>
2
3 #include "glib-mainloop.h"
4 #include "idxset.h"
5 #include "xmalloc.h"
6
7 struct pa_io_event {
8 GSource source;
9 int dead;
10 struct pa_glib_mainloop *mainloop;
11 int fd;
12 GPollFD pollfd;
13 void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata);
14 void *userdata;
15 void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata);
16 struct pa_io_event *next, *prev;
17 };
18
19 struct pa_time_event {
20 struct pa_glib_mainloop *mainloop;
21 int dead;
22 GSource *source;
23 struct timeval timeval;
24 void (*callback) (struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata);
25 void *userdata;
26 void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_time_event*e, void *userdata);
27 struct pa_time_event *next, *prev;
28 };
29
30 struct pa_defer_event {
31 struct pa_glib_mainloop *mainloop;
32 int dead;
33 GSource *source;
34 void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata);
35 void *userdata;
36 void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata);
37 struct pa_defer_event *next, *prev;
38 };
39
40 struct pa_glib_mainloop {
41 GMainLoop *glib_mainloop;
42 struct pa_mainloop_api api;
43 GSource *cleanup_source;
44 struct pa_io_event *io_events, *dead_io_events;
45 struct pa_time_event *time_events, *dead_time_events;
46 struct pa_defer_event *defer_events, *dead_defer_events;
47 };
48
49 static void schedule_free_dead_events(struct pa_glib_mainloop *g);
50
51 static gboolean glib_source_prepare(GSource *source, gint *timeout) {
52 return FALSE;
53 }
54
55 static gboolean glib_source_check(GSource *source) {
56 struct pa_io_event *e = (struct pa_io_event*) source;
57 assert(e);
58 return !!e->pollfd.revents;
59 }
60
61 static gboolean glib_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
62 struct pa_io_event *e = (struct pa_io_event*) source;
63 assert(e);
64
65 if (e->pollfd.revents) {
66 int f =
67 (e->pollfd.revents ? G_IO_IN : PA_IO_EVENT_INPUT) |
68 (e->pollfd.revents ? G_IO_OUT : PA_IO_EVENT_OUTPUT) |
69 (e->pollfd.revents ? G_IO_HUP : PA_IO_EVENT_HANGUP) |
70 (e->pollfd.revents ? G_IO_ERR : PA_IO_EVENT_ERROR);
71 e->pollfd.revents = 0;
72
73 assert(e->callback);
74 e->callback(&e->mainloop->api, e, e->fd, f, e->userdata);
75 }
76
77 return TRUE;
78 }
79
80 static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f);
81
82 static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) {
83 struct pa_io_event *e;
84 struct pa_glib_mainloop *g;
85
86 GSourceFuncs io_source_funcs = {
87 prepare: glib_source_prepare,
88 check: glib_source_check,
89 dispatch: glib_source_dispatch,
90 finalize: NULL,
91 closure_callback: NULL,
92 closure_marshal : NULL,
93 };
94
95 assert(m && m->userdata && fd >= 0 && callback);
96 g = m->userdata;
97
98 e = (struct pa_io_event*) g_source_new(&io_source_funcs, sizeof(struct pa_io_event));
99 assert(e);
100 e->mainloop = m->userdata;
101 e->dead = 0;
102 e->fd = fd;
103 e->callback = callback;
104 e->userdata = userdata;
105 e->destroy_callback = NULL;
106
107 e->pollfd.fd = fd;
108 e->pollfd.events = e->pollfd.revents = 0;
109
110 g_source_attach(&e->source, g_main_loop_get_context(g->glib_mainloop));
111
112 glib_io_enable(e, f);
113
114 e->next = g->io_events;
115 if (e->next) e->next->prev = e;
116 g->io_events = e;
117 e->prev = NULL;
118
119 return e;
120 }
121
122 static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) {
123 int o;
124 assert(e && !e->dead);
125
126 o = e->pollfd.events;
127 e->pollfd.events = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | G_IO_HUP | G_IO_ERR;
128
129 if (!o && e->pollfd.events)
130 g_source_add_poll(&e->source, &e->pollfd);
131 else if (o && !e->pollfd.events)
132 g_source_remove_poll(&e->source, &e->pollfd);
133 }
134
135 static void glib_io_free(struct pa_io_event*e) {
136 assert(e && !e->dead);
137
138 g_source_destroy(&e->source);
139
140 if (e->prev)
141 e->prev->next = e->next;
142 else
143 e->mainloop->io_events = e->next;
144
145 if (e->next)
146 e->next->prev = e->prev;
147
148 if ((e->next = e->mainloop->dead_io_events))
149 e->next->prev = e;
150
151 e->mainloop->dead_io_events = e;
152 e->prev = NULL;
153
154 e->dead = 1;
155 schedule_free_dead_events(e->mainloop);
156 }
157
158 static void glib_io_set_destroy(struct pa_io_event*e, void (*callback)(struct pa_mainloop_api*m, struct pa_io_event *e, void *userdata)) {
159 assert(e);
160 e->destroy_callback = callback;
161 }
162
163 /* Time sources */
164
165 static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv);
166
167 static struct pa_time_event* glib_time_new(struct pa_mainloop_api*m, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) {
168 struct pa_glib_mainloop *g;
169 struct pa_time_event *e;
170
171 assert(m && m->userdata && tv && callback);
172 g = m->userdata;
173
174 e = pa_xmalloc(sizeof(struct pa_time_event));
175 e->mainloop = g;
176 e->dead = 0;
177 e->callback = callback;
178 e->userdata = userdata;
179 e->destroy_callback = NULL;
180 e->source = NULL;
181
182 glib_time_restart(e, tv);
183
184 e->next = g->time_events;
185 if (e->next) e->next->prev = e;
186 g->time_events = e;
187 e->prev = NULL;
188
189 return e;
190 }
191
192 static guint msec_diff(const struct timeval *a, const struct timeval *b) {
193 guint r;
194 assert(a && b);
195
196 if (a->tv_sec < b->tv_sec)
197 return 0;
198
199 if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec)
200 return 0;
201
202 r = (a->tv_sec-b->tv_sec)*1000;
203
204 if (a->tv_usec >= b->tv_usec)
205 r += (a->tv_usec - b->tv_usec) / 1000;
206 else
207 r -= (b->tv_usec - a->tv_usec) / 1000;
208
209 return r;
210 }
211
212 static gboolean time_cb(gpointer data) {
213 struct pa_time_event* e = data;
214 assert(e && e->mainloop && e->source);
215
216 g_source_unref(e->source);
217 e->source = NULL;
218
219 e->callback(&e->mainloop->api, e, &e->timeval, e->userdata);
220 return FALSE;
221 }
222
223 static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) {
224 struct timeval now;
225 assert(e && e->mainloop);
226
227 gettimeofday(&now, NULL);
228 if (e->source) {
229 g_source_destroy(e->source);
230 g_source_unref(e->source);
231 }
232
233 if (tv) {
234 e->timeval = *tv;
235 e->source = g_timeout_source_new(msec_diff(tv, &now));
236 assert(e->source);
237 g_source_set_callback(e->source, time_cb, e, NULL);
238 g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop));
239 } else
240 e->source = NULL;
241 }
242
243 static void glib_time_free(struct pa_time_event *e) {
244 assert(e && e->mainloop);
245
246 if (e->source) {
247 g_source_destroy(e->source);
248 g_source_unref(e->source);
249 e->source = NULL;
250 }
251
252 if (e->prev)
253 e->prev->next = e->next;
254 else
255 e->mainloop->time_events = e->next;
256
257 if (e->next)
258 e->next->prev = e->prev;
259
260 if ((e->next = e->mainloop->dead_time_events))
261 e->next->prev = e;
262
263 e->mainloop->dead_time_events = e;
264 e->prev = NULL;
265
266 e->dead = 1;
267 schedule_free_dead_events(e->mainloop);
268 }
269
270 static void glib_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*m, struct pa_time_event*e, void *userdata)) {
271 assert(e);
272 e->destroy_callback = callback;
273 }
274
275 /* Deferred sources */
276
277 static void glib_defer_enable(struct pa_defer_event *e, int b);
278
279 static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata), void *userdata) {
280 struct pa_defer_event *e;
281 struct pa_glib_mainloop *g;
282
283 assert(m && m->userdata && callback);
284 g = m->userdata;
285
286 e = pa_xmalloc(sizeof(struct pa_defer_event));
287 e->mainloop = g;
288 e->dead = 0;
289 e->callback = callback;
290 e->userdata = userdata;
291 e->destroy_callback = NULL;
292 e->source = NULL;
293
294 glib_defer_enable(e, 1);
295
296 e->next = g->defer_events;
297 if (e->next) e->next->prev = e;
298 g->defer_events = e;
299 e->prev = NULL;
300 return e;
301 }
302
303 static gboolean idle_cb(gpointer data) {
304 struct pa_defer_event* e = data;
305 assert(e && e->mainloop && e->source);
306
307 e->callback(&e->mainloop->api, e, e->userdata);
308 return TRUE;
309 }
310
311 static void glib_defer_enable(struct pa_defer_event *e, int b) {
312 assert(e && e->mainloop);
313
314 if (e->source && !b) {
315 g_source_destroy(e->source);
316 g_source_unref(e->source);
317 e->source = NULL;
318 } else if (!e->source && b) {
319 e->source = g_idle_source_new();
320 assert(e->source);
321 g_source_set_callback(e->source, idle_cb, e, NULL);
322 g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop));
323 g_source_set_priority(e->source, G_PRIORITY_HIGH_IDLE);
324 }
325 }
326
327 static void glib_defer_free(struct pa_defer_event *e) {
328 assert(e && e->mainloop);
329
330 if (e->source) {
331 g_source_destroy(e->source);
332 g_source_unref(e->source);
333 e->source = NULL;
334 }
335
336 if (e->prev)
337 e->prev->next = e->next;
338 else
339 e->mainloop->defer_events = e->next;
340
341 if (e->next)
342 e->next->prev = e->prev;
343
344 if ((e->next = e->mainloop->dead_defer_events))
345 e->next->prev = e;
346
347 e->mainloop->dead_defer_events = e;
348 e->prev = NULL;
349
350 e->dead = 1;
351 schedule_free_dead_events(e->mainloop);
352 }
353
354 static void glib_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata)) {
355 assert(e);
356 e->destroy_callback = callback;
357 }
358
359 /* quit() */
360
361 static void glib_quit(struct pa_mainloop_api*a, int retval) {
362 struct pa_glib_mainloop *g;
363 assert(a && a->userdata);
364 g = a->userdata;
365
366 g_main_loop_quit(g->glib_mainloop);
367 }
368
369 static const struct pa_mainloop_api vtable = {
370 userdata: NULL,
371
372 io_new: glib_io_new,
373 io_enable: glib_io_enable,
374 io_free: glib_io_free,
375 io_set_destroy: glib_io_set_destroy,
376
377 time_new : glib_time_new,
378 time_restart : glib_time_restart,
379 time_free : glib_time_free,
380 time_set_destroy : glib_time_set_destroy,
381
382 defer_new : glib_defer_new,
383 defer_enable : glib_defer_enable,
384 defer_free : glib_defer_free,
385 defer_set_destroy : glib_defer_set_destroy,
386
387 quit : glib_quit,
388 };
389
390 struct pa_glib_mainloop *pa_glib_mainloop_new(GMainLoop *ml) {
391 struct pa_glib_mainloop *g;
392 assert(ml);
393
394 g = pa_xmalloc(sizeof(struct pa_glib_mainloop));
395 g->glib_mainloop = g_main_loop_ref(ml);
396 g->api = vtable;
397 g->api.userdata = g;
398
399 g->io_events = g->dead_io_events = NULL;
400 g->time_events = g->dead_time_events = NULL;
401 g->defer_events = g->dead_defer_events = NULL;
402
403 g->cleanup_source = NULL;
404 return g;
405 }
406
407 static void free_io_events(struct pa_io_event *e) {
408 while (e) {
409 struct pa_io_event *r = e;
410 e = r->next;
411
412 if (r->pollfd.events)
413 g_source_remove_poll(&r->source, &r->pollfd);
414
415 if (!r->dead)
416 g_source_destroy(&r->source);
417
418 if (r->destroy_callback)
419 r->destroy_callback(&r->mainloop->api, r, r->userdata);
420
421 g_source_unref(&r->source);
422 }
423 }
424
425 static void free_time_events(struct pa_time_event *e) {
426 while (e) {
427 struct pa_time_event *r = e;
428 e = r->next;
429
430 if (r->source) {
431 g_source_destroy(r->source);
432 g_source_unref(r->source);
433 }
434
435 if (r->destroy_callback)
436 r->destroy_callback(&r->mainloop->api, r, r->userdata);
437
438 pa_xfree(r);
439 }
440 }
441
442 static void free_defer_events(struct pa_defer_event *e) {
443 while (e) {
444 struct pa_defer_event *r = e;
445 e = r->next;
446
447 if (r->source) {
448 g_source_destroy(r->source);
449 g_source_unref(r->source);
450 }
451
452 if (r->destroy_callback)
453 r->destroy_callback(&r->mainloop->api, r, r->userdata);
454
455 pa_xfree(r);
456 }
457 }
458
459 void pa_glib_mainloop_free(struct pa_glib_mainloop* g) {
460 assert(g);
461
462 free_io_events(g->io_events);
463 free_io_events(g->dead_io_events);
464 free_defer_events(g->defer_events);
465 free_defer_events(g->dead_defer_events);
466 free_time_events(g->time_events);
467 free_time_events(g->dead_time_events);
468
469 g_main_loop_unref(g->glib_mainloop);
470 pa_xfree(g);
471 }
472
473 struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g) {
474 assert(g);
475 return &g->api;
476 }
477
478 static gboolean free_dead_events(gpointer p) {
479 struct pa_glib_mainloop *g = p;
480 assert(g);
481
482 free_io_events(g->dead_io_events);
483 free_defer_events(g->dead_defer_events);
484 free_time_events(g->dead_time_events);
485
486 g_source_destroy(g->cleanup_source);
487 g_source_unref(g->cleanup_source);
488 g->cleanup_source = NULL;
489
490 return FALSE;
491 }
492
493 static void schedule_free_dead_events(struct pa_glib_mainloop *g) {
494 assert(g && g->glib_mainloop);
495
496 if (g->cleanup_source)
497 return;
498
499 g->cleanup_source = g_idle_source_new();
500 assert(g->cleanup_source);
501 g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL);
502 g_source_attach(g->cleanup_source, g_main_loop_get_context(g->glib_mainloop));
503 }