diff options
Diffstat (limited to 'src/pulse/mainloop.c')
| -rw-r--r-- | src/pulse/mainloop.c | 890 |
1 files changed, 530 insertions, 360 deletions
diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index dfbc337b..3ef387b6 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -1,18 +1,19 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -24,81 +25,96 @@ #endif #include <stdio.h> -#include <signal.h> #include <unistd.h> #include <stdlib.h> -#include <string.h> -#include <assert.h> #include <fcntl.h> #include <errno.h> -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#else -#include "../pulsecore/poll.h" -#endif - -#include "../pulsecore/winsock.h" - #ifndef HAVE_PIPE -#include "../pulsecore/pipe.h" +#include <pulsecore/pipe.h> #endif -#include <pulsecore/core-error.h> +#include <pulse/i18n.h> +#include <pulse/rtclock.h> #include <pulse/timeval.h> #include <pulse/xmalloc.h> +#include <pulsecore/poll.h> +#include <pulsecore/core-rtclock.h> #include <pulsecore/core-util.h> -#include <pulsecore/idxset.h> +#include <pulsecore/llist.h> #include <pulsecore/log.h> +#include <pulsecore/core-error.h> +#include <pulsecore/socket.h> +#include <pulsecore/macro.h> #include "mainloop.h" +#include "internal.h" struct pa_io_event { pa_mainloop *mainloop; - int dead; + pa_bool_t dead:1; + int fd; pa_io_event_flags_t events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); struct pollfd *pollfd; + + pa_io_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); + pa_io_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_io_event); }; struct pa_time_event { pa_mainloop *mainloop; - int dead; - int enabled; - struct timeval timeval; - void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); + pa_bool_t dead:1; + + pa_bool_t enabled:1; + pa_bool_t use_rtclock:1; + pa_usec_t time; + + pa_time_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); + pa_time_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_time_event); }; struct pa_defer_event { pa_mainloop *mainloop; - int dead; - int enabled; - void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); + pa_bool_t dead:1; + + pa_bool_t enabled:1; + + pa_defer_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); + pa_defer_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_defer_event); }; struct pa_mainloop { - pa_idxset *io_events, *time_events, *defer_events; - int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; + PA_LLIST_HEAD(pa_io_event, io_events); + PA_LLIST_HEAD(pa_time_event, time_events); + PA_LLIST_HEAD(pa_defer_event, defer_events); + + unsigned n_enabled_defer_events, n_enabled_time_events, n_io_events; + unsigned io_events_please_scan, time_events_please_scan, defer_events_please_scan; + pa_bool_t rebuild_pollfds:1; struct pollfd *pollfds; unsigned max_pollfds, n_pollfds; - int rebuild_pollfds; - int prepared_timeout; + pa_usec_t prepared_timeout; + pa_time_event *cached_next_time_event; - int quit, retval; pa_mainloop_api api; - int deferred_pending; + int retval; + pa_bool_t quit:1; + pa_bool_t wakeup_requested:1; int wakeup_pipe[2]; int wakeup_pipe_type; @@ -112,33 +128,52 @@ struct pa_mainloop { pa_poll_func poll_func; void *poll_func_userdata; + int poll_func_ret; }; +static short map_flags_to_libc(pa_io_event_flags_t flags) { + return (short) + ((flags & PA_IO_EVENT_INPUT ? POLLIN : 0) | + (flags & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) | + (flags & PA_IO_EVENT_ERROR ? POLLERR : 0) | + (flags & PA_IO_EVENT_HANGUP ? POLLHUP : 0)); +} + +static pa_io_event_flags_t map_flags_from_libc(short flags) { + return + (flags & POLLIN ? PA_IO_EVENT_INPUT : 0) | + (flags & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | + (flags & POLLERR ? PA_IO_EVENT_ERROR : 0) | + (flags & POLLHUP ? PA_IO_EVENT_HANGUP : 0); +} + /* IO events */ static pa_io_event* mainloop_io_new( - pa_mainloop_api*a, - int fd, - pa_io_event_flags_t events, - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), - void *userdata) { - + pa_mainloop_api *a, + int fd, + pa_io_event_flags_t events, + pa_io_event_cb_t callback, + void *userdata) { + pa_mainloop *m; pa_io_event *e; - assert(a && a->userdata && fd >= 0 && callback); + pa_assert(a); + pa_assert(a->userdata); + pa_assert(fd >= 0); + pa_assert(callback); + m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_io_event)); + e = pa_xnew0(pa_io_event, 1); e->mainloop = m; - e->dead = 0; e->fd = fd; e->events = events; + e->callback = callback; e->userdata = userdata; - e->destroy_callback = NULL; - e->pollfd = NULL; #ifdef OS_IS_WIN32 { @@ -154,14 +189,15 @@ static pa_io_event* mainloop_io_new( if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); - e->dead = 1; + pa_log_warn("Cannot monitor non-socket file descriptors."); + e->dead = TRUE; } } #endif - pa_idxset_put(m->io_events, e, NULL); - m->rebuild_pollfds = 1; + PA_LLIST_PREPEND(pa_io_event, m->io_events, e); + m->rebuild_pollfds = TRUE; + m->n_io_events ++; pa_mainloop_wakeup(m); @@ -169,48 +205,67 @@ static pa_io_event* mainloop_io_new( } static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e && e->mainloop); + pa_assert(e); + pa_assert(!e->dead); + + if (e->events == events) + return; e->events = events; - e->mainloop->rebuild_pollfds = 1; + + if (e->pollfd) + e->pollfd->events = map_flags_to_libc(events); + else + e->mainloop->rebuild_pollfds = TRUE; pa_mainloop_wakeup(e->mainloop); } static void mainloop_io_free(pa_io_event *e) { - assert(e && e->mainloop); + pa_assert(e); + pa_assert(!e->dead); - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; + e->dead = TRUE; + e->mainloop->io_events_please_scan ++; + + e->mainloop->n_io_events --; + e->mainloop->rebuild_pollfds = TRUE; pa_mainloop_wakeup(e->mainloop); } -static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { - assert(e); +static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) { + pa_assert(e); + e->destroy_callback = callback; } /* Defer events */ -static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { +static pa_defer_event* mainloop_defer_new( + pa_mainloop_api *a, + pa_defer_event_cb_t callback, + void *userdata) { + pa_mainloop *m; pa_defer_event *e; - assert(a && a->userdata && callback); + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); + m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_defer_event)); + e = pa_xnew0(pa_defer_event, 1); e->mainloop = m; - e->dead = 0; - e->enabled = 1; + e->enabled = TRUE; + m->n_enabled_defer_events++; + e->callback = callback; e->userdata = userdata; - e->destroy_callback = NULL; - pa_idxset_put(m->defer_events, e, NULL); - - m->deferred_pending++; + PA_LLIST_PREPEND(pa_defer_event, m->defer_events, e); pa_mainloop_wakeup(e->mainloop); @@ -218,254 +273,357 @@ static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (p } static void mainloop_defer_enable(pa_defer_event *e, int b) { - assert(e); + pa_assert(e); + pa_assert(!e->dead); if (e->enabled && !b) { - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; + pa_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; } else if (!e->enabled && b) { - e->mainloop->deferred_pending++; + e->mainloop->n_enabled_defer_events++; pa_mainloop_wakeup(e->mainloop); } - + e->enabled = b; } static void mainloop_defer_free(pa_defer_event *e) { - assert(e); - e->dead = e->mainloop->defer_events_scan_dead = 1; + pa_assert(e); + pa_assert(!e->dead); + + e->dead = TRUE; + e->mainloop->defer_events_please_scan ++; if (e->enabled) { - e->enabled = 0; - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; + pa_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; + e->enabled = FALSE; } } -static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { - assert(e); +static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) { + pa_assert(e); + pa_assert(!e->dead); + e->destroy_callback = callback; } /* Time events */ -static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { +static pa_usec_t make_rt(const struct timeval *tv, pa_bool_t *use_rtclock) { + struct timeval ttv; + + if (!tv) { + *use_rtclock = FALSE; + return PA_USEC_INVALID; + } + + ttv = *tv; + *use_rtclock = !!(ttv.tv_usec & PA_TIMEVAL_RTCLOCK); + + if (*use_rtclock) + ttv.tv_usec &= ~PA_TIMEVAL_RTCLOCK; + else + pa_rtclock_from_wallclock(&ttv); + + return pa_timeval_load(&ttv); +} + +static pa_time_event* mainloop_time_new( + pa_mainloop_api *a, + const struct timeval *tv, + pa_time_event_cb_t callback, + void *userdata) { + pa_mainloop *m; pa_time_event *e; + pa_usec_t t; + pa_bool_t use_rtclock = FALSE; + + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); + + t = make_rt(tv, &use_rtclock); - assert(a && a->userdata && callback); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_time_event)); + e = pa_xnew0(pa_time_event, 1); e->mainloop = m; - e->dead = 0; - e->enabled = !!tv; - if (tv) - e->timeval = *tv; + if ((e->enabled = (t != PA_USEC_INVALID))) { + e->time = t; + e->use_rtclock = use_rtclock; + + m->n_enabled_time_events++; + + if (m->cached_next_time_event) { + pa_assert(m->cached_next_time_event->enabled); + + if (t < m->cached_next_time_event->time) + m->cached_next_time_event = e; + } + } e->callback = callback; e->userdata = userdata; - e->destroy_callback = NULL; - pa_idxset_put(m->time_events, e, NULL); + PA_LLIST_PREPEND(pa_time_event, m->time_events, e); if (e->enabled) pa_mainloop_wakeup(m); - + return e; } static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { - assert(e); + pa_bool_t valid; + pa_usec_t t; + pa_bool_t use_rtclock = FALSE; + + pa_assert(e); + pa_assert(!e->dead); + + t = make_rt(tv, &use_rtclock); - if (tv) { - e->enabled = 1; - e->timeval = *tv; + valid = (t != PA_USEC_INVALID); + if (e->enabled && !valid) { + pa_assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + } else if (!e->enabled && valid) + e->mainloop->n_enabled_time_events++; + if ((e->enabled = valid)) { + e->time = t; + e->use_rtclock = use_rtclock; pa_mainloop_wakeup(e->mainloop); - } else - e->enabled = 0; + } + + if (e->mainloop->cached_next_time_event && e->enabled) { + pa_assert(e->mainloop->cached_next_time_event->enabled); + + if (t < e->mainloop->cached_next_time_event->time) + e->mainloop->cached_next_time_event = e; + } else if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; } static void mainloop_time_free(pa_time_event *e) { - assert(e); + pa_assert(e); + pa_assert(!e->dead); - e->dead = e->mainloop->time_events_scan_dead = 1; + e->dead = TRUE; + e->mainloop->time_events_please_scan ++; + + if (e->enabled) { + pa_assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + e->enabled = FALSE; + } + + if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; /* no wakeup needed here. Think about it! */ } -static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { - assert(e); +static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) { + pa_assert(e); + pa_assert(!e->dead); + e->destroy_callback = callback; } /* quit() */ -static void mainloop_quit(pa_mainloop_api*a, int retval) { +static void mainloop_quit(pa_mainloop_api *a, int retval) { pa_mainloop *m; - assert(a && a->userdata); + + pa_assert(a); + pa_assert(a->userdata); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); pa_mainloop_quit(m, retval); } - + static const pa_mainloop_api vtable = { .userdata = NULL, - .io_new= mainloop_io_new, - .io_enable= mainloop_io_enable, - .io_free= mainloop_io_free, - .io_set_destroy= mainloop_io_set_destroy, + .io_new = mainloop_io_new, + .io_enable = mainloop_io_enable, + .io_free = mainloop_io_free, + .io_set_destroy = mainloop_io_set_destroy, .time_new = mainloop_time_new, .time_restart = mainloop_time_restart, .time_free = mainloop_time_free, .time_set_destroy = mainloop_time_set_destroy, - + .defer_new = mainloop_defer_new, .defer_enable = mainloop_defer_enable, .defer_free = mainloop_defer_free, .defer_set_destroy = mainloop_defer_set_destroy, - + .quit = mainloop_quit, }; pa_mainloop *pa_mainloop_new(void) { pa_mainloop *m; - m = pa_xmalloc(sizeof(pa_mainloop)); + pa_init_i18n(); + + m = pa_xnew0(pa_mainloop, 1); - m->wakeup_pipe_type = 0; - if (pipe(m->wakeup_pipe) < 0) { - pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); + if (pa_pipe_cloexec(m->wakeup_pipe) < 0) { + pa_log_error("ERROR: cannot create wakeup pipe"); pa_xfree(m); return NULL; } - pa_make_nonblock_fd(m->wakeup_pipe[0]); - pa_make_nonblock_fd(m->wakeup_pipe[1]); - - m->io_events = pa_idxset_new(NULL, NULL); - m->defer_events = pa_idxset_new(NULL, NULL); - m->time_events = pa_idxset_new(NULL, NULL); + pa_make_fd_nonblock(m->wakeup_pipe[0]); + pa_make_fd_nonblock(m->wakeup_pipe[1]); - assert(m->io_events && m->defer_events && m->time_events); - - m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; - - m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = 0; - m->rebuild_pollfds = 1; - - m->quit = m->retval = 0; + m->rebuild_pollfds = TRUE; m->api = vtable; m->api.userdata = m; - m->deferred_pending = 0; - m->state = STATE_PASSIVE; - m->poll_func = NULL; - m->poll_func_userdata = NULL; + m->poll_func_ret = -1; - m->retval = -1; - return m; } -static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_io_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_io_events(pa_mainloop *m, pa_bool_t force) { + pa_io_event *e, *n; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + PA_LLIST_FOREACH_SAFE(e, n, m->io_events) { + + if (!force && m->io_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_io_event, m->io_events, e); + + if (e->dead) { + pa_assert(m->io_events_please_scan > 0); + m->io_events_please_scan--; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + + m->rebuild_pollfds = TRUE; + } + } + + pa_assert(m->io_events_please_scan == 0); } -static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_time_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_time_events(pa_mainloop *m, pa_bool_t force) { + pa_time_event *e, *n; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + PA_LLIST_FOREACH_SAFE(e, n, m->time_events) { + + if (!force && m->time_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_time_event, m->time_events, e); + + if (e->dead) { + pa_assert(m->time_events_please_scan > 0); + m->time_events_please_scan--; + } + + if (!e->dead && e->enabled) { + pa_assert(m->n_enabled_time_events > 0); + m->n_enabled_time_events--; + e->enabled = FALSE; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + } + + pa_assert(m->time_events_please_scan == 0); } -static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_defer_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_defer_events(pa_mainloop *m, pa_bool_t force) { + pa_defer_event *e, *n; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + PA_LLIST_FOREACH_SAFE(e, n, m->defer_events) { + + if (!force && m->defer_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e); + + if (e->dead) { + pa_assert(m->defer_events_please_scan > 0); + m->defer_events_please_scan--; + } + + if (!e->dead && e->enabled) { + pa_assert(m->n_enabled_defer_events > 0); + m->n_enabled_defer_events--; + e->enabled = FALSE; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + } + + pa_assert(m->defer_events_please_scan == 0); } -void pa_mainloop_free(pa_mainloop* m) { - int all = 1; - assert(m); - pa_idxset_foreach(m->io_events, io_foreach, &all); - pa_idxset_foreach(m->time_events, time_foreach, &all); - pa_idxset_foreach(m->defer_events, defer_foreach, &all); +void pa_mainloop_free(pa_mainloop *m) { + pa_assert(m); - pa_idxset_free(m->io_events, NULL, NULL); - pa_idxset_free(m->time_events, NULL, NULL); - pa_idxset_free(m->defer_events, NULL, NULL); + cleanup_io_events(m, TRUE); + cleanup_defer_events(m, TRUE); + cleanup_time_events(m, TRUE); pa_xfree(m->pollfds); - if (m->wakeup_pipe[0] >= 0) - close(m->wakeup_pipe[0]); - if (m->wakeup_pipe[1] >= 0) - close(m->wakeup_pipe[1]); + pa_close_pipe(m->wakeup_pipe); pa_xfree(m); } static void scan_dead(pa_mainloop *m) { - int all = 0; - assert(m); + pa_assert(m); + + if (m->io_events_please_scan) + cleanup_io_events(m, FALSE); - if (m->io_events_scan_dead) - pa_idxset_foreach(m->io_events, io_foreach, &all); - if (m->time_events_scan_dead) - pa_idxset_foreach(m->time_events, time_foreach, &all); - if (m->defer_events_scan_dead) - pa_idxset_foreach(m->defer_events, defer_foreach, &all); + if (m->time_events_please_scan) + cleanup_time_events(m, FALSE); - m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; + if (m->defer_events_please_scan) + cleanup_defer_events(m, FALSE); } static void rebuild_pollfds(pa_mainloop *m) { pa_io_event*e; struct pollfd *p; - uint32_t idx = PA_IDXSET_INVALID; unsigned l; - l = pa_idxset_size(m->io_events) + 1; + l = m->n_io_events + 1; if (m->max_pollfds < l) { + l *= 2; m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; } @@ -481,7 +639,7 @@ static void rebuild_pollfds(pa_mainloop *m) { m->n_pollfds++; } - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + PA_LLIST_FOREACH(e, m->io_events) { if (e->dead) { e->pollfd = NULL; continue; @@ -489,56 +647,60 @@ static void rebuild_pollfds(pa_mainloop *m) { e->pollfd = p; p->fd = e->fd; - p->events = - ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | - ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | - POLLHUP | - POLLERR; + p->events = map_flags_to_libc(e->events); p->revents = 0; p++; m->n_pollfds++; } - m->rebuild_pollfds = 0; + m->rebuild_pollfds = FALSE; } -static int dispatch_pollfds(pa_mainloop *m) { - uint32_t idx = PA_IDXSET_INVALID; +static unsigned dispatch_pollfds(pa_mainloop *m) { pa_io_event *e; - int r = 0; + unsigned r = 0, k; + + pa_assert(m->poll_func_ret > 0); + + k = m->poll_func_ret; + + PA_LLIST_FOREACH(e, m->io_events) { + + if (k <= 0 || m->quit) + break; - for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; - - assert(e->pollfd->fd == e->fd && e->callback); - e->callback(&m->api, e, e->fd, - (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | - (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | - (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | - (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), - e->userdata); + + pa_assert(e->pollfd->fd == e->fd); + pa_assert(e->callback); + + e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata); e->pollfd->revents = 0; r++; + k--; } return r; } -static int dispatch_defer(pa_mainloop *m) { - uint32_t idx; +static unsigned dispatch_defer(pa_mainloop *m) { pa_defer_event *e; - int r = 0; + unsigned r = 0; - if (!m->deferred_pending) + if (m->n_enabled_defer_events <= 0) return 0; - for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { + PA_LLIST_FOREACH(e, m->defer_events) { + + if (m->quit) + break; + if (e->dead || !e->enabled) continue; - - assert(e->callback); + + pa_assert(e->callback); e->callback(&m->api, e, e->userdata); r++; } @@ -546,74 +708,78 @@ static int dispatch_defer(pa_mainloop *m) { return r; } -static int calc_next_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int t = -1; - int got_time = 0; +static pa_time_event* find_next_time_event(pa_mainloop *m) { + pa_time_event *t, *n = NULL; + pa_assert(m); - if (pa_idxset_isempty(m->time_events)) - return -1; + if (m->cached_next_time_event) + return m->cached_next_time_event; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - int tmp; - - if (e->dead || !e->enabled) + PA_LLIST_FOREACH(t, m->time_events) { + + if (t->dead || !t->enabled) continue; - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; + if (!n || t->time < n->time) { + n = t; + + /* Shortcut for time == 0 */ + if (n->time == 0) + break; } + } - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) - return 0; + m->cached_next_time_event = n; + return n; +} - tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - - if (e->timeval.tv_usec > now.tv_usec) - tmp += (e->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; +static pa_usec_t calc_next_timeout(pa_mainloop *m) { + pa_time_event *t; + pa_usec_t clock_now; - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } + if (m->n_enabled_time_events <= 0) + return PA_USEC_INVALID; + + pa_assert_se(t = find_next_time_event(m)); + + if (t->time <= 0) + return 0; + + clock_now = pa_rtclock_now(); + + if (t->time <= clock_now) + return 0; - return t; + return t->time - clock_now; } -static int dispatch_timeout(pa_mainloop *m) { - uint32_t idx; +static unsigned dispatch_timeout(pa_mainloop *m) { pa_time_event *e; - struct timeval now; - int got_time = 0; - int r = 0; - assert(m); + pa_usec_t now; + unsigned r = 0; + pa_assert(m); - if (pa_idxset_isempty(m->time_events)) + if (m->n_enabled_time_events <= 0) return 0; - for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { - + now = pa_rtclock_now(); + + PA_LLIST_FOREACH(e, m->time_events) { + + if (m->quit) + break; + if (e->dead || !e->enabled) continue; - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { - assert(e->callback); + if (e->time <= now) { + struct timeval tv; + pa_assert(e->callback); + + /* Disable time event */ + mainloop_time_restart(e, NULL); - e->enabled = 0; - e->callback(&m->api, e, &e->timeval, e->userdata); + e->callback(&m->api, e, pa_timeval_rtstore(&tv, e->time, e->use_rtclock), e->userdata); r++; } @@ -624,26 +790,32 @@ static int dispatch_timeout(pa_mainloop *m) { void pa_mainloop_wakeup(pa_mainloop *m) { char c = 'W'; - assert(m); + pa_assert(m); - if (m->wakeup_pipe[1] >= 0) + if (m->wakeup_pipe[1] >= 0 && m->state == STATE_POLLING) { pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type); + m->wakeup_requested++; + } } static void clear_wakeup(pa_mainloop *m) { char c[10]; - assert(m); + pa_assert(m); if (m->wakeup_pipe[0] < 0) return; - while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c)); + if (m->wakeup_requested) { + while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c)) + ; + m->wakeup_requested = 0; + } } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - assert(m); - assert(m->state == STATE_PASSIVE); + pa_assert(m); + pa_assert(m->state == STATE_PASSIVE); clear_wakeup(m); scan_dead(m); @@ -651,14 +823,18 @@ int pa_mainloop_prepare(pa_mainloop *m, int timeout) { if (m->quit) goto quit; - if (!m->deferred_pending) { - + if (m->n_enabled_defer_events <= 0) { + if (m->rebuild_pollfds) rebuild_pollfds(m); - + m->prepared_timeout = calc_next_timeout(m); - if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) - m->prepared_timeout = timeout; + if (timeout >= 0) { + uint64_t u = (uint64_t) timeout * PA_USEC_PER_MSEC; + + if (u < m->prepared_timeout || m->prepared_timeout == PA_USEC_INVALID) + m->prepared_timeout = timeout; + } } m->state = STATE_PREPARED; @@ -669,35 +845,62 @@ quit: return -2; } -int pa_mainloop_poll(pa_mainloop *m) { - int r; +static int usec_to_timeout(pa_usec_t u) { + int timeout; + + if (u == PA_USEC_INVALID) + return -1; + + timeout = (u + PA_USEC_PER_MSEC - 1) / PA_USEC_PER_MSEC; + pa_assert(timeout >= 0); - assert(m); - assert(m->state == STATE_PREPARED); + return timeout; +} + +int pa_mainloop_poll(pa_mainloop *m) { + pa_assert(m); + pa_assert(m->state == STATE_PREPARED); if (m->quit) goto quit; m->state = STATE_POLLING; - if (m->deferred_pending) - r = 0; + if (m->n_enabled_defer_events ) + m->poll_func_ret = 0; else { + pa_assert(!m->rebuild_pollfds); + if (m->poll_func) - r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); - else - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + m->poll_func_ret = m->poll_func( + m->pollfds, m->n_pollfds, + usec_to_timeout(m->prepared_timeout), + m->poll_func_userdata); + else { +#ifdef HAVE_PPOLL + struct timespec ts; + + m->poll_func_ret = ppoll( + m->pollfds, m->n_pollfds, + m->prepared_timeout == PA_USEC_INVALID ? NULL : pa_timespec_store(&ts, m->prepared_timeout), + NULL); +#else + m->poll_func_ret = pa_poll( + m->pollfds, m->n_pollfds, + usec_to_timeout(m->prepared_timeout)); +#endif + } - if (r < 0) { + if (m->poll_func_ret < 0) { if (errno == EINTR) - r = 0; + m->poll_func_ret = 0; else - pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); + pa_log("poll(): %s", pa_cstrerror(errno)); } } - m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; - return r; + m->state = m->poll_func_ret < 0 ? STATE_PASSIVE : STATE_POLLED; + return m->poll_func_ret; quit: m->state = STATE_QUIT; @@ -705,32 +908,33 @@ quit: } int pa_mainloop_dispatch(pa_mainloop *m) { - int dispatched = 0; + unsigned dispatched = 0; - assert(m); - assert(m->state == STATE_POLLED); + pa_assert(m); + pa_assert(m->state == STATE_POLLED); if (m->quit) goto quit; - - if (m->deferred_pending) + + if (m->n_enabled_defer_events) dispatched += dispatch_defer(m); else { - dispatched += dispatch_timeout(m); - + if (m->n_enabled_time_events) + dispatched += dispatch_timeout(m); + if (m->quit) goto quit; - - dispatched += dispatch_pollfds(m); + if (m->poll_func_ret > 0) + dispatched += dispatch_pollfds(m); } - + if (m->quit) goto quit; - + m->state = STATE_PASSIVE; - return dispatched; + return (int) dispatched; quit: m->state = STATE_QUIT; @@ -738,13 +942,14 @@ quit: } int pa_mainloop_get_retval(pa_mainloop *m) { - assert(m); + pa_assert(m); + return m->retval; } int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { int r; - assert(m); + pa_assert(m); if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) goto quit; @@ -758,7 +963,7 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { return r; quit: - + if ((r == -2) && retval) *retval = pa_mainloop_get_retval(m); return r; @@ -766,8 +971,9 @@ quit: int pa_mainloop_run(pa_mainloop *m, int *retval) { int r; - - while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); + + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0) + ; if (r == -2) return 1; @@ -778,64 +984,28 @@ int pa_mainloop_run(pa_mainloop *m, int *retval) { } void pa_mainloop_quit(pa_mainloop *m, int retval) { - assert(m); + pa_assert(m); - m->quit = 1; + m->quit = TRUE; m->retval = retval; pa_mainloop_wakeup(m); } -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { - assert(m); +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop *m) { + pa_assert(m); + return &m->api; } void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { - assert(m); + pa_assert(m); m->poll_func = poll_func; m->poll_func_userdata = userdata; } +pa_bool_t pa_mainloop_is_our_api(pa_mainloop_api *m) { + pa_assert(m); -#if 0 -void pa_mainloop_dump(pa_mainloop *m) { - assert(m); - - pa_log(__FILE__": Dumping mainloop sources START"); - - { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); - } - } - - pa_log(__FILE__": Dumping mainloop sources STOP"); - + return m->io_new == mainloop_io_new; } -#endif |
