2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #include <pulsecore/pipe.h>
37 #include <pulse/rtclock.h>
38 #include <pulse/timeval.h>
39 #include <pulse/xmalloc.h>
41 #include <pulsecore/poll.h>
42 #include <pulsecore/core-rtclock.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/i18n.h>
45 #include <pulsecore/llist.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/core-error.h>
48 #include <pulsecore/socket.h>
49 #include <pulsecore/macro.h>
55 pa_mainloop
*mainloop
;
59 pa_io_event_flags_t events
;
60 struct pollfd
*pollfd
;
62 pa_io_event_cb_t callback
;
64 pa_io_event_destroy_cb_t destroy_callback
;
66 PA_LLIST_FIELDS(pa_io_event
);
69 struct pa_time_event
{
70 pa_mainloop
*mainloop
;
74 pa_bool_t use_rtclock
:1;
77 pa_time_event_cb_t callback
;
79 pa_time_event_destroy_cb_t destroy_callback
;
81 PA_LLIST_FIELDS(pa_time_event
);
84 struct pa_defer_event
{
85 pa_mainloop
*mainloop
;
90 pa_defer_event_cb_t callback
;
92 pa_defer_event_destroy_cb_t destroy_callback
;
94 PA_LLIST_FIELDS(pa_defer_event
);
98 PA_LLIST_HEAD(pa_io_event
, io_events
);
99 PA_LLIST_HEAD(pa_time_event
, time_events
);
100 PA_LLIST_HEAD(pa_defer_event
, defer_events
);
102 unsigned n_enabled_defer_events
, n_enabled_time_events
, n_io_events
;
103 unsigned io_events_please_scan
, time_events_please_scan
, defer_events_please_scan
;
105 pa_bool_t rebuild_pollfds
:1;
106 struct pollfd
*pollfds
;
107 unsigned max_pollfds
, n_pollfds
;
109 pa_usec_t prepared_timeout
;
110 pa_time_event
*cached_next_time_event
;
117 pa_atomic_t wakeup_requested
;
119 int wakeup_pipe_type
;
129 pa_poll_func poll_func
;
130 void *poll_func_userdata
;
134 static short map_flags_to_libc(pa_io_event_flags_t flags
) {
136 ((flags
& PA_IO_EVENT_INPUT
? POLLIN
: 0) |
137 (flags
& PA_IO_EVENT_OUTPUT
? POLLOUT
: 0) |
138 (flags
& PA_IO_EVENT_ERROR
? POLLERR
: 0) |
139 (flags
& PA_IO_EVENT_HANGUP
? POLLHUP
: 0));
142 static pa_io_event_flags_t
map_flags_from_libc(short flags
) {
144 (flags
& POLLIN
? PA_IO_EVENT_INPUT
: 0) |
145 (flags
& POLLOUT
? PA_IO_EVENT_OUTPUT
: 0) |
146 (flags
& POLLERR
? PA_IO_EVENT_ERROR
: 0) |
147 (flags
& POLLHUP
? PA_IO_EVENT_HANGUP
: 0);
151 static pa_io_event
* mainloop_io_new(
154 pa_io_event_flags_t events
,
155 pa_io_event_cb_t callback
,
162 pa_assert(a
->userdata
);
167 pa_assert(a
== &m
->api
);
169 e
= pa_xnew0(pa_io_event
, 1);
175 e
->callback
= callback
;
176 e
->userdata
= userdata
;
178 PA_LLIST_PREPEND(pa_io_event
, m
->io_events
, e
);
179 m
->rebuild_pollfds
= TRUE
;
182 pa_mainloop_wakeup(m
);
187 static void mainloop_io_enable(pa_io_event
*e
, pa_io_event_flags_t events
) {
191 if (e
->events
== events
)
197 e
->pollfd
->events
= map_flags_to_libc(events
);
199 e
->mainloop
->rebuild_pollfds
= TRUE
;
201 pa_mainloop_wakeup(e
->mainloop
);
204 static void mainloop_io_free(pa_io_event
*e
) {
209 e
->mainloop
->io_events_please_scan
++;
211 e
->mainloop
->n_io_events
--;
212 e
->mainloop
->rebuild_pollfds
= TRUE
;
214 pa_mainloop_wakeup(e
->mainloop
);
217 static void mainloop_io_set_destroy(pa_io_event
*e
, pa_io_event_destroy_cb_t callback
) {
220 e
->destroy_callback
= callback
;
224 static pa_defer_event
* mainloop_defer_new(
226 pa_defer_event_cb_t callback
,
233 pa_assert(a
->userdata
);
237 pa_assert(a
== &m
->api
);
239 e
= pa_xnew0(pa_defer_event
, 1);
243 m
->n_enabled_defer_events
++;
245 e
->callback
= callback
;
246 e
->userdata
= userdata
;
248 PA_LLIST_PREPEND(pa_defer_event
, m
->defer_events
, e
);
250 pa_mainloop_wakeup(e
->mainloop
);
255 static void mainloop_defer_enable(pa_defer_event
*e
, int b
) {
259 if (e
->enabled
&& !b
) {
260 pa_assert(e
->mainloop
->n_enabled_defer_events
> 0);
261 e
->mainloop
->n_enabled_defer_events
--;
262 } else if (!e
->enabled
&& b
) {
263 e
->mainloop
->n_enabled_defer_events
++;
264 pa_mainloop_wakeup(e
->mainloop
);
270 static void mainloop_defer_free(pa_defer_event
*e
) {
275 e
->mainloop
->defer_events_please_scan
++;
278 pa_assert(e
->mainloop
->n_enabled_defer_events
> 0);
279 e
->mainloop
->n_enabled_defer_events
--;
284 static void mainloop_defer_set_destroy(pa_defer_event
*e
, pa_defer_event_destroy_cb_t callback
) {
288 e
->destroy_callback
= callback
;
292 static pa_usec_t
make_rt(const struct timeval
*tv
, pa_bool_t
*use_rtclock
) {
296 *use_rtclock
= FALSE
;
297 return PA_USEC_INVALID
;
301 *use_rtclock
= !!(ttv
.tv_usec
& PA_TIMEVAL_RTCLOCK
);
304 ttv
.tv_usec
&= ~PA_TIMEVAL_RTCLOCK
;
306 pa_rtclock_from_wallclock(&ttv
);
308 return pa_timeval_load(&ttv
);
311 static pa_time_event
* mainloop_time_new(
313 const struct timeval
*tv
,
314 pa_time_event_cb_t callback
,
320 pa_bool_t use_rtclock
= FALSE
;
323 pa_assert(a
->userdata
);
326 t
= make_rt(tv
, &use_rtclock
);
329 pa_assert(a
== &m
->api
);
331 e
= pa_xnew0(pa_time_event
, 1);
334 if ((e
->enabled
= (t
!= PA_USEC_INVALID
))) {
336 e
->use_rtclock
= use_rtclock
;
338 m
->n_enabled_time_events
++;
340 if (m
->cached_next_time_event
) {
341 pa_assert(m
->cached_next_time_event
->enabled
);
343 if (t
< m
->cached_next_time_event
->time
)
344 m
->cached_next_time_event
= e
;
348 e
->callback
= callback
;
349 e
->userdata
= userdata
;
351 PA_LLIST_PREPEND(pa_time_event
, m
->time_events
, e
);
354 pa_mainloop_wakeup(m
);
359 static void mainloop_time_restart(pa_time_event
*e
, const struct timeval
*tv
) {
362 pa_bool_t use_rtclock
= FALSE
;
367 t
= make_rt(tv
, &use_rtclock
);
369 valid
= (t
!= PA_USEC_INVALID
);
370 if (e
->enabled
&& !valid
) {
371 pa_assert(e
->mainloop
->n_enabled_time_events
> 0);
372 e
->mainloop
->n_enabled_time_events
--;
373 } else if (!e
->enabled
&& valid
)
374 e
->mainloop
->n_enabled_time_events
++;
376 if ((e
->enabled
= valid
)) {
378 e
->use_rtclock
= use_rtclock
;
379 pa_mainloop_wakeup(e
->mainloop
);
382 if (e
->mainloop
->cached_next_time_event
&& e
->enabled
) {
383 pa_assert(e
->mainloop
->cached_next_time_event
->enabled
);
385 if (t
< e
->mainloop
->cached_next_time_event
->time
)
386 e
->mainloop
->cached_next_time_event
= e
;
387 } else if (e
->mainloop
->cached_next_time_event
== e
)
388 e
->mainloop
->cached_next_time_event
= NULL
;
391 static void mainloop_time_free(pa_time_event
*e
) {
396 e
->mainloop
->time_events_please_scan
++;
399 pa_assert(e
->mainloop
->n_enabled_time_events
> 0);
400 e
->mainloop
->n_enabled_time_events
--;
404 if (e
->mainloop
->cached_next_time_event
== e
)
405 e
->mainloop
->cached_next_time_event
= NULL
;
407 /* no wakeup needed here. Think about it! */
410 static void mainloop_time_set_destroy(pa_time_event
*e
, pa_time_event_destroy_cb_t callback
) {
414 e
->destroy_callback
= callback
;
419 static void mainloop_quit(pa_mainloop_api
*a
, int retval
) {
423 pa_assert(a
->userdata
);
425 pa_assert(a
== &m
->api
);
427 pa_mainloop_quit(m
, retval
);
430 static const pa_mainloop_api vtable
= {
433 .io_new
= mainloop_io_new
,
434 .io_enable
= mainloop_io_enable
,
435 .io_free
= mainloop_io_free
,
436 .io_set_destroy
= mainloop_io_set_destroy
,
438 .time_new
= mainloop_time_new
,
439 .time_restart
= mainloop_time_restart
,
440 .time_free
= mainloop_time_free
,
441 .time_set_destroy
= mainloop_time_set_destroy
,
443 .defer_new
= mainloop_defer_new
,
444 .defer_enable
= mainloop_defer_enable
,
445 .defer_free
= mainloop_defer_free
,
446 .defer_set_destroy
= mainloop_defer_set_destroy
,
448 .quit
= mainloop_quit
,
451 pa_mainloop
*pa_mainloop_new(void) {
456 m
= pa_xnew0(pa_mainloop
, 1);
458 if (pa_pipe_cloexec(m
->wakeup_pipe
) < 0) {
459 pa_log_error("ERROR: cannot create wakeup pipe");
464 pa_make_fd_nonblock(m
->wakeup_pipe
[0]);
465 pa_make_fd_nonblock(m
->wakeup_pipe
[1]);
467 m
->rebuild_pollfds
= TRUE
;
472 m
->state
= STATE_PASSIVE
;
474 m
->poll_func_ret
= -1;
479 static void cleanup_io_events(pa_mainloop
*m
, pa_bool_t force
) {
482 PA_LLIST_FOREACH_SAFE(e
, n
, m
->io_events
) {
484 if (!force
&& m
->io_events_please_scan
<= 0)
487 if (force
|| e
->dead
) {
488 PA_LLIST_REMOVE(pa_io_event
, m
->io_events
, e
);
491 pa_assert(m
->io_events_please_scan
> 0);
492 m
->io_events_please_scan
--;
495 if (e
->destroy_callback
)
496 e
->destroy_callback(&m
->api
, e
, e
->userdata
);
500 m
->rebuild_pollfds
= TRUE
;
504 pa_assert(m
->io_events_please_scan
== 0);
507 static void cleanup_time_events(pa_mainloop
*m
, pa_bool_t force
) {
508 pa_time_event
*e
, *n
;
510 PA_LLIST_FOREACH_SAFE(e
, n
, m
->time_events
) {
512 if (!force
&& m
->time_events_please_scan
<= 0)
515 if (force
|| e
->dead
) {
516 PA_LLIST_REMOVE(pa_time_event
, m
->time_events
, e
);
519 pa_assert(m
->time_events_please_scan
> 0);
520 m
->time_events_please_scan
--;
523 if (!e
->dead
&& e
->enabled
) {
524 pa_assert(m
->n_enabled_time_events
> 0);
525 m
->n_enabled_time_events
--;
529 if (e
->destroy_callback
)
530 e
->destroy_callback(&m
->api
, e
, e
->userdata
);
536 pa_assert(m
->time_events_please_scan
== 0);
539 static void cleanup_defer_events(pa_mainloop
*m
, pa_bool_t force
) {
540 pa_defer_event
*e
, *n
;
542 PA_LLIST_FOREACH_SAFE(e
, n
, m
->defer_events
) {
544 if (!force
&& m
->defer_events_please_scan
<= 0)
547 if (force
|| e
->dead
) {
548 PA_LLIST_REMOVE(pa_defer_event
, m
->defer_events
, e
);
551 pa_assert(m
->defer_events_please_scan
> 0);
552 m
->defer_events_please_scan
--;
555 if (!e
->dead
&& e
->enabled
) {
556 pa_assert(m
->n_enabled_defer_events
> 0);
557 m
->n_enabled_defer_events
--;
561 if (e
->destroy_callback
)
562 e
->destroy_callback(&m
->api
, e
, e
->userdata
);
568 pa_assert(m
->defer_events_please_scan
== 0);
572 void pa_mainloop_free(pa_mainloop
*m
) {
575 cleanup_io_events(m
, TRUE
);
576 cleanup_defer_events(m
, TRUE
);
577 cleanup_time_events(m
, TRUE
);
579 pa_xfree(m
->pollfds
);
581 pa_close_pipe(m
->wakeup_pipe
);
586 static void scan_dead(pa_mainloop
*m
) {
589 if (m
->io_events_please_scan
)
590 cleanup_io_events(m
, FALSE
);
592 if (m
->time_events_please_scan
)
593 cleanup_time_events(m
, FALSE
);
595 if (m
->defer_events_please_scan
)
596 cleanup_defer_events(m
, FALSE
);
599 static void rebuild_pollfds(pa_mainloop
*m
) {
604 l
= m
->n_io_events
+ 1;
605 if (m
->max_pollfds
< l
) {
607 m
->pollfds
= pa_xrealloc(m
->pollfds
, sizeof(struct pollfd
)*l
);
614 m
->pollfds
[0].fd
= m
->wakeup_pipe
[0];
615 m
->pollfds
[0].events
= POLLIN
;
616 m
->pollfds
[0].revents
= 0;
620 PA_LLIST_FOREACH(e
, m
->io_events
) {
628 p
->events
= map_flags_to_libc(e
->events
);
635 m
->rebuild_pollfds
= FALSE
;
638 static unsigned dispatch_pollfds(pa_mainloop
*m
) {
642 pa_assert(m
->poll_func_ret
> 0);
644 k
= m
->poll_func_ret
;
646 PA_LLIST_FOREACH(e
, m
->io_events
) {
648 if (k
<= 0 || m
->quit
)
651 if (e
->dead
|| !e
->pollfd
|| !e
->pollfd
->revents
)
654 pa_assert(e
->pollfd
->fd
== e
->fd
);
655 pa_assert(e
->callback
);
657 e
->callback(&m
->api
, e
, e
->fd
, map_flags_from_libc(e
->pollfd
->revents
), e
->userdata
);
658 e
->pollfd
->revents
= 0;
666 static unsigned dispatch_defer(pa_mainloop
*m
) {
670 if (m
->n_enabled_defer_events
<= 0)
673 PA_LLIST_FOREACH(e
, m
->defer_events
) {
678 if (e
->dead
|| !e
->enabled
)
681 pa_assert(e
->callback
);
682 e
->callback(&m
->api
, e
, e
->userdata
);
689 static pa_time_event
* find_next_time_event(pa_mainloop
*m
) {
690 pa_time_event
*t
, *n
= NULL
;
693 if (m
->cached_next_time_event
)
694 return m
->cached_next_time_event
;
696 PA_LLIST_FOREACH(t
, m
->time_events
) {
698 if (t
->dead
|| !t
->enabled
)
701 if (!n
|| t
->time
< n
->time
) {
704 /* Shortcut for time == 0 */
710 m
->cached_next_time_event
= n
;
714 static pa_usec_t
calc_next_timeout(pa_mainloop
*m
) {
718 if (m
->n_enabled_time_events
<= 0)
719 return PA_USEC_INVALID
;
721 pa_assert_se(t
= find_next_time_event(m
));
726 clock_now
= pa_rtclock_now();
728 if (t
->time
<= clock_now
)
731 return t
->time
- clock_now
;
734 static unsigned dispatch_timeout(pa_mainloop
*m
) {
740 if (m
->n_enabled_time_events
<= 0)
743 now
= pa_rtclock_now();
745 PA_LLIST_FOREACH(e
, m
->time_events
) {
750 if (e
->dead
|| !e
->enabled
)
753 if (e
->time
<= now
) {
755 pa_assert(e
->callback
);
757 /* Disable time event */
758 mainloop_time_restart(e
, NULL
);
760 e
->callback(&m
->api
, e
, pa_timeval_rtstore(&tv
, e
->time
, e
->use_rtclock
), e
->userdata
);
769 void pa_mainloop_wakeup(pa_mainloop
*m
) {
773 if (pa_write(m
->wakeup_pipe
[1], &c
, sizeof(c
), &m
->wakeup_pipe_type
) < 0)
774 /* Not much options for recovering from the error. Let's at least log something. */
775 pa_log("pa_write() failed while trying to wake up the mainloop: %s", pa_cstrerror(errno
));
777 pa_atomic_store(&m
->wakeup_requested
, TRUE
);
780 static void clear_wakeup(pa_mainloop
*m
) {
785 if (pa_atomic_cmpxchg(&m
->wakeup_requested
, TRUE
, FALSE
)) {
786 while (pa_read(m
->wakeup_pipe
[0], &c
, sizeof(c
), &m
->wakeup_pipe_type
) == sizeof(c
))
791 int pa_mainloop_prepare(pa_mainloop
*m
, int timeout
) {
793 pa_assert(m
->state
== STATE_PASSIVE
);
801 if (m
->n_enabled_defer_events
<= 0) {
803 if (m
->rebuild_pollfds
)
806 m
->prepared_timeout
= calc_next_timeout(m
);
808 uint64_t u
= (uint64_t) timeout
* PA_USEC_PER_MSEC
;
810 if (u
< m
->prepared_timeout
|| m
->prepared_timeout
== PA_USEC_INVALID
)
811 m
->prepared_timeout
= timeout
;
815 m
->state
= STATE_PREPARED
;
819 m
->state
= STATE_QUIT
;
823 static int usec_to_timeout(pa_usec_t u
) {
826 if (u
== PA_USEC_INVALID
)
829 timeout
= (u
+ PA_USEC_PER_MSEC
- 1) / PA_USEC_PER_MSEC
;
830 pa_assert(timeout
>= 0);
835 int pa_mainloop_poll(pa_mainloop
*m
) {
837 pa_assert(m
->state
== STATE_PREPARED
);
842 m
->state
= STATE_POLLING
;
844 if (m
->n_enabled_defer_events
)
845 m
->poll_func_ret
= 0;
847 pa_assert(!m
->rebuild_pollfds
);
850 m
->poll_func_ret
= m
->poll_func(
851 m
->pollfds
, m
->n_pollfds
,
852 usec_to_timeout(m
->prepared_timeout
),
853 m
->poll_func_userdata
);
858 m
->poll_func_ret
= ppoll(
859 m
->pollfds
, m
->n_pollfds
,
860 m
->prepared_timeout
== PA_USEC_INVALID
? NULL
: pa_timespec_store(&ts
, m
->prepared_timeout
),
863 m
->poll_func_ret
= pa_poll(
864 m
->pollfds
, m
->n_pollfds
,
865 usec_to_timeout(m
->prepared_timeout
));
869 if (m
->poll_func_ret
< 0) {
871 m
->poll_func_ret
= 0;
873 pa_log("poll(): %s", pa_cstrerror(errno
));
877 m
->state
= m
->poll_func_ret
< 0 ? STATE_PASSIVE
: STATE_POLLED
;
878 return m
->poll_func_ret
;
881 m
->state
= STATE_QUIT
;
885 int pa_mainloop_dispatch(pa_mainloop
*m
) {
886 unsigned dispatched
= 0;
889 pa_assert(m
->state
== STATE_POLLED
);
894 if (m
->n_enabled_defer_events
)
895 dispatched
+= dispatch_defer(m
);
897 if (m
->n_enabled_time_events
)
898 dispatched
+= dispatch_timeout(m
);
903 if (m
->poll_func_ret
> 0)
904 dispatched
+= dispatch_pollfds(m
);
910 m
->state
= STATE_PASSIVE
;
912 return (int) dispatched
;
915 m
->state
= STATE_QUIT
;
919 int pa_mainloop_get_retval(pa_mainloop
*m
) {
925 int pa_mainloop_iterate(pa_mainloop
*m
, int block
, int *retval
) {
929 if ((r
= pa_mainloop_prepare(m
, block
? -1 : 0)) < 0)
932 if ((r
= pa_mainloop_poll(m
)) < 0)
935 if ((r
= pa_mainloop_dispatch(m
)) < 0)
942 if ((r
== -2) && retval
)
943 *retval
= pa_mainloop_get_retval(m
);
947 int pa_mainloop_run(pa_mainloop
*m
, int *retval
) {
950 while ((r
= pa_mainloop_iterate(m
, 1, retval
)) >= 0)
961 void pa_mainloop_quit(pa_mainloop
*m
, int retval
) {
966 pa_mainloop_wakeup(m
);
969 pa_mainloop_api
* pa_mainloop_get_api(pa_mainloop
*m
) {
975 void pa_mainloop_set_poll_func(pa_mainloop
*m
, pa_poll_func poll_func
, void *userdata
) {
978 m
->poll_func
= poll_func
;
979 m
->poll_func_userdata
= userdata
;
982 pa_bool_t
pa_mainloop_is_our_api(pa_mainloop_api
*m
) {
985 return m
->io_new
== mainloop_io_new
;