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