X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/964bdfd1e8255b57e9d22cd22b3784e2fc79b905..fa499dad06ba6558111cdef64c18f2401e803cff:/polyp/mainloop.c diff --git a/polyp/mainloop.c b/polyp/mainloop.c index c678537e..eb2eddc2 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + 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. @@ -13,7 +13,7 @@ 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 General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. @@ -37,9 +37,7 @@ #include "util.h" #include "idxset.h" #include "xmalloc.h" - -struct pa_base_event { -}; +#include "log.h" struct pa_io_event { struct pa_mainloop *mainloop; @@ -81,6 +79,8 @@ struct pa_mainloop { int quit, running, retval; struct pa_mainloop_api api; + + int deferred_pending; }; /* IO events */ @@ -149,17 +149,32 @@ struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callb e->destroy_callback = NULL; pa_idxset_put(m->defer_events, e, NULL); + + m->deferred_pending++; return e; } static void mainloop_defer_enable(struct pa_defer_event *e, int b) { assert(e); + + if (e->enabled && !b) { + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } else if (!e->enabled && b) + e->mainloop->deferred_pending++; + e->enabled = b; } static void mainloop_defer_free(struct pa_defer_event *e) { assert(e); e->dead = e->mainloop->defer_events_scan_dead = 1; + + if (e->enabled) { + e->enabled = 0; + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } } static void mainloop_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)) { @@ -189,6 +204,7 @@ static struct pa_time_event* mainloop_time_new(struct pa_mainloop_api*a, const s e->destroy_callback = NULL; pa_idxset_put(m->time_events, e, NULL); + return e; } @@ -204,6 +220,7 @@ static void mainloop_time_restart(struct pa_time_event *e, const struct timeval static void mainloop_time_free(struct pa_time_event *e) { assert(e); + e->dead = e->mainloop->time_events_scan_dead = 1; } @@ -225,24 +242,24 @@ static void mainloop_quit(struct pa_mainloop_api*a, int retval) { } static const struct pa_mainloop_api vtable = { - userdata: NULL, + .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, + .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, + .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, + .quit = mainloop_quit, }; struct pa_mainloop *pa_mainloop_new(void) { @@ -265,6 +282,8 @@ struct pa_mainloop *pa_mainloop_new(void) { m->api = vtable; m->api.userdata = m; + + m->deferred_pending = 0; return m; } @@ -274,7 +293,7 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -282,14 +301,14 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { struct pa_time_event *e = p; int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -297,14 +316,14 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { struct pa_defer_event *e = p; int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -312,7 +331,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} void pa_mainloop_free(struct pa_mainloop* m) { int all = 1; @@ -333,12 +352,15 @@ void pa_mainloop_free(struct pa_mainloop* m) { static void scan_dead(struct pa_mainloop *m) { int all = 0; assert(m); + 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); + + m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; } static void rebuild_pollfds(struct pa_mainloop *m) { @@ -375,11 +397,12 @@ static void rebuild_pollfds(struct pa_mainloop *m) { } } -static void dispatch_pollfds(struct pa_mainloop *m) { +static int dispatch_pollfds(struct pa_mainloop *m) { uint32_t index = PA_IDXSET_INVALID; struct pa_io_event *e; + int r = 0; - for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + for (e = pa_idxset_first(m->io_events, &index); e && !m->quit; e = pa_idxset_next(m->io_events, &index)) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; @@ -391,20 +414,27 @@ static void dispatch_pollfds(struct pa_mainloop *m) { (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), e->userdata); e->pollfd->revents = 0; + r++; } + + return r; } -static void dispatch_defer(struct pa_mainloop *m) { +static int dispatch_defer(struct pa_mainloop *m) { uint32_t index; struct pa_defer_event *e; + int r = 0; - for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { + for (e = pa_idxset_first(m->defer_events, &index); e && !m->quit; e = pa_idxset_next(m->defer_events, &index)) { if (e->dead || !e->enabled) continue; - + assert(e->callback); e->callback(&m->api, e, e->userdata); + r++; } + + return r; } static int calc_next_timeout(struct pa_mainloop *m) { @@ -412,18 +442,23 @@ static int calc_next_timeout(struct pa_mainloop *m) { struct pa_time_event *e; struct timeval now; int t = -1; + int got_time = 0; if (pa_idxset_isempty(m->time_events)) return -1; - gettimeofday(&now, NULL); - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { int tmp; if (e->dead || !e->enabled) continue; + /* Let's save a system call */ + if (!got_time) { + gettimeofday(&now, NULL); + 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)) return 0; @@ -443,71 +478,109 @@ static int calc_next_timeout(struct pa_mainloop *m) { return t; } -static void dispatch_timeout(struct pa_mainloop *m) { +static int dispatch_timeout(struct pa_mainloop *m) { uint32_t index; struct pa_time_event *e; struct timeval now; + int got_time = 0; + int r = 0; assert(m); if (pa_idxset_isempty(m->time_events)) - return; + return 0; - gettimeofday(&now, NULL); - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { + for (e = pa_idxset_first(m->time_events, &index); e && !m->quit; e = pa_idxset_next(m->time_events, &index)) { if (e->dead || !e->enabled) continue; + /* Let's save a system call */ + if (!got_time) { + gettimeofday(&now, NULL); + 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); e->enabled = 0; e->callback(&m->api, e, &e->timeval, e->userdata); + + r++; } } + + return r; } int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { - int r; + int r, t, dispatched = 0; assert(m && !m->running); - if(m->quit) { - if (retval) - *retval = m->retval; - return 1; - } - m->running = 1; + if(m->quit) + goto quit; + scan_dead(m); - dispatch_defer(m); + dispatched += dispatch_defer(m); + if(m->quit) + goto quit; + if (m->rebuild_pollfds) { rebuild_pollfds(m); m->rebuild_pollfds = 0; } - do { - int t = block ? calc_next_timeout(m) : 0; - /*fprintf(stderr, "%u\n", t);*/ - r = poll(m->pollfds, m->n_pollfds, t); - } while (r < 0 && errno == EINTR); + t = block ? calc_next_timeout(m) : 0; + r = poll(m->pollfds, m->n_pollfds, t); + + if (r < 0) { + if (errno == EINTR) + r = 0; + else + pa_log(__FILE__": select(): %s\n", strerror(errno)); + } else { + dispatched += dispatch_timeout(m); + + if(m->quit) + goto quit; + + if (r > 0) { + dispatched += dispatch_pollfds(m); - dispatch_timeout(m); + if(m->quit) + goto quit; + } + } - if (r > 0) - dispatch_pollfds(m); - else if (r < 0) - fprintf(stderr, "select(): %s\n", strerror(errno)); + m->running = 0; + +/* pa_log("dispatched: %i\n", dispatched); */ + return r < 0 ? -1 : dispatched; + +quit: + m->running = 0; - return r < 0 ? -1 : 0; + + if (retval) + *retval = m->retval; + + return -2; } int pa_mainloop_run(struct pa_mainloop *m, int *retval) { int r; - while ((r = pa_mainloop_iterate(m, 1, retval)) == 0); - return 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(struct pa_mainloop *m, int r) { @@ -519,3 +592,8 @@ struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { assert(m); return &m->api; } + +int pa_mainloop_deferred_pending(struct pa_mainloop *m) { + assert(m); + return m->deferred_pending > 0; +}