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.
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.
#include "util.h"
#include "idxset.h"
#include "xmalloc.h"
-
-struct pa_base_event {
-};
+#include "log.h"
struct pa_io_event {
struct pa_mainloop *mainloop;
int quit, running, retval;
struct pa_mainloop_api api;
+
+ int deferred_pending;
};
/* IO events */
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)) {
e->destroy_callback = NULL;
pa_idxset_put(m->time_events, e, NULL);
+
return e;
}
static void mainloop_time_free(struct pa_time_event *e) {
assert(e);
+
e->dead = e->mainloop->time_events_scan_dead = 1;
}
}
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) {
m->api = vtable;
m->api.userdata = m;
+
+ m->deferred_pending = 0;
return m;
}
int *all = userdata;
assert(e && del && all);
- if (!*all || !e->dead)
+ if (!*all && !e->dead)
return 0;
if (e->destroy_callback)
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)
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)
pa_xfree(e);
*del = 1;
return 0;
-};
+}
void pa_mainloop_free(struct pa_mainloop* m) {
int all = 1;
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) {
}
}
-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;
(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) {
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;
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) {
assert(m);
return &m->api;
}
+
+int pa_mainloop_deferred_pending(struct pa_mainloop *m) {
+ assert(m);
+ return m->deferred_pending > 0;
+}