]> git.meshlink.io Git - catta/blobdiff - avahi-core/timeeventq.c
implement new main loop abstraction layer
[catta] / avahi-core / timeeventq.c
index efce7b7d1e2769be055dd1554fc9d425859b7467..88e17792e09436f8cf43d3c7fcb2e7a1d80e3dbb 100644 (file)
 #include <config.h>
 #endif
 
+#include <avahi-common/timeval.h>
 #include "timeeventq.h"
-#include "util.h"
 
 static gint compare(gconstpointer _a, gconstpointer _b) {
     const AvahiTimeEvent *a = _a,  *b = _b;
+    gint ret;
 
-    return avahi_timeval_compare(&a->expiry, &b->expiry);
+    if ((ret = avahi_timeval_compare(&a->expiry, &b->expiry)) != 0)
+        return ret;
+
+    /* If both exevents are scheduled for the same time, put the entry
+     * that has been run earlier the last time first. */
+    return avahi_timeval_compare(&a->last_run, &b->last_run);
+}
+
+static void source_get_timeval(GSource *source, struct timeval *tv) {
+    GTimeVal gtv;
+    
+    g_assert(source);
+    g_assert(tv);
+
+    g_source_get_current_time(source, &gtv);
+    tv->tv_sec = gtv.tv_sec;
+    tv->tv_usec = gtv.tv_usec;
 }
 
 static gboolean prepare_func(GSource *source, gint *timeout) {
     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
     AvahiTimeEvent *e;
-    GTimeVal now;
+    struct timeval now;
 
     g_assert(source);
     g_assert(timeout);
@@ -48,14 +65,19 @@ static gboolean prepare_func(GSource *source, gint *timeout) {
     e = q->prioq->root->data;
     g_assert(e);
 
-    g_source_get_current_time(source, &now);
+    source_get_timeval(source, &now);
 
-    if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
+    if (avahi_timeval_compare(&now, &e->expiry) >= 0 &&  /* Time elapsed */
+        avahi_timeval_compare(&now, &e->last_run) != 0   /* Not yet run */) {
         *timeout = -1;
         return TRUE;
     }
 
     *timeout = (gint) (avahi_timeval_diff(&e->expiry, &now)/1000);
+
+    /* Wait at least 1 msec */
+    if (*timeout <= 0)
+        *timeout = 1;
     
     return FALSE;
 }
@@ -63,7 +85,7 @@ static gboolean prepare_func(GSource *source, gint *timeout) {
 static gboolean check_func(GSource *source) {
     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
     AvahiTimeEvent *e;
-    GTimeVal now;
+    struct timeval now;
 
     g_assert(source);
 
@@ -73,25 +95,37 @@ static gboolean check_func(GSource *source) {
     e = q->prioq->root->data;
     g_assert(e);
 
-    g_source_get_current_time(source, &now);
+    source_get_timeval(source, &now);
     
-    return avahi_timeval_compare(&now, &e->expiry) >= 0;
+    return
+        avahi_timeval_compare(&now, &e->expiry) >= 0 && /* Time elapsed */
+        avahi_timeval_compare(&now, &e->last_run) != 0;  /* Not yet run */
 }
 
 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
-    GTimeVal now;
+    struct timeval now;
 
     g_assert(source);
 
-    g_source_get_current_time(source, &now);
+    source_get_timeval(source, &now);
 
     while (q->prioq->root) {
         AvahiTimeEvent *e = q->prioq->root->data;
 
+        /* Not yet expired */
         if (avahi_timeval_compare(&now, &e->expiry) < 0)
             break;
 
+        /* Already ran */
+        if (avahi_timeval_compare(&now, &e->last_run) == 0)
+            break;
+
+        /* Make sure to move the entry away from the front */
+        e->last_run = now;
+        avahi_prio_queue_shuffle(q->prioq, e->node);
+
+        /* Run it */
         g_assert(e->callback);
         e->callback(e, e->userdata);
     }
@@ -99,6 +133,17 @@ static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer us
     return TRUE;
 }
 
+static void fix_expiry_time(AvahiTimeEvent *e) {
+    struct timeval now;
+    g_assert(e);
+
+    source_get_timeval(&e->queue->source, &now);
+
+    if (avahi_timeval_compare(&now, &e->expiry) > 0)
+        e->expiry = now;
+    
+}
+
 AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority) {
     AvahiTimeEventQueue *q;
 
@@ -132,7 +177,7 @@ void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
     g_source_unref(&q->source);
 }
 
-AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(AvahiTimeEvent *e, void *userdata), void *userdata) {
+AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const struct timeval *timeval, AvahiTimeEventCallback callback, gpointer userdata) {
     AvahiTimeEvent *e;
     
     g_assert(q);
@@ -142,10 +187,15 @@ AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVa
 
     e = g_new(AvahiTimeEvent, 1);
     e->queue = q;
-    e->expiry = *timeval;
     e->callback = callback;
     e->userdata = userdata;
 
+    e->expiry = *timeval;
+    fix_expiry_time(e);
+    
+    e->last_run.tv_sec = 0;
+    e->last_run.tv_usec = 0;
+
     e->node = avahi_prio_queue_put(q->prioq, e);
     
     return e;
@@ -160,12 +210,14 @@ void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e) {
     g_free(e);
 }
 
-void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const GTimeVal *timeval) {
+void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const struct timeval *timeval) {
     g_assert(q);
     g_assert(e);
     g_assert(e->queue == q);
+    g_assert(timeval);
 
     e->expiry = *timeval;
+    fix_expiry_time(e);
 
     avahi_prio_queue_shuffle(q->prioq, e->node);
 }