diff options
author | Lennart Poettering <lennart@poettering.net> | 2008-03-15 15:15:36 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2008-03-15 15:15:36 +0000 |
commit | 8d9bdaca5a4092cd078d79c58c4bfa0da277bff4 (patch) | |
tree | cbb37fd94b84fb8547c50f07f50c81b26098be99 /src/pulse/mainloop.c | |
parent | dd81a907a7a596c20284baf44977dcb6a9d8cf91 (diff) | |
parent | 6ad7621b61d40dba9b877379ef5f15f73a2ed268 (diff) |
really create glitch-free branch
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2120 fefdeb5f-60dc-0310-8127-8f9354f1896f
Diffstat (limited to 'src/pulse/mainloop.c')
-rw-r--r-- | src/pulse/mainloop.c | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c new file mode 100644 index 00000000..ad4e4e97 --- /dev/null +++ b/src/pulse/mainloop.c @@ -0,0 +1,965 @@ +/* $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, + 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 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#ifdef HAVE_POLL_H +#include <poll.h> +#else +#include <pulsecore/poll.h> +#endif + +#ifndef HAVE_PIPE +#include <pulsecore/pipe.h> +#endif + +#include <pulse/timeval.h> +#include <pulse/xmalloc.h> + +#include <pulsecore/core-util.h> +#include <pulsecore/llist.h> +#include <pulsecore/log.h> +#include <pulsecore/core-error.h> +#include <pulsecore/winsock.h> +#include <pulsecore/macro.h> + +#include "mainloop.h" + +struct pa_io_event { + pa_mainloop *mainloop; + int dead; + + int fd; + pa_io_event_flags_t events; + struct pollfd *pollfd; + + pa_io_event_cb_t callback; + 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; + + pa_time_event_cb_t callback; + 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; + + pa_defer_event_cb_t callback; + void *userdata; + pa_defer_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_defer_event); +}; + +struct pa_mainloop { + PA_LLIST_HEAD(pa_io_event, io_events); + PA_LLIST_HEAD(pa_time_event, time_events); + PA_LLIST_HEAD(pa_defer_event, defer_events); + + int n_enabled_defer_events, n_enabled_time_events, n_io_events; + int io_events_please_scan, time_events_please_scan, defer_events_please_scan; + + struct pollfd *pollfds; + unsigned max_pollfds, n_pollfds; + int rebuild_pollfds; + + int prepared_timeout; + pa_time_event *cached_next_time_event; + + int quit, retval; + pa_mainloop_api api; + + int wakeup_pipe[2]; + int wakeup_pipe_type; + int wakeup_requested; + + enum { + STATE_PASSIVE, + STATE_PREPARED, + STATE_POLLING, + STATE_POLLED, + STATE_QUIT + } state; + + 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 + (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, + pa_io_event_cb_t callback, + void *userdata) { + + pa_mainloop *m; + pa_io_event *e; + + pa_assert(a); + pa_assert(a->userdata); + pa_assert(fd >= 0); + pa_assert(callback); + + m = a->userdata; + pa_assert(a == &m->api); + + e = pa_xnew(pa_io_event, 1); + e->mainloop = m; + e->dead = 0; + + e->fd = fd; + e->events = events; + e->pollfd = NULL; + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + +#ifdef OS_IS_WIN32 + { + fd_set xset; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&xset); + FD_SET (fd, &xset); + + if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &tv) == -1) && + (WSAGetLastError() == WSAENOTSOCK)) { + pa_log_warn("Cannot monitor non-socket file descriptors."); + e->dead = 1; + } + } +#endif + + PA_LLIST_PREPEND(pa_io_event, m->io_events, e); + m->rebuild_pollfds = 1; + m->n_io_events ++; + + pa_mainloop_wakeup(m); + + return e; +} + +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { + pa_assert(e); + pa_assert(!e->dead); + + if (e->events == events) + return; + + e->events = events; + + if (e->pollfd) + e->pollfd->events = map_flags_to_libc(events); + else + e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); +} + +static void mainloop_io_free(pa_io_event *e) { + pa_assert(e); + pa_assert(!e->dead); + + e->dead = 1; + e->mainloop->io_events_please_scan ++; + + e->mainloop->n_io_events --; + e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); +} + +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, + pa_defer_event_cb_t callback, + void *userdata) { + + pa_mainloop *m; + pa_defer_event *e; + + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); + + m = a->userdata; + pa_assert(a == &m->api); + + e = pa_xnew(pa_defer_event, 1); + e->mainloop = m; + e->dead = 0; + + e->enabled = 1; + m->n_enabled_defer_events++; + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + PA_LLIST_PREPEND(pa_defer_event, m->defer_events, e); + + pa_mainloop_wakeup(e->mainloop); + + return e; +} + +static void mainloop_defer_enable(pa_defer_event *e, int b) { + pa_assert(e); + pa_assert(!e->dead); + + if (e->enabled && !b) { + pa_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; + } else if (!e->enabled && b) { + e->mainloop->n_enabled_defer_events++; + pa_mainloop_wakeup(e->mainloop); + } + + e->enabled = b; +} + +static void mainloop_defer_free(pa_defer_event *e) { + pa_assert(e); + pa_assert(!e->dead); + + e->dead = 1; + e->mainloop->defer_events_please_scan ++; + + if (e->enabled) { + pa_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; + e->enabled = 0; + } +} + +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, + pa_time_event_cb_t callback, + void *userdata) { + + pa_mainloop *m; + pa_time_event *e; + + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); + + m = a->userdata; + pa_assert(a == &m->api); + + e = pa_xnew(pa_time_event, 1); + e->mainloop = m; + e->dead = 0; + + if ((e->enabled = !!tv)) { + e->timeval = *tv; + + m->n_enabled_time_events++; + + if (m->cached_next_time_event) { + pa_assert(m->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0) + m->cached_next_time_event = e; + } + } + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = 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) { + pa_assert(e); + pa_assert(!e->dead); + + if (e->enabled && !tv) { + pa_assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + } else if (!e->enabled && tv) + e->mainloop->n_enabled_time_events++; + + if ((e->enabled = !!tv)) { + e->timeval = *tv; + pa_mainloop_wakeup(e->mainloop); + } + + if (e->mainloop->cached_next_time_event && e->enabled) { + pa_assert(e->mainloop->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) + 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) { + pa_assert(e); + pa_assert(!e->dead); + + e->dead = 1; + 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 = 0; + } + + 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, 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) { + pa_mainloop *m; + + pa_assert(a); + pa_assert(a->userdata); + m = a->userdata; + 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, + + .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_xnew(pa_mainloop, 1); + + m->wakeup_pipe_type = 0; + if (pipe(m->wakeup_pipe) < 0) { + pa_log_error("ERROR: cannot create wakeup pipe"); + pa_xfree(m); + return NULL; + } + + pa_make_fd_nonblock(m->wakeup_pipe[0]); + pa_make_fd_nonblock(m->wakeup_pipe[1]); + pa_make_fd_cloexec(m->wakeup_pipe[0]); + pa_make_fd_cloexec(m->wakeup_pipe[1]); + m->wakeup_requested = 0; + + PA_LLIST_HEAD_INIT(pa_io_event, m->io_events); + PA_LLIST_HEAD_INIT(pa_time_event, m->time_events); + PA_LLIST_HEAD_INIT(pa_defer_event, m->defer_events); + + m->n_enabled_defer_events = m->n_enabled_time_events = m->n_io_events = 0; + m->io_events_please_scan = m->time_events_please_scan = m->defer_events_please_scan = 0; + + m->cached_next_time_event = NULL; + m->prepared_timeout = 0; + + m->pollfds = NULL; + m->max_pollfds = m->n_pollfds = 0; + m->rebuild_pollfds = 1; + + m->quit = m->retval = 0; + + m->api = vtable; + m->api.userdata = m; + + m->state = STATE_PASSIVE; + + m->poll_func = NULL; + m->poll_func_userdata = NULL; + m->poll_func_ret = -1; + + return m; +} + +static void cleanup_io_events(pa_mainloop *m, int force) { + pa_io_event *e; + + e = m->io_events; + while (e) { + pa_io_event *n = e->next; + + 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 = 1; + } + + e = n; + } + + pa_assert(m->io_events_please_scan == 0); +} + +static void cleanup_time_events(pa_mainloop *m, int force) { + pa_time_event *e; + + e = m->time_events; + while (e) { + pa_time_event *n = e->next; + + 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 = 0; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + pa_assert(m->time_events_please_scan == 0); +} + +static void cleanup_defer_events(pa_mainloop *m, int force) { + pa_defer_event *e; + + e = m->defer_events; + while (e) { + pa_defer_event *n = e->next; + + 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 = 0; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + pa_assert(m->defer_events_please_scan == 0); +} + + +void pa_mainloop_free(pa_mainloop* m) { + pa_assert(m); + + cleanup_io_events(m, 1); + cleanup_defer_events(m, 1); + cleanup_time_events(m, 1); + + pa_xfree(m->pollfds); + + pa_close_pipe(m->wakeup_pipe); + + pa_xfree(m); +} + +static void scan_dead(pa_mainloop *m) { + pa_assert(m); + + if (m->io_events_please_scan) + cleanup_io_events(m, 0); + + if (m->time_events_please_scan) + cleanup_time_events(m, 0); + + if (m->defer_events_please_scan) + cleanup_defer_events(m, 0); +} + +static void rebuild_pollfds(pa_mainloop *m) { + pa_io_event*e; + struct pollfd *p; + unsigned l; + + 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; + } + + m->n_pollfds = 0; + p = m->pollfds; + + if (m->wakeup_pipe[0] >= 0) { + m->pollfds[0].fd = m->wakeup_pipe[0]; + m->pollfds[0].events = POLLIN; + m->pollfds[0].revents = 0; + p++; + m->n_pollfds++; + } + + for (e = m->io_events; e; e = e->next) { + if (e->dead) { + e->pollfd = NULL; + continue; + } + + e->pollfd = p; + p->fd = e->fd; + p->events = map_flags_to_libc(e->events); + p->revents = 0; + + p++; + m->n_pollfds++; + } + + m->rebuild_pollfds = 0; +} + +static int dispatch_pollfds(pa_mainloop *m) { + pa_io_event *e; + int r = 0, k; + + pa_assert(m->poll_func_ret > 0); + + for (e = m->io_events, k = m->poll_func_ret; e && !m->quit && k > 0; e = e->next) { + if (e->dead || !e->pollfd || !e->pollfd->revents) + continue; + + 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) { + pa_defer_event *e; + int r = 0; + + if (m->n_enabled_defer_events <= 0) + return 0; + + for (e = m->defer_events; e && !m->quit; e = e->next) { + if (e->dead || !e->enabled) + continue; + + pa_assert(e->callback); + e->callback(&m->api, e, e->userdata); + r++; + } + + return r; +} + +static pa_time_event* find_next_time_event(pa_mainloop *m) { + pa_time_event *t, *n = NULL; + pa_assert(m); + + if (m->cached_next_time_event) + return m->cached_next_time_event; + + for (t = m->time_events; t; t = t->next) { + + if (t->dead || !t->enabled) + continue; + + if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { + n = t; + + /* Shortcut for tv = { 0, 0 } */ + if (n->timeval.tv_sec <= 0) + break; + } + } + + m->cached_next_time_event = n; + return n; +} + +static int calc_next_timeout(pa_mainloop *m) { + pa_time_event *t; + struct timeval now; + pa_usec_t usec; + + if (!m->n_enabled_time_events) + return -1; + + t = find_next_time_event(m); + pa_assert(t); + + if (t->timeval.tv_sec <= 0) + return 0; + + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&t->timeval, &now) <= 0) + return 0; + + usec = pa_timeval_diff(&t->timeval, &now); + return (int) (usec / 1000); +} + +static int dispatch_timeout(pa_mainloop *m) { + pa_time_event *e; + struct timeval now; + int r = 0; + pa_assert(m); + + if (m->n_enabled_time_events <= 0) + return 0; + + pa_gettimeofday(&now); + + for (e = m->time_events; e && !m->quit; e = e->next) { + + if (e->dead || !e->enabled) + continue; + + if (pa_timeval_cmp(&e->timeval, &now) <= 0) { + pa_assert(e->callback); + + /* Disable time event */ + mainloop_time_restart(e, NULL); + + e->callback(&m->api, e, &e->timeval, e->userdata); + + r++; + } + } + + return r; +} + +void pa_mainloop_wakeup(pa_mainloop *m) { + char c = 'W'; + pa_assert(m); + + 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]; + + pa_assert(m); + + if (m->wakeup_pipe[0] < 0) + return; + + 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) { + pa_assert(m); + pa_assert(m->state == STATE_PASSIVE); + + clear_wakeup(m); + scan_dead(m); + + if (m->quit) + goto quit; + + 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; + } + + m->state = STATE_PREPARED; + return 0; + +quit: + m->state = STATE_QUIT; + return -2; +} + +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->n_enabled_defer_events ) + m->poll_func_ret = 0; + else { + pa_assert(!m->rebuild_pollfds); + + if (m->poll_func) + m->poll_func_ret = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); + else + m->poll_func_ret = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + + if (m->poll_func_ret < 0) { + if (errno == EINTR) + m->poll_func_ret = 0; + else + pa_log("poll(): %s", pa_cstrerror(errno)); + } + } + + m->state = m->poll_func_ret < 0 ? STATE_PASSIVE : STATE_POLLED; + return m->poll_func_ret; + +quit: + m->state = STATE_QUIT; + return -2; +} + +int pa_mainloop_dispatch(pa_mainloop *m) { + int dispatched = 0; + + pa_assert(m); + pa_assert(m->state == STATE_POLLED); + + if (m->quit) + goto quit; + + if (m->n_enabled_defer_events) + dispatched += dispatch_defer(m); + else { + if (m->n_enabled_time_events) + dispatched += dispatch_timeout(m); + + if (m->quit) + goto quit; + + if (m->poll_func_ret > 0) + dispatched += dispatch_pollfds(m); + } + + if (m->quit) + goto quit; + + m->state = STATE_PASSIVE; + + return dispatched; + +quit: + m->state = STATE_QUIT; + return -2; +} + +int pa_mainloop_get_retval(pa_mainloop *m) { + pa_assert(m); + return m->retval; +} + +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { + int r; + pa_assert(m); + + if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) + goto quit; + + if ((r = pa_mainloop_poll(m)) < 0) + goto quit; + + if ((r = pa_mainloop_dispatch(m)) < 0) + goto quit; + + return r; + +quit: + + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; +} + +int pa_mainloop_run(pa_mainloop *m, int *retval) { + int r; + + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); + + if (r == -2) + return 1; + else if (r < 0) + return -1; + else + return 0; +} + +void pa_mainloop_quit(pa_mainloop *m, int retval) { + pa_assert(m); + + m->quit = 1; + m->retval = retval; + pa_mainloop_wakeup(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) { + pa_assert(m); + + m->poll_func = poll_func; + m->poll_func_userdata = userdata; +} |