]> code.delx.au - pulseaudio/blobdiff - polyp/mainloop.c
Merge Pierre's changes
[pulseaudio] / polyp / mainloop.c
index 83f0b1e828cf7a013a2a8a5d0749db206adaf069..ada74afc8281b6003bb7b2d4d6c17f415031862e 100644 (file)
@@ -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.
 #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;
@@ -78,6 +86,8 @@ struct pa_mainloop {
 
     int quit, running, retval;
     struct pa_mainloop_api api;
+
+    int deferred_pending;
 };
 
 /* IO events */
@@ -100,6 +110,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu
     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;
@@ -113,8 +143,7 @@ static void mainloop_io_enable(struct pa_io_event *e, enum pa_io_event_flags eve
         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) {
@@ -128,7 +157,7 @@ static void mainloop_io_set_destroy(struct pa_io_event *e, void (*callback)(stru
 }
 
 /* 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;
 
@@ -146,17 +175,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)) {
@@ -264,6 +308,8 @@ struct pa_mainloop *pa_mainloop_new(void) {
 
     m->api = vtable;
     m->api.userdata = m;
+
+    m->deferred_pending = 0;
     
     return m;
 }
@@ -377,11 +423,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;
         
@@ -393,20 +440,30 @@ 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)) {
+    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) {
@@ -427,7 +484,7 @@ 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;
         }
 
@@ -450,24 +507,25 @@ 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;
 
-    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;
         }
         
@@ -476,51 +534,83 @@ static void dispatch_timeout(struct pa_mainloop *m) {
 
             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) {
@@ -532,3 +622,49 @@ 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;
+}
+
+
+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");
+
+}