4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/xmalloc.h>
31 #include <pulse/timeval.h>
33 #include <pulsecore/idxset.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/llist.h>
39 #include "glib-mainloop.h"
42 pa_glib_mainloop
*mainloop
;
48 pa_io_event_cb_t callback
;
50 pa_io_event_destroy_cb_t destroy_callback
;
52 PA_LLIST_FIELDS(pa_io_event
);
55 struct pa_time_event
{
56 pa_glib_mainloop
*mainloop
;
60 struct timeval timeval
;
62 pa_time_event_cb_t callback
;
64 pa_time_event_destroy_cb_t destroy_callback
;
66 PA_LLIST_FIELDS(pa_time_event
);
69 struct pa_defer_event
{
70 pa_glib_mainloop
*mainloop
;
75 pa_defer_event_cb_t callback
;
77 pa_defer_event_destroy_cb_t destroy_callback
;
79 PA_LLIST_FIELDS(pa_defer_event
);
82 struct pa_glib_mainloop
{
86 GMainContext
*context
;
88 PA_LLIST_HEAD(pa_io_event
, io_events
);
89 PA_LLIST_HEAD(pa_time_event
, time_events
);
90 PA_LLIST_HEAD(pa_defer_event
, defer_events
);
92 int n_enabled_defer_events
, n_enabled_time_events
;
93 int io_events_please_scan
, time_events_please_scan
, defer_events_please_scan
;
95 pa_time_event
*cached_next_time_event
;
98 static void cleanup_io_events(pa_glib_mainloop
*g
, int force
) {
103 pa_io_event
*n
= e
->next
;
105 if (!force
&& g
->io_events_please_scan
<= 0)
108 if (force
|| e
->dead
) {
109 PA_LLIST_REMOVE(pa_io_event
, g
->io_events
, e
);
112 g_assert(g
->io_events_please_scan
> 0);
113 g
->io_events_please_scan
--;
116 if (e
->poll_fd_added
)
117 g_source_remove_poll(&g
->source
, &e
->poll_fd
);
119 if (e
->destroy_callback
)
120 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
128 g_assert(g
->io_events_please_scan
== 0);
131 static void cleanup_time_events(pa_glib_mainloop
*g
, int force
) {
136 pa_time_event
*n
= e
->next
;
138 if (!force
&& g
->time_events_please_scan
<= 0)
141 if (force
|| e
->dead
) {
142 PA_LLIST_REMOVE(pa_time_event
, g
->time_events
, e
);
145 g_assert(g
->time_events_please_scan
> 0);
146 g
->time_events_please_scan
--;
149 if (!e
->dead
&& e
->enabled
) {
150 g_assert(g
->n_enabled_time_events
> 0);
151 g
->n_enabled_time_events
--;
154 if (e
->destroy_callback
)
155 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
163 g_assert(g
->time_events_please_scan
== 0);
166 static void cleanup_defer_events(pa_glib_mainloop
*g
, int force
) {
171 pa_defer_event
*n
= e
->next
;
173 if (!force
&& g
->defer_events_please_scan
<= 0)
176 if (force
|| e
->dead
) {
177 PA_LLIST_REMOVE(pa_defer_event
, g
->defer_events
, e
);
180 g_assert(g
->defer_events_please_scan
> 0);
181 g
->defer_events_please_scan
--;
184 if (!e
->dead
&& e
->enabled
) {
185 g_assert(g
->n_enabled_defer_events
> 0);
186 g
->n_enabled_defer_events
--;
189 if (e
->destroy_callback
)
190 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
198 g_assert(g
->defer_events_please_scan
== 0);
201 static gushort
map_flags_to_glib(pa_io_event_flags_t flags
) {
203 (flags
& PA_IO_EVENT_INPUT
? G_IO_IN
: 0) |
204 (flags
& PA_IO_EVENT_OUTPUT
? G_IO_OUT
: 0) |
205 (flags
& PA_IO_EVENT_ERROR
? G_IO_ERR
: 0) |
206 (flags
& PA_IO_EVENT_HANGUP
? G_IO_HUP
: 0);
209 static pa_io_event_flags_t
map_flags_from_glib(gushort flags
) {
211 (flags
& G_IO_IN
? PA_IO_EVENT_INPUT
: 0) |
212 (flags
& G_IO_OUT
? PA_IO_EVENT_OUTPUT
: 0) |
213 (flags
& G_IO_ERR
? PA_IO_EVENT_ERROR
: 0) |
214 (flags
& G_IO_HUP
? PA_IO_EVENT_HANGUP
: 0);
217 static pa_io_event
* glib_io_new(
220 pa_io_event_flags_t f
,
228 g_assert(m
->userdata
);
234 e
= pa_xnew(pa_io_event
, 1);
239 e
->poll_fd
.events
= map_flags_to_glib(f
);
240 e
->poll_fd
.revents
= 0;
243 e
->userdata
= userdata
;
244 e
->destroy_callback
= NULL
;
246 PA_LLIST_PREPEND(pa_io_event
, g
->io_events
, e
);
248 g_source_add_poll(&g
->source
, &e
->poll_fd
);
249 e
->poll_fd_added
= 1;
254 static void glib_io_enable(pa_io_event
*e
, pa_io_event_flags_t f
) {
258 e
->poll_fd
.events
= map_flags_to_glib(f
);
261 static void glib_io_free(pa_io_event
*e
) {
266 e
->mainloop
->io_events_please_scan
++;
268 if (e
->poll_fd_added
) {
269 g_source_remove_poll(&e
->mainloop
->source
, &e
->poll_fd
);
270 e
->poll_fd_added
= 0;
274 static void glib_io_set_destroy(pa_io_event
*e
, pa_io_event_destroy_cb_t cb
) {
278 e
->destroy_callback
= cb
;
283 static pa_time_event
* glib_time_new(
285 const struct timeval
*tv
,
286 pa_time_event_cb_t cb
,
293 g_assert(m
->userdata
);
298 e
= pa_xnew(pa_time_event
, 1);
302 if ((e
->enabled
= !!tv
)) {
304 g
->n_enabled_time_events
++;
306 if (g
->cached_next_time_event
) {
307 g_assert(g
->cached_next_time_event
->enabled
);
309 if (pa_timeval_cmp(tv
, &g
->cached_next_time_event
->timeval
) < 0)
310 g
->cached_next_time_event
= e
;
315 e
->userdata
= userdata
;
316 e
->destroy_callback
= NULL
;
318 PA_LLIST_PREPEND(pa_time_event
, g
->time_events
, e
);
323 static void glib_time_restart(pa_time_event
*e
, const struct timeval
*tv
) {
327 if (e
->enabled
&& !tv
) {
328 g_assert(e
->mainloop
->n_enabled_time_events
> 0);
329 e
->mainloop
->n_enabled_time_events
--;
330 } else if (!e
->enabled
&& tv
)
331 e
->mainloop
->n_enabled_time_events
++;
333 if ((e
->enabled
= !!tv
))
336 if (e
->mainloop
->cached_next_time_event
&& e
->enabled
) {
337 g_assert(e
->mainloop
->cached_next_time_event
->enabled
);
339 if (pa_timeval_cmp(tv
, &e
->mainloop
->cached_next_time_event
->timeval
) < 0)
340 e
->mainloop
->cached_next_time_event
= e
;
341 } else if (e
->mainloop
->cached_next_time_event
== e
)
342 e
->mainloop
->cached_next_time_event
= NULL
;
345 static void glib_time_free(pa_time_event
*e
) {
350 e
->mainloop
->time_events_please_scan
++;
353 e
->mainloop
->n_enabled_time_events
--;
355 if (e
->mainloop
->cached_next_time_event
== e
)
356 e
->mainloop
->cached_next_time_event
= NULL
;
359 static void glib_time_set_destroy(pa_time_event
*e
, pa_time_event_destroy_cb_t cb
) {
363 e
->destroy_callback
= cb
;
366 /* Deferred sources */
368 static pa_defer_event
* glib_defer_new(
370 pa_defer_event_cb_t cb
,
377 g_assert(m
->userdata
);
382 e
= pa_xnew(pa_defer_event
, 1);
387 g
->n_enabled_defer_events
++;
390 e
->userdata
= userdata
;
391 e
->destroy_callback
= NULL
;
393 PA_LLIST_PREPEND(pa_defer_event
, g
->defer_events
, e
);
397 static void glib_defer_enable(pa_defer_event
*e
, int b
) {
401 if (e
->enabled
&& !b
) {
402 g_assert(e
->mainloop
->n_enabled_defer_events
> 0);
403 e
->mainloop
->n_enabled_defer_events
--;
404 } else if (!e
->enabled
&& b
)
405 e
->mainloop
->n_enabled_defer_events
++;
410 static void glib_defer_free(pa_defer_event
*e
) {
415 e
->mainloop
->defer_events_please_scan
++;
418 g_assert(e
->mainloop
->n_enabled_defer_events
> 0);
419 e
->mainloop
->n_enabled_defer_events
--;
423 static void glib_defer_set_destroy(pa_defer_event
*e
, pa_defer_event_destroy_cb_t cb
) {
427 e
->destroy_callback
= cb
;
432 static void glib_quit(pa_mainloop_api
*a
, PA_GCC_UNUSED
int retval
) {
434 g_warning("quit() ignored");
439 static pa_time_event
* find_next_time_event(pa_glib_mainloop
*g
) {
440 pa_time_event
*t
, *n
= NULL
;
443 if (g
->cached_next_time_event
)
444 return g
->cached_next_time_event
;
446 for (t
= g
->time_events
; t
; t
= t
->next
) {
448 if (t
->dead
|| !t
->enabled
)
451 if (!n
|| pa_timeval_cmp(&t
->timeval
, &n
->timeval
) < 0) {
454 /* Shortcut for tv = { 0, 0 } */
455 if (n
->timeval
.tv_sec
<= 0)
460 g
->cached_next_time_event
= n
;
464 static void scan_dead(pa_glib_mainloop
*g
) {
467 if (g
->io_events_please_scan
)
468 cleanup_io_events(g
, 0);
470 if (g
->time_events_please_scan
)
471 cleanup_time_events(g
, 0);
473 if (g
->defer_events_please_scan
)
474 cleanup_defer_events(g
, 0);
477 static gboolean
prepare_func(GSource
*source
, gint
*timeout
) {
478 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
485 if (g
->n_enabled_defer_events
) {
488 } else if (g
->n_enabled_time_events
) {
491 struct timeval tvnow
;
494 t
= find_next_time_event(g
);
497 g_source_get_current_time(source
, &now
);
498 tvnow
.tv_sec
= now
.tv_sec
;
499 tvnow
.tv_usec
= now
.tv_usec
;
501 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
505 usec
= pa_timeval_diff(&t
->timeval
, &tvnow
);
506 *timeout
= (gint
) (usec
/ 1000);
512 static gboolean
check_func(GSource
*source
) {
513 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
518 if (g
->n_enabled_defer_events
)
520 else if (g
->n_enabled_time_events
) {
523 struct timeval tvnow
;
525 t
= find_next_time_event(g
);
528 g_source_get_current_time(source
, &now
);
529 tvnow
.tv_sec
= now
.tv_sec
;
530 tvnow
.tv_usec
= now
.tv_usec
;
532 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0)
536 for (e
= g
->io_events
; e
; e
= e
->next
)
537 if (!e
->dead
&& e
->poll_fd
.revents
!= 0)
543 static gboolean
dispatch_func(GSource
*source
, PA_GCC_UNUSED GSourceFunc callback
, PA_GCC_UNUSED gpointer userdata
) {
544 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
549 if (g
->n_enabled_defer_events
) {
552 for (d
= g
->defer_events
; d
; d
= d
->next
) {
553 if (d
->dead
|| !d
->enabled
)
561 d
->callback(&g
->api
, d
, d
->userdata
);
565 if (g
->n_enabled_time_events
) {
567 struct timeval tvnow
;
570 t
= find_next_time_event(g
);
573 g_source_get_current_time(source
, &now
);
574 tvnow
.tv_sec
= now
.tv_sec
;
575 tvnow
.tv_usec
= now
.tv_usec
;
577 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
579 /* Disable time event */
580 glib_time_restart(t
, NULL
);
582 t
->callback(&g
->api
, t
, &t
->timeval
, t
->userdata
);
587 for (e
= g
->io_events
; e
; e
= e
->next
)
588 if (!e
->dead
&& e
->poll_fd
.revents
!= 0) {
589 e
->callback(&g
->api
, e
, e
->poll_fd
.fd
, map_flags_from_glib(e
->poll_fd
.revents
), e
->userdata
);
590 e
->poll_fd
.revents
= 0;
597 static const pa_mainloop_api vtable
= {
600 .io_new
= glib_io_new
,
601 .io_enable
= glib_io_enable
,
602 .io_free
= glib_io_free
,
603 .io_set_destroy
= glib_io_set_destroy
,
605 .time_new
= glib_time_new
,
606 .time_restart
= glib_time_restart
,
607 .time_free
= glib_time_free
,
608 .time_set_destroy
= glib_time_set_destroy
,
610 .defer_new
= glib_defer_new
,
611 .defer_enable
= glib_defer_enable
,
612 .defer_free
= glib_defer_free
,
613 .defer_set_destroy
= glib_defer_set_destroy
,
618 pa_glib_mainloop
*pa_glib_mainloop_new(GMainContext
*c
) {
621 static GSourceFuncs source_funcs
= {
630 g
= (pa_glib_mainloop
*) g_source_new(&source_funcs
, sizeof(pa_glib_mainloop
));
631 g_main_context_ref(g
->context
= c
? c
: g_main_context_default());
636 PA_LLIST_HEAD_INIT(pa_io_event
, g
->io_events
);
637 PA_LLIST_HEAD_INIT(pa_time_event
, g
->time_events
);
638 PA_LLIST_HEAD_INIT(pa_defer_event
, g
->defer_events
);
640 g
->n_enabled_defer_events
= g
->n_enabled_time_events
= 0;
641 g
->io_events_please_scan
= g
->time_events_please_scan
= g
->defer_events_please_scan
= 0;
643 g
->cached_next_time_event
= NULL
;
645 g_source_attach(&g
->source
, g
->context
);
646 g_source_set_can_recurse(&g
->source
, FALSE
);
651 void pa_glib_mainloop_free(pa_glib_mainloop
* g
) {
654 cleanup_io_events(g
, 1);
655 cleanup_defer_events(g
, 1);
656 cleanup_time_events(g
, 1);
658 g_main_context_unref(g
->context
);
659 g_source_destroy(&g
->source
);
660 g_source_unref(&g
->source
);
663 pa_mainloop_api
* pa_glib_mainloop_get_api(pa_glib_mainloop
*g
) {