4 This file is part of PulseAudio.
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 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
28 #include <pulse/xmalloc.h>
29 #include <pulse/timeval.h>
31 #include <pulsecore/idxset.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/log.h>
34 #include <pulsecore/llist.h>
37 #include "glib-mainloop.h"
40 pa_glib_mainloop
*mainloop
;
46 pa_io_event_cb_t callback
;
48 pa_io_event_destroy_cb_t destroy_callback
;
50 PA_LLIST_FIELDS(pa_io_event
);
53 struct pa_time_event
{
54 pa_glib_mainloop
*mainloop
;
58 struct timeval timeval
;
60 pa_time_event_cb_t callback
;
62 pa_time_event_destroy_cb_t destroy_callback
;
64 PA_LLIST_FIELDS(pa_time_event
);
67 struct pa_defer_event
{
68 pa_glib_mainloop
*mainloop
;
73 pa_defer_event_cb_t callback
;
75 pa_defer_event_destroy_cb_t destroy_callback
;
77 PA_LLIST_FIELDS(pa_defer_event
);
80 struct pa_glib_mainloop
{
84 GMainContext
*context
;
86 PA_LLIST_HEAD(pa_io_event
, io_events
);
87 PA_LLIST_HEAD(pa_time_event
, time_events
);
88 PA_LLIST_HEAD(pa_defer_event
, defer_events
);
90 int n_enabled_defer_events
, n_enabled_time_events
;
91 int io_events_please_scan
, time_events_please_scan
, defer_events_please_scan
;
93 pa_time_event
*cached_next_time_event
;
96 static void cleanup_io_events(pa_glib_mainloop
*g
, int force
) {
101 pa_io_event
*n
= e
->next
;
103 if (!force
&& g
->io_events_please_scan
<= 0)
106 if (force
|| e
->dead
) {
107 PA_LLIST_REMOVE(pa_io_event
, g
->io_events
, e
);
110 g_assert(g
->io_events_please_scan
> 0);
111 g
->io_events_please_scan
--;
114 if (e
->poll_fd_added
)
115 g_source_remove_poll(&g
->source
, &e
->poll_fd
);
117 if (e
->destroy_callback
)
118 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
126 g_assert(g
->io_events_please_scan
== 0);
129 static void cleanup_time_events(pa_glib_mainloop
*g
, int force
) {
134 pa_time_event
*n
= e
->next
;
136 if (!force
&& g
->time_events_please_scan
<= 0)
139 if (force
|| e
->dead
) {
140 PA_LLIST_REMOVE(pa_time_event
, g
->time_events
, e
);
143 g_assert(g
->time_events_please_scan
> 0);
144 g
->time_events_please_scan
--;
147 if (!e
->dead
&& e
->enabled
) {
148 g_assert(g
->n_enabled_time_events
> 0);
149 g
->n_enabled_time_events
--;
152 if (e
->destroy_callback
)
153 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
161 g_assert(g
->time_events_please_scan
== 0);
164 static void cleanup_defer_events(pa_glib_mainloop
*g
, int force
) {
169 pa_defer_event
*n
= e
->next
;
171 if (!force
&& g
->defer_events_please_scan
<= 0)
174 if (force
|| e
->dead
) {
175 PA_LLIST_REMOVE(pa_defer_event
, g
->defer_events
, e
);
178 g_assert(g
->defer_events_please_scan
> 0);
179 g
->defer_events_please_scan
--;
182 if (!e
->dead
&& e
->enabled
) {
183 g_assert(g
->n_enabled_defer_events
> 0);
184 g
->n_enabled_defer_events
--;
187 if (e
->destroy_callback
)
188 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
196 g_assert(g
->defer_events_please_scan
== 0);
199 static gushort
map_flags_to_glib(pa_io_event_flags_t flags
) {
201 (flags
& PA_IO_EVENT_INPUT
? G_IO_IN
: 0) |
202 (flags
& PA_IO_EVENT_OUTPUT
? G_IO_OUT
: 0) |
203 (flags
& PA_IO_EVENT_ERROR
? G_IO_ERR
: 0) |
204 (flags
& PA_IO_EVENT_HANGUP
? G_IO_HUP
: 0);
207 static pa_io_event_flags_t
map_flags_from_glib(gushort flags
) {
209 (flags
& G_IO_IN
? PA_IO_EVENT_INPUT
: 0) |
210 (flags
& G_IO_OUT
? PA_IO_EVENT_OUTPUT
: 0) |
211 (flags
& G_IO_ERR
? PA_IO_EVENT_ERROR
: 0) |
212 (flags
& G_IO_HUP
? PA_IO_EVENT_HANGUP
: 0);
215 static pa_io_event
* glib_io_new(
218 pa_io_event_flags_t f
,
226 g_assert(m
->userdata
);
232 e
= pa_xnew(pa_io_event
, 1);
237 e
->poll_fd
.events
= map_flags_to_glib(f
);
238 e
->poll_fd
.revents
= 0;
241 e
->userdata
= userdata
;
242 e
->destroy_callback
= NULL
;
244 PA_LLIST_PREPEND(pa_io_event
, g
->io_events
, e
);
246 g_source_add_poll(&g
->source
, &e
->poll_fd
);
247 e
->poll_fd_added
= 1;
252 static void glib_io_enable(pa_io_event
*e
, pa_io_event_flags_t f
) {
256 e
->poll_fd
.events
= map_flags_to_glib(f
);
259 static void glib_io_free(pa_io_event
*e
) {
264 e
->mainloop
->io_events_please_scan
++;
266 if (e
->poll_fd_added
) {
267 g_source_remove_poll(&e
->mainloop
->source
, &e
->poll_fd
);
268 e
->poll_fd_added
= 0;
272 static void glib_io_set_destroy(pa_io_event
*e
, pa_io_event_destroy_cb_t cb
) {
276 e
->destroy_callback
= cb
;
281 static pa_time_event
* glib_time_new(
283 const struct timeval
*tv
,
284 pa_time_event_cb_t cb
,
291 g_assert(m
->userdata
);
296 e
= pa_xnew(pa_time_event
, 1);
300 if ((e
->enabled
= !!tv
)) {
302 g
->n_enabled_time_events
++;
304 if (g
->cached_next_time_event
) {
305 g_assert(g
->cached_next_time_event
->enabled
);
307 if (pa_timeval_cmp(tv
, &g
->cached_next_time_event
->timeval
) < 0)
308 g
->cached_next_time_event
= e
;
313 e
->userdata
= userdata
;
314 e
->destroy_callback
= NULL
;
316 PA_LLIST_PREPEND(pa_time_event
, g
->time_events
, e
);
321 static void glib_time_restart(pa_time_event
*e
, const struct timeval
*tv
) {
325 if (e
->enabled
&& !tv
) {
326 g_assert(e
->mainloop
->n_enabled_time_events
> 0);
327 e
->mainloop
->n_enabled_time_events
--;
328 } else if (!e
->enabled
&& tv
)
329 e
->mainloop
->n_enabled_time_events
++;
331 if ((e
->enabled
= !!tv
))
334 if (e
->mainloop
->cached_next_time_event
&& e
->enabled
) {
335 g_assert(e
->mainloop
->cached_next_time_event
->enabled
);
337 if (pa_timeval_cmp(tv
, &e
->mainloop
->cached_next_time_event
->timeval
) < 0)
338 e
->mainloop
->cached_next_time_event
= e
;
339 } else if (e
->mainloop
->cached_next_time_event
== e
)
340 e
->mainloop
->cached_next_time_event
= NULL
;
343 static void glib_time_free(pa_time_event
*e
) {
348 e
->mainloop
->time_events_please_scan
++;
351 e
->mainloop
->n_enabled_time_events
--;
353 if (e
->mainloop
->cached_next_time_event
== e
)
354 e
->mainloop
->cached_next_time_event
= NULL
;
357 static void glib_time_set_destroy(pa_time_event
*e
, pa_time_event_destroy_cb_t cb
) {
361 e
->destroy_callback
= cb
;
364 /* Deferred sources */
366 static pa_defer_event
* glib_defer_new(
368 pa_defer_event_cb_t cb
,
375 g_assert(m
->userdata
);
380 e
= pa_xnew(pa_defer_event
, 1);
385 g
->n_enabled_defer_events
++;
388 e
->userdata
= userdata
;
389 e
->destroy_callback
= NULL
;
391 PA_LLIST_PREPEND(pa_defer_event
, g
->defer_events
, e
);
395 static void glib_defer_enable(pa_defer_event
*e
, int b
) {
399 if (e
->enabled
&& !b
) {
400 g_assert(e
->mainloop
->n_enabled_defer_events
> 0);
401 e
->mainloop
->n_enabled_defer_events
--;
402 } else if (!e
->enabled
&& b
)
403 e
->mainloop
->n_enabled_defer_events
++;
408 static void glib_defer_free(pa_defer_event
*e
) {
413 e
->mainloop
->defer_events_please_scan
++;
416 g_assert(e
->mainloop
->n_enabled_defer_events
> 0);
417 e
->mainloop
->n_enabled_defer_events
--;
421 static void glib_defer_set_destroy(pa_defer_event
*e
, pa_defer_event_destroy_cb_t cb
) {
425 e
->destroy_callback
= cb
;
430 static void glib_quit(pa_mainloop_api
*a
, PA_GCC_UNUSED
int retval
) {
432 g_warning("quit() ignored");
437 static pa_time_event
* find_next_time_event(pa_glib_mainloop
*g
) {
438 pa_time_event
*t
, *n
= NULL
;
441 if (g
->cached_next_time_event
)
442 return g
->cached_next_time_event
;
444 for (t
= g
->time_events
; t
; t
= t
->next
) {
446 if (t
->dead
|| !t
->enabled
)
449 if (!n
|| pa_timeval_cmp(&t
->timeval
, &n
->timeval
) < 0) {
452 /* Shortcut for tv = { 0, 0 } */
453 if (n
->timeval
.tv_sec
<= 0)
458 g
->cached_next_time_event
= n
;
462 static void scan_dead(pa_glib_mainloop
*g
) {
465 if (g
->io_events_please_scan
)
466 cleanup_io_events(g
, 0);
468 if (g
->time_events_please_scan
)
469 cleanup_time_events(g
, 0);
471 if (g
->defer_events_please_scan
)
472 cleanup_defer_events(g
, 0);
475 static gboolean
prepare_func(GSource
*source
, gint
*timeout
) {
476 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
483 if (g
->n_enabled_defer_events
) {
486 } else if (g
->n_enabled_time_events
) {
489 struct timeval tvnow
;
492 t
= find_next_time_event(g
);
495 g_source_get_current_time(source
, &now
);
496 tvnow
.tv_sec
= now
.tv_sec
;
497 tvnow
.tv_usec
= now
.tv_usec
;
499 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
503 usec
= pa_timeval_diff(&t
->timeval
, &tvnow
);
504 *timeout
= (gint
) (usec
/ 1000);
510 static gboolean
check_func(GSource
*source
) {
511 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
516 if (g
->n_enabled_defer_events
)
518 else if (g
->n_enabled_time_events
) {
521 struct timeval tvnow
;
523 t
= find_next_time_event(g
);
526 g_source_get_current_time(source
, &now
);
527 tvnow
.tv_sec
= now
.tv_sec
;
528 tvnow
.tv_usec
= now
.tv_usec
;
530 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0)
534 for (e
= g
->io_events
; e
; e
= e
->next
)
535 if (!e
->dead
&& e
->poll_fd
.revents
!= 0)
541 static gboolean
dispatch_func(GSource
*source
, PA_GCC_UNUSED GSourceFunc callback
, PA_GCC_UNUSED gpointer userdata
) {
542 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
547 if (g
->n_enabled_defer_events
) {
550 for (d
= g
->defer_events
; d
; d
= d
->next
) {
551 if (d
->dead
|| !d
->enabled
)
559 d
->callback(&g
->api
, d
, d
->userdata
);
563 if (g
->n_enabled_time_events
) {
565 struct timeval tvnow
;
568 t
= find_next_time_event(g
);
571 g_source_get_current_time(source
, &now
);
572 tvnow
.tv_sec
= now
.tv_sec
;
573 tvnow
.tv_usec
= now
.tv_usec
;
575 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0) {
577 t
->callback(&g
->api
, t
, &t
->timeval
, t
->userdata
);
582 for (e
= g
->io_events
; e
; e
= e
->next
)
583 if (!e
->dead
&& e
->poll_fd
.revents
!= 0) {
584 e
->callback(&g
->api
, e
, e
->poll_fd
.fd
, map_flags_from_glib(e
->poll_fd
.revents
), e
->userdata
);
585 e
->poll_fd
.revents
= 0;
592 static const pa_mainloop_api vtable
= {
595 .io_new
= glib_io_new
,
596 .io_enable
= glib_io_enable
,
597 .io_free
= glib_io_free
,
598 .io_set_destroy
= glib_io_set_destroy
,
600 .time_new
= glib_time_new
,
601 .time_restart
= glib_time_restart
,
602 .time_free
= glib_time_free
,
603 .time_set_destroy
= glib_time_set_destroy
,
605 .defer_new
= glib_defer_new
,
606 .defer_enable
= glib_defer_enable
,
607 .defer_free
= glib_defer_free
,
608 .defer_set_destroy
= glib_defer_set_destroy
,
613 pa_glib_mainloop
*pa_glib_mainloop_new(GMainContext
*c
) {
616 static GSourceFuncs source_funcs
= {
625 g
= (pa_glib_mainloop
*) g_source_new(&source_funcs
, sizeof(pa_glib_mainloop
));
626 g_main_context_ref(g
->context
= c
? c
: g_main_context_default());
631 PA_LLIST_HEAD_INIT(pa_io_event
, g
->io_events
);
632 PA_LLIST_HEAD_INIT(pa_time_event
, g
->time_events
);
633 PA_LLIST_HEAD_INIT(pa_defer_event
, g
->defer_events
);
635 g
->n_enabled_defer_events
= g
->n_enabled_time_events
= 0;
636 g
->io_events_please_scan
= g
->time_events_please_scan
= g
->defer_events_please_scan
= 0;
638 g_source_attach(&g
->source
, g
->context
);
639 g_source_set_can_recurse(&g
->source
, FALSE
);
644 void pa_glib_mainloop_free(pa_glib_mainloop
* g
) {
647 cleanup_io_events(g
, 1);
648 cleanup_defer_events(g
, 1);
649 cleanup_time_events(g
, 1);
651 g_main_context_unref(g
->context
);
652 g_source_destroy(&g
->source
);
653 g_source_unref(&g
->source
);
656 pa_mainloop_api
* pa_glib_mainloop_get_api(pa_glib_mainloop
*g
) {