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 <stdio.h>
#include <signal.h>
#include <unistd.h>
-#include <sys/poll.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 "poll.h"
+#endif
+
+#include "winsock.h"
+
#include "mainloop.h"
#include "util.h"
#include "idxset.h"
#include "xmalloc.h"
+#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;
e->pollfd = 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(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n");
+ e->dead = 1;
+ }
+ }
+#endif
+
pa_idxset_put(m->io_events, e, NULL);
m->rebuild_pollfds = 1;
return e;
e->pollfd->events =
(events & PA_IO_EVENT_INPUT ? POLLIN : 0) |
(events & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) |
- POLLHUP |
- POLLERR;
+ POLLERR | POLLHUP;
}
static void mainloop_io_free(struct pa_io_event *e) {
}
/* Defer events */
-struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) {
+static struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) {
struct pa_mainloop *m;
struct pa_defer_event *e;
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)) {
m->api = vtable;
m->api.userdata = m;
+
+ m->deferred_pending = 0;
return 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)) {
+ if (!m->deferred_pending)
+ return 0;
+
+ 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) {
/* Let's save a system call */
if (!got_time) {
- gettimeofday(&now, NULL);
+ pa_gettimeofday(&now);
got_time = 1;
}
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;
- 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);
+ pa_gettimeofday(&now);
got_time = 1;
}
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;
+ m->running ++;
+
+ 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;
- dispatch_timeout(m);
+ 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);
+
+ if(m->quit)
+ goto quit;
+ }
+ }
- if (r > 0)
- dispatch_pollfds(m);
- else if (r < 0)
- fprintf(stderr, "select(): %s\n", strerror(errno));
+ m->running--;
+
+/* pa_log("dispatched: %i\n", dispatched); */
+
+ return r < 0 ? -1 : dispatched;
+
+quit:
+
+ m->running--;
+
+ if (retval)
+ *retval = m->retval;
- m->running = 0;
- return r < 0 ? -1 : 0;
+ 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;
+}
+
+
+void pa_mainloop_dump(struct pa_mainloop *m) {
+ assert(m);
+
+ pa_log(__FILE__": Dumping mainloop sources START\n");
+
+ {
+ uint32_t index = PA_IDXSET_INVALID;
+ struct pa_io_event *e;
+ for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) {
+ if (e->dead)
+ continue;
+
+ pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata);
+ }
+ }
+ {
+ uint32_t index = PA_IDXSET_INVALID;
+ struct pa_defer_event *e;
+ for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) {
+ if (e->dead)
+ continue;
+
+ pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata);
+ }
+ }
+ {
+ uint32_t index = PA_IDXSET_INVALID;
+ struct pa_time_event *e;
+ for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) {
+ if (e->dead)
+ continue;
+
+ pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", 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\n");
+
+}