]> code.delx.au - pulseaudio/blobdiff - polyp/mainloop.c
Make the whole stuff LGPL only
[pulseaudio] / polyp / mainloop.c
index c678537eb5520c353354ecfd6b8f72e6cee99bd7..eb2eddc2ced61ede798352a2c3db28852bf3fb4f 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.
@@ -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;
+}