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
->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 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
->time_events_please_scan
--;
143 if (!e
->dead
&& e
->enabled
)
144 g
->n_enabled_time_events
--;
146 if (e
->destroy_callback
)
147 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
155 assert(g
->time_events_please_scan
== 0);
158 static void cleanup_defer_events(pa_glib_mainloop
*g
, int force
) {
163 pa_defer_event
*n
= e
->next
;
165 if (!force
&& g
->defer_events_please_scan
<= 0)
168 if (force
|| e
->dead
) {
169 PA_LLIST_REMOVE(pa_defer_event
, g
->defer_events
, e
);
172 g
->defer_events_please_scan
--;
174 if (!e
->dead
&& e
->enabled
)
175 g
->n_enabled_defer_events
--;
177 if (e
->destroy_callback
)
178 e
->destroy_callback(&g
->api
, e
, e
->userdata
);
186 assert(g
->defer_events_please_scan
== 0);
189 static gushort
map_flags_to_glib(pa_io_event_flags_t flags
) {
191 (flags
& PA_IO_EVENT_INPUT
? G_IO_IN
: 0) |
192 (flags
& PA_IO_EVENT_OUTPUT
? G_IO_OUT
: 0) |
193 (flags
& PA_IO_EVENT_ERROR
? G_IO_ERR
: 0) |
194 (flags
& PA_IO_EVENT_HANGUP
? G_IO_HUP
: 0);
197 static pa_io_event_flags_t
map_flags_from_glib(gushort flags
) {
199 (flags
& G_IO_IN
? PA_IO_EVENT_INPUT
: 0) |
200 (flags
& G_IO_OUT
? PA_IO_EVENT_OUTPUT
: 0) |
201 (flags
& G_IO_ERR
? PA_IO_EVENT_ERROR
: 0) |
202 (flags
& G_IO_HUP
? PA_IO_EVENT_HANGUP
: 0);
205 static pa_io_event
* glib_io_new(
208 pa_io_event_flags_t f
,
222 e
= pa_xnew(pa_io_event
, 1);
227 e
->poll_fd
.events
= map_flags_to_glib(f
);
228 e
->poll_fd
.revents
= 0;
231 e
->userdata
= userdata
;
232 e
->destroy_callback
= NULL
;
234 PA_LLIST_PREPEND(pa_io_event
, g
->io_events
, e
);
236 g_source_add_poll(&g
->source
, &e
->poll_fd
);
237 e
->poll_fd_added
= 1;
242 static void glib_io_enable(pa_io_event
*e
, pa_io_event_flags_t f
) {
246 e
->poll_fd
.events
= map_flags_to_glib(f
);
249 static void glib_io_free(pa_io_event
*e
) {
254 e
->mainloop
->io_events_please_scan
++;
256 if (e
->poll_fd_added
) {
257 g_source_remove_poll(&e
->mainloop
->source
, &e
->poll_fd
);
258 e
->poll_fd_added
= 0;
262 static void glib_io_set_destroy(pa_io_event
*e
, pa_io_event_destroy_cb_t cb
) {
266 e
->destroy_callback
= cb
;
271 static pa_time_event
* glib_time_new(
273 const struct timeval
*tv
,
274 pa_time_event_cb_t cb
,
286 e
= pa_xnew(pa_time_event
, 1);
290 if ((e
->enabled
= !!tv
)) {
292 g
->n_enabled_time_events
++;
294 if (g
->cached_next_time_event
) {
295 g_assert(g
->cached_next_time_event
->enabled
);
297 if (pa_timeval_cmp(tv
, &g
->cached_next_time_event
->timeval
) < 0)
298 g
->cached_next_time_event
= e
;
303 e
->userdata
= userdata
;
304 e
->destroy_callback
= NULL
;
306 PA_LLIST_PREPEND(pa_time_event
, g
->time_events
, e
);
311 static void glib_time_restart(pa_time_event
*e
, const struct timeval
*tv
) {
315 if (e
->enabled
&& !!tv
)
316 e
->mainloop
->n_enabled_time_events
--;
317 else if (!e
->enabled
&& tv
)
318 e
->mainloop
->n_enabled_time_events
++;
320 if ((e
->enabled
= !!tv
))
323 if (e
->mainloop
->cached_next_time_event
&& e
->enabled
) {
324 g_assert(e
->mainloop
->cached_next_time_event
->enabled
);
326 if (pa_timeval_cmp(tv
, &e
->mainloop
->cached_next_time_event
->timeval
) < 0)
327 e
->mainloop
->cached_next_time_event
= e
;
328 } else if (e
->mainloop
->cached_next_time_event
== e
)
329 e
->mainloop
->cached_next_time_event
= NULL
;
332 static void glib_time_free(pa_time_event
*e
) {
337 e
->mainloop
->time_events_please_scan
++;
340 e
->mainloop
->n_enabled_time_events
--;
342 if (e
->mainloop
->cached_next_time_event
== e
)
343 e
->mainloop
->cached_next_time_event
= NULL
;
346 static void glib_time_set_destroy(pa_time_event
*e
, pa_time_event_destroy_cb_t cb
) {
350 e
->destroy_callback
= cb
;
353 /* Deferred sources */
355 static pa_defer_event
* glib_defer_new(
357 pa_defer_event_cb_t cb
,
369 e
= pa_xnew(pa_defer_event
, 1);
374 g
->n_enabled_defer_events
++;
377 e
->userdata
= userdata
;
378 e
->destroy_callback
= NULL
;
380 PA_LLIST_PREPEND(pa_defer_event
, g
->defer_events
, e
);
384 static void glib_defer_enable(pa_defer_event
*e
, int b
) {
388 if (e
->enabled
&& !b
)
389 e
->mainloop
->n_enabled_defer_events
--;
390 else if (!e
->enabled
&& b
)
391 e
->mainloop
->n_enabled_defer_events
++;
396 static void glib_defer_free(pa_defer_event
*e
) {
401 e
->mainloop
->defer_events_please_scan
++;
404 e
->mainloop
->n_enabled_defer_events
--;
407 static void glib_defer_set_destroy(pa_defer_event
*e
, pa_defer_event_destroy_cb_t cb
) {
411 e
->destroy_callback
= cb
;
416 static void glib_quit(pa_mainloop_api
*a
, PA_GCC_UNUSED
int retval
) {
418 g_warning("quit() ignored");
423 static pa_time_event
* find_next_time_event(pa_glib_mainloop
*g
) {
424 pa_time_event
*t
, *n
= NULL
;
427 if (g
->cached_next_time_event
)
428 return g
->cached_next_time_event
;
430 for (t
= g
->time_events
; t
; t
= t
->next
) {
432 if (t
->dead
|| !t
->enabled
)
435 if (!n
|| pa_timeval_cmp(&t
->timeval
, &n
->timeval
) < 0) {
438 /* Shortcut for tv = { 0, 0 } */
439 if (n
->timeval
.tv_sec
<= 0)
444 g
->cached_next_time_event
= n
;
448 static gboolean
prepare_func(GSource
*source
, gint
*timeout
) {
449 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
454 if (g
->io_events_please_scan
)
455 cleanup_io_events(g
, 0);
457 if (g
->time_events_please_scan
)
458 cleanup_time_events(g
, 0);
460 if (g
->defer_events_please_scan
)
461 cleanup_defer_events(g
, 0);
463 if (g
->n_enabled_defer_events
) {
466 } else if (g
->n_enabled_time_events
) {
469 struct timeval tvnow
;
472 t
= find_next_time_event(g
);
475 g_source_get_current_time(source
, &now
);
476 tvnow
.tv_sec
= now
.tv_sec
;
477 tvnow
.tv_usec
= now
.tv_usec
;
479 usec
= pa_timeval_diff(&t
->timeval
, &tvnow
);
486 *timeout
= (gint
) (usec
/ 1000);
492 static gboolean
check_func(GSource
*source
) {
493 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
498 if (g
->n_enabled_defer_events
)
500 else if (g
->n_enabled_time_events
) {
503 struct timeval tvnow
;
505 t
= find_next_time_event(g
);
508 g_source_get_current_time(source
, &now
);
509 tvnow
.tv_sec
= now
.tv_sec
;
510 tvnow
.tv_usec
= now
.tv_usec
;
512 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) <= 0)
516 for (e
= g
->io_events
; e
; e
= e
->next
)
517 if (!e
->dead
&& e
->poll_fd
.revents
!= 0)
523 static gboolean
dispatch_func(GSource
*source
, PA_GCC_UNUSED GSourceFunc callback
, PA_GCC_UNUSED gpointer userdata
) {
524 pa_glib_mainloop
*g
= (pa_glib_mainloop
*) source
;
529 if (g
->n_enabled_defer_events
) {
532 for (d
= g
->defer_events
; d
; d
= d
->next
) {
533 if (d
->dead
|| !d
->enabled
)
541 d
->callback(&g
->api
, d
, d
->userdata
);
545 if (g
->n_enabled_time_events
) {
547 struct timeval tvnow
;
550 t
= find_next_time_event(g
);
553 g_source_get_current_time(source
, &now
);
554 tvnow
.tv_sec
= now
.tv_sec
;
555 tvnow
.tv_usec
= now
.tv_usec
;
557 if (pa_timeval_cmp(&t
->timeval
, &tvnow
) < 0) {
558 t
->callback(&g
->api
, t
, &t
->timeval
, t
->userdata
);
563 for (e
= g
->io_events
; e
; e
= e
->next
)
564 if (!e
->dead
&& e
->poll_fd
.revents
!= 0) {
565 e
->callback(&g
->api
, e
, e
->poll_fd
.fd
, map_flags_from_glib(e
->poll_fd
.revents
), e
->userdata
);
566 e
->poll_fd
.revents
= 0;
573 static const pa_mainloop_api vtable
= {
576 .io_new
= glib_io_new
,
577 .io_enable
= glib_io_enable
,
578 .io_free
= glib_io_free
,
579 .io_set_destroy
= glib_io_set_destroy
,
581 .time_new
= glib_time_new
,
582 .time_restart
= glib_time_restart
,
583 .time_free
= glib_time_free
,
584 .time_set_destroy
= glib_time_set_destroy
,
586 .defer_new
= glib_defer_new
,
587 .defer_enable
= glib_defer_enable
,
588 .defer_free
= glib_defer_free
,
589 .defer_set_destroy
= glib_defer_set_destroy
,
594 pa_glib_mainloop
*pa_glib_mainloop_new(GMainContext
*c
) {
597 static GSourceFuncs source_funcs
= {
606 g
= (pa_glib_mainloop
*) g_source_new(&source_funcs
, sizeof(pa_glib_mainloop
));
607 g_main_context_ref(g
->context
= c
? c
: g_main_context_default());
612 PA_LLIST_HEAD_INIT(pa_io_event
, g
->io_events
);
613 PA_LLIST_HEAD_INIT(pa_time_event
, g
->time_events
);
614 PA_LLIST_HEAD_INIT(pa_defer_event
, g
->defer_events
);
616 g
->n_enabled_defer_events
= g
->n_enabled_time_events
= 0;
617 g
->io_events_please_scan
= g
->time_events_please_scan
= g
->defer_events_please_scan
= 0;
619 g_source_attach(&g
->source
, g
->context
);
620 g_source_set_can_recurse(&g
->source
, FALSE
);
625 void pa_glib_mainloop_free(pa_glib_mainloop
* g
) {
628 cleanup_io_events(g
, 1);
629 cleanup_defer_events(g
, 1);
630 cleanup_time_events(g
, 1);
632 g_main_context_unref(g
->context
);
633 g_source_destroy(&g
->source
);
634 g_source_unref(&g
->source
);
637 pa_mainloop_api
* pa_glib_mainloop_get_api(pa_glib_mainloop
*g
) {