2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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.
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.
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
26 #include <pulse/xmalloc.h>
27 #include <pulse/timeval.h>
29 #include <pulsecore/idxset.h>
30 #include <pulsecore/core-util.h>
31 #include <pulsecore/log.h>
32 #include <pulsecore/llist.h>
35 #include "glib-mainloop.h"
38 pa_glib_mainloop
*mainloop
;
44 pa_io_event_cb_t callback
;
46 pa_io_event_destroy_cb_t destroy_callback
;
48 PA_LLIST_FIELDS(pa_io_event
);
51 struct pa_time_event
{
52 pa_glib_mainloop
*mainloop
;
56 struct timeval timeval
;
58 pa_time_event_cb_t callback
;
60 pa_time_event_destroy_cb_t destroy_callback
;
62 PA_LLIST_FIELDS(pa_time_event
);
65 struct pa_defer_event
{
66 pa_glib_mainloop
*mainloop
;
71 pa_defer_event_cb_t callback
;
73 pa_defer_event_destroy_cb_t destroy_callback
;
75 PA_LLIST_FIELDS(pa_defer_event
);
78 struct pa_glib_mainloop
{
82 GMainContext
*context
;
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
);
88 int n_enabled_defer_events
, n_enabled_time_events
;
89 int io_events_please_scan
, time_events_please_scan
, defer_events_please_scan
;
91 pa_time_event
*cached_next_time_event
;
94 static void cleanup_io_events(pa_glib_mainloop
*g
, int force
) {
99 pa_io_event
*n
= e
->next
;
101 if (!force
&& g
->io_events_please_scan
<= 0)
104 if (force
|| e
->dead
) {
105 PA_LLIST_REMOVE(pa_io_event
, g
->io_events
, e
);
108 g_assert(g
->io_events_please_scan
> 0);
109 g
->io_events_please_scan
--;
112 if (e
->poll_fd_added
)
113 g_source_remove_poll(&g
->source
, &e
->poll_fd
);
115 if (e
->destroy_callback
)
116 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
124 g_assert(g
->io_events_please_scan
== 0);
127 static void cleanup_time_events(pa_glib_mainloop
*g
, int force
) {
132 pa_time_event
*n
= e
->next
;
134 if (!force
&& g
->time_events_please_scan
<= 0)
137 if (force
|| e
->dead
) {
138 PA_LLIST_REMOVE(pa_time_event
, g
->time_events
, e
);
141 g_assert(g
->time_events_please_scan
> 0);
142 g
->time_events_please_scan
--;
145 if (!e
->dead
&& e
->enabled
) {
146 g_assert(g
->n_enabled_time_events
> 0);
147 g
->n_enabled_time_events
--;
150 if (e
->destroy_callback
)
151 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
159 g_assert(g
->time_events_please_scan
== 0);
162 static void cleanup_defer_events(pa_glib_mainloop
*g
, int force
) {
167 pa_defer_event
*n
= e
->next
;
169 if (!force
&& g
->defer_events_please_scan
<= 0)
172 if (force
|| e
->dead
) {
173 PA_LLIST_REMOVE(pa_defer_event
, g
->defer_events
, e
);
176 g_assert(g
->defer_events_please_scan
> 0);
177 g
->defer_events_please_scan
--;
180 if (!e
->dead
&& e
->enabled
) {
181 g_assert(g
->n_enabled_defer_events
> 0);
182 g
->n_enabled_defer_events
--;
185 if (e
->destroy_callback
)
186 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
194 g_assert(g
->defer_events_please_scan
== 0);
197 static gushort
map_flags_to_glib(pa_io_event_flags_t flags
) {
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));
205 static pa_io_event_flags_t
map_flags_from_glib(gushort flags
) {
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);
213 static pa_io_event
* glib_io_new(
216 pa_io_event_flags_t f
,
224 g_assert(m
->userdata
);
230 e
= pa_xnew(pa_io_event
, 1);
235 e
->poll_fd
.events
= map_flags_to_glib(f
);
236 e
->poll_fd
.revents
= 0;
239 e
->userdata
= userdata
;
240 e
->destroy_callback
= NULL
;
242 PA_LLIST_PREPEND(pa_io_event
, g
->io_events
, e
);
244 g_source_add_poll(&g
->source
, &e
->poll_fd
);
245 e
->poll_fd_added
= 1;
250 static void glib_io_enable(pa_io_event
*e
, pa_io_event_flags_t f
) {
254 e
->poll_fd
.events
= map_flags_to_glib(f
);
257 static void glib_io_free(pa_io_event
*e
) {
262 e
->mainloop
->io_events_please_scan
++;
264 if (e
->poll_fd_added
) {
265 g_source_remove_poll(&e
->mainloop
->source
, &e
->poll_fd
);
266 e
->poll_fd_added
= 0;
270 static void glib_io_set_destroy(pa_io_event
*e
, pa_io_event_destroy_cb_t cb
) {
274 e
->destroy_callback
= cb
;
279 static pa_time_event
* glib_time_new(
281 const struct timeval
*tv
,
282 pa_time_event_cb_t cb
,
289 g_assert(m
->userdata
);
294 e
= pa_xnew(pa_time_event
, 1);
298 if ((e
->enabled
= !!tv
)) {
300 g
->n_enabled_time_events
++;
302 if (g
->cached_next_time_event
) {
303 g_assert(g
->cached_next_time_event
->enabled
);
305 if (pa_timeval_cmp(tv
, &g
->cached_next_time_event
->timeval
) < 0)
306 g
->cached_next_time_event
= e
;
311 e
->userdata
= userdata
;
312 e
->destroy_callback
= NULL
;
314 PA_LLIST_PREPEND(pa_time_event
, g
->time_events
, e
);
319 static void glib_time_restart(pa_time_event
*e
, const struct timeval
*tv
) {
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
++;
329 if ((e
->enabled
= !!tv
))
332 if (e
->mainloop
->cached_next_time_event
&& e
->enabled
) {
333 g_assert(e
->mainloop
->cached_next_time_event
->enabled
);
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
;
341 static void glib_time_free(pa_time_event
*e
) {
346 e
->mainloop
->time_events_please_scan
++;
349 e
->mainloop
->n_enabled_time_events
--;
351 if (e
->mainloop
->cached_next_time_event
== e
)
352 e
->mainloop
->cached_next_time_event
= NULL
;
355 static void glib_time_set_destroy(pa_time_event
*e
, pa_time_event_destroy_cb_t cb
) {
359 e
->destroy_callback
= cb
;
362 /* Deferred sources */
364 static pa_defer_event
* glib_defer_new(
366 pa_defer_event_cb_t cb
,
373 g_assert(m
->userdata
);
378 e
= pa_xnew(pa_defer_event
, 1);
383 g
->n_enabled_defer_events
++;
386 e
->userdata
= userdata
;
387 e
->destroy_callback
= NULL
;
389 PA_LLIST_PREPEND(pa_defer_event
, g
->defer_events
, e
);
393 static void glib_defer_enable(pa_defer_event
*e
, int b
) {
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
++;
406 static void glib_defer_free(pa_defer_event
*e
) {
411 e
->mainloop
->defer_events_please_scan
++;
414 g_assert(e
->mainloop
->n_enabled_defer_events
> 0);
415 e
->mainloop
->n_enabled_defer_events
--;
419 static void glib_defer_set_destroy(pa_defer_event
*e
, pa_defer_event_destroy_cb_t cb
) {
423 e
->destroy_callback
= cb
;
428 static void glib_quit(pa_mainloop_api
*a
, int retval
) {
430 g_warning("quit() ignored");
435 static pa_time_event
* find_next_time_event(pa_glib_mainloop
*g
) {
436 pa_time_event
*t
, *n
= NULL
;
439 if (g
->cached_next_time_event
)
440 return g
->cached_next_time_event
;
442 for (t
= g
->time_events
; t
; t
= t
->next
) {
444 if (t
->dead
|| !t
->enabled
)
447 if (!n
|| pa_timeval_cmp(&t
->timeval
, &n
->timeval
) < 0) {
450 /* Shortcut for tv = { 0, 0 } */
451 if (n
->timeval
.tv_sec
<= 0)
456 g
->cached_next_time_event
= n
;
460 static void scan_dead(pa_glib_mainloop
*g
) {
463 if (g
->io_events_please_scan
)
464 cleanup_io_events(g
, 0);
466 if (g
->time_events_please_scan
)
467 cleanup_time_events(g
, 0);
469 if (g
->defer_events_please_scan
)
470 cleanup_defer_events(g
, 0);
473 static gboolean
prepare_func(GSource
*source
, gint
*timeout
) {
474 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
481 if (g
->n_enabled_defer_events
) {
484 } else if (g
->n_enabled_time_events
) {
487 struct timeval tvnow
;
490 t
= find_next_time_event(g
);
493 g_source_get_current_time(source
, &now
);
494 tvnow
.tv_sec
= now
.tv_sec
;
495 tvnow
.tv_usec
= now
.tv_usec
;
497 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
501 usec
= pa_timeval_diff(&t
->timeval
, &tvnow
);
502 *timeout
= (gint
) (usec
/ 1000);
508 static gboolean
check_func(GSource
*source
) {
509 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
514 if (g
->n_enabled_defer_events
)
516 else if (g
->n_enabled_time_events
) {
519 struct timeval tvnow
;
521 t
= find_next_time_event(g
);
524 g_source_get_current_time(source
, &now
);
525 tvnow
.tv_sec
= now
.tv_sec
;
526 tvnow
.tv_usec
= now
.tv_usec
;
528 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0)
532 for (e
= g
->io_events
; e
; e
= e
->next
)
533 if (!e
->dead
&& e
->poll_fd
.revents
!= 0)
539 static gboolean
dispatch_func(GSource
*source
, GSourceFunc callback
, gpointer userdata
) {
540 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
545 if (g
->n_enabled_defer_events
) {
548 for (d
= g
->defer_events
; d
; d
= d
->next
) {
549 if (d
->dead
|| !d
->enabled
)
557 d
->callback(&g
->api
, d
, d
->userdata
);
561 if (g
->n_enabled_time_events
) {
563 struct timeval tvnow
;
566 t
= find_next_time_event(g
);
569 g_source_get_current_time(source
, &now
);
570 tvnow
.tv_sec
= now
.tv_sec
;
571 tvnow
.tv_usec
= now
.tv_usec
;
573 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
575 /* Disable time event */
576 glib_time_restart(t
, NULL
);
578 t
->callback(&g
->api
, t
, &t
->timeval
, t
->userdata
);
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;
593 static const pa_mainloop_api vtable
= {
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
,
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
,
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
,
614 pa_glib_mainloop
*pa_glib_mainloop_new(GMainContext
*c
) {
617 static GSourceFuncs source_funcs
= {
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());
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
);
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;
639 g
->cached_next_time_event
= NULL
;
641 g_source_attach(&g
->source
, g
->context
);
642 g_source_set_can_recurse(&g
->source
, FALSE
);
647 void pa_glib_mainloop_free(pa_glib_mainloop
* g
) {
650 cleanup_io_events(g
, 1);
651 cleanup_defer_events(g
, 1);
652 cleanup_time_events(g
, 1);
654 g_main_context_unref(g
->context
);
655 g_source_destroy(&g
->source
);
656 g_source_unref(&g
->source
);
659 pa_mainloop_api
* pa_glib_mainloop_get_api(pa_glib_mainloop
*g
) {