3 #include "glib-mainloop.h"
8 struct pa_glib_mainloop
*mainloop
;
10 GIOChannel
*io_channel
;
12 GIOCondition io_condition
;
14 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_io_event
*e
, int fd
, enum pa_io_event_flags f
, 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
;
20 struct pa_time_event
{
21 struct pa_glib_mainloop
*mainloop
;
24 struct timeval timeval
;
25 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_time_event
*e
, const struct timeval
*tv
, 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
;
31 struct pa_defer_event
{
32 struct pa_glib_mainloop
*mainloop
;
35 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_defer_event
*e
, 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
;
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
;
50 static void schedule_free_dead_events(struct pa_glib_mainloop
*g
);
52 static void glib_io_enable(struct pa_io_event
*e
, enum pa_io_event_flags f
);
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
;
58 assert(m
&& m
->userdata
&& fd
>= 0 && callback
);
61 e
= pa_xmalloc(sizeof(struct pa_io_event
));
62 e
->mainloop
= m
->userdata
;
65 e
->callback
= callback
;
66 e
->userdata
= userdata
;
67 e
->destroy_callback
= NULL
;
69 e
->io_channel
= g_io_channel_unix_new(e
->fd
);
70 assert(e
->io_channel
);
76 e
->next
= g
->io_events
;
77 if (e
->next
) e
->next
->prev
= e
;
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
);
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);
94 e
->callback(&e
->mainloop
->api
, e
, e
->fd
, f
, e
->userdata
);
98 static void glib_io_enable(struct pa_io_event
*e
, enum pa_io_event_flags f
) {
100 assert(e
&& !e
->dead
);
102 c
= (f
& PA_IO_EVENT_INPUT
? G_IO_IN
: 0) | (f
& PA_IO_EVENT_OUTPUT
? G_IO_OUT
: 0);
104 if (c
== e
->io_condition
)
108 g_source_destroy(e
->source
);
109 g_source_unref(e
->source
);
112 e
->source
= g_io_create_watch(e
->io_channel
, c
| G_IO_ERR
| G_IO_HUP
);
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
);
122 static void glib_io_free(struct pa_io_event
*e
) {
123 assert(e
&& !e
->dead
);
126 g_source_destroy(e
->source
);
127 g_source_unref(e
->source
);
132 e
->prev
->next
= e
->next
;
134 e
->mainloop
->io_events
= e
->next
;
137 e
->next
->prev
= e
->prev
;
139 if ((e
->next
= e
->mainloop
->dead_io_events
))
142 e
->mainloop
->dead_io_events
= e
;
146 schedule_free_dead_events(e
->mainloop
);
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
)) {
151 e
->destroy_callback
= callback
;
156 static void glib_time_restart(struct pa_time_event
*e
, const struct timeval
*tv
);
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
;
162 assert(m
&& m
->userdata
&& tv
&& callback
);
165 e
= pa_xmalloc(sizeof(struct pa_time_event
));
168 e
->callback
= callback
;
169 e
->userdata
= userdata
;
170 e
->destroy_callback
= NULL
;
173 glib_time_restart(e
, tv
);
175 e
->next
= g
->time_events
;
176 if (e
->next
) e
->next
->prev
= e
;
183 static guint
msec_diff(const struct timeval
*a
, const struct timeval
*b
) {
187 if (a
->tv_sec
< b
->tv_sec
)
190 if (a
->tv_sec
== b
->tv_sec
&& a
->tv_sec
<= b
->tv_sec
)
193 r
= (a
->tv_sec
-b
->tv_sec
)*1000;
195 if (a
->tv_usec
>= b
->tv_usec
)
196 r
+= (a
->tv_usec
- b
->tv_usec
) / 1000;
198 r
-= (b
->tv_usec
- a
->tv_usec
) / 1000;
203 static gboolean
time_cb(gpointer data
) {
204 struct pa_time_event
* e
= data
;
205 assert(e
&& e
->mainloop
&& e
->source
);
207 g_source_unref(e
->source
);
210 e
->callback(&e
->mainloop
->api
, e
, &e
->timeval
, e
->userdata
);
214 static void glib_time_restart(struct pa_time_event
*e
, const struct timeval
*tv
) {
216 assert(e
&& e
->mainloop
);
218 gettimeofday(&now
, NULL
);
220 g_source_destroy(e
->source
);
221 g_source_unref(e
->source
);
226 e
->source
= g_timeout_source_new(msec_diff(tv
, &now
));
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
);
235 static void glib_time_free(struct pa_time_event
*e
) {
236 assert(e
&& e
->mainloop
);
239 g_source_destroy(e
->source
);
240 g_source_unref(e
->source
);
245 e
->prev
->next
= e
->next
;
247 e
->mainloop
->time_events
= e
->next
;
250 e
->next
->prev
= e
->prev
;
252 if ((e
->next
= e
->mainloop
->dead_time_events
))
255 e
->mainloop
->dead_time_events
= e
;
259 schedule_free_dead_events(e
->mainloop
);
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
)) {
264 e
->destroy_callback
= callback
;
267 /* Deferred sources */
269 static void glib_defer_enable(struct pa_defer_event
*e
, int b
);
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
;
275 assert(m
&& m
->userdata
&& callback
);
278 e
= pa_xmalloc(sizeof(struct pa_defer_event
));
281 e
->callback
= callback
;
282 e
->userdata
= userdata
;
283 e
->destroy_callback
= NULL
;
286 glib_defer_enable(e
, 1);
288 e
->next
= g
->defer_events
;
289 if (e
->next
) e
->next
->prev
= e
;
295 static gboolean
idle_cb(gpointer data
) {
296 struct pa_defer_event
* e
= data
;
297 assert(e
&& e
->mainloop
&& e
->source
);
299 e
->callback(&e
->mainloop
->api
, e
, e
->userdata
);
303 static void glib_defer_enable(struct pa_defer_event
*e
, int b
) {
304 assert(e
&& e
->mainloop
);
306 if (e
->source
&& !b
) {
307 g_source_destroy(e
->source
);
308 g_source_unref(e
->source
);
310 } else if (!e
->source
&& b
) {
311 e
->source
= g_idle_source_new();
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
);
319 static void glib_defer_free(struct pa_defer_event
*e
) {
320 assert(e
&& e
->mainloop
);
323 g_source_destroy(e
->source
);
324 g_source_unref(e
->source
);
329 e
->prev
->next
= e
->next
;
331 e
->mainloop
->defer_events
= e
->next
;
334 e
->next
->prev
= e
->prev
;
336 if ((e
->next
= e
->mainloop
->dead_defer_events
))
339 e
->mainloop
->dead_defer_events
= e
;
343 schedule_free_dead_events(e
->mainloop
);
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
)) {
348 e
->destroy_callback
= callback
;
353 static void glib_quit(struct pa_mainloop_api
*a
, int retval
) {
354 struct pa_glib_mainloop
*g
;
355 assert(a
&& a
->userdata
);
361 static const struct pa_mainloop_api vtable
= {
365 io_enable
: glib_io_enable
,
366 io_free
: glib_io_free
,
367 io_set_destroy
: glib_io_set_destroy
,
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
,
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
,
382 struct pa_glib_mainloop
*pa_glib_mainloop_new(GMainContext
*c
) {
383 struct pa_glib_mainloop
*g
;
385 g
= pa_xmalloc(sizeof(struct pa_glib_mainloop
));
387 g
->glib_main_context
= c
;
388 g_main_context_ref(c
);
390 g
->glib_main_context
= g_main_context_default();
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
;
399 g
->cleanup_source
= NULL
;
403 static void free_io_events(struct pa_io_event
*e
) {
405 struct pa_io_event
*r
= e
;
409 g_source_destroy(r
->source
);
410 g_source_unref(r
->source
);
414 g_io_channel_unref(r
->io_channel
);
416 if (r
->destroy_callback
)
417 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
423 static void free_time_events(struct pa_time_event
*e
) {
425 struct pa_time_event
*r
= e
;
429 g_source_destroy(r
->source
);
430 g_source_unref(r
->source
);
433 if (r
->destroy_callback
)
434 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
440 static void free_defer_events(struct pa_defer_event
*e
) {
442 struct pa_defer_event
*r
= e
;
446 g_source_destroy(r
->source
);
447 g_source_unref(r
->source
);
450 if (r
->destroy_callback
)
451 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
457 void pa_glib_mainloop_free(struct pa_glib_mainloop
* g
) {
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
);
467 if (g
->cleanup_source
) {
468 g_source_destroy(g
->cleanup_source
);
469 g_source_unref(g
->cleanup_source
);
472 g_main_context_unref(g
->glib_main_context
);
476 struct pa_mainloop_api
* pa_glib_mainloop_get_api(struct pa_glib_mainloop
*g
) {
481 static gboolean
free_dead_events(gpointer p
) {
482 struct pa_glib_mainloop
*g
= p
;
485 free_io_events(g
->dead_io_events
);
486 free_defer_events(g
->dead_defer_events
);
487 free_time_events(g
->dead_time_events
);
489 g_source_destroy(g
->cleanup_source
);
490 g_source_unref(g
->cleanup_source
);
491 g
->cleanup_source
= NULL
;
496 static void schedule_free_dead_events(struct pa_glib_mainloop
*g
) {
497 assert(g
&& g
->glib_main_context
);
499 if (g
->cleanup_source
)
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
);