]> git.meshlink.io Git - catta/blobdiff - src/timeeventq.c
move public headers into their own directory
[catta] / src / timeeventq.c
diff --git a/src/timeeventq.c b/src/timeeventq.c
new file mode 100644 (file)
index 0000000..d7ae12f
--- /dev/null
@@ -0,0 +1,225 @@
+/***
+  This file is part of avahi.
+
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <avahi/timeval.h>
+#include <avahi/malloc.h>
+#include <avahi/log.h>
+
+#include "timeeventq.h"
+
+struct AvahiTimeEvent {
+    AvahiTimeEventQueue *queue;
+    AvahiPrioQueueNode *node;
+    struct timeval expiry;
+    struct timeval last_run;
+    AvahiTimeEventCallback callback;
+    void* userdata;
+};
+
+struct AvahiTimeEventQueue {
+    const AvahiPoll *poll_api;
+    AvahiPrioQueue *prioq;
+    AvahiTimeout *timeout;
+};
+
+static int compare(const void* _a, const void* _b) {
+    const AvahiTimeEvent *a = _a,  *b = _b;
+    int ret;
+
+    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 AvahiTimeEvent* time_event_queue_root(AvahiTimeEventQueue *q) {
+    assert(q);
+
+    return q->prioq->root ? q->prioq->root->data : NULL;
+}
+
+static void update_timeout(AvahiTimeEventQueue *q) {
+    AvahiTimeEvent *e;
+    assert(q);
+
+    if ((e = time_event_queue_root(q)))
+        q->poll_api->timeout_update(q->timeout, &e->expiry);
+    else
+        q->poll_api->timeout_update(q->timeout, NULL);
+}
+
+static void expiration_event(AVAHI_GCC_UNUSED AvahiTimeout *timeout, void *userdata) {
+    AvahiTimeEventQueue *q = userdata;
+    AvahiTimeEvent *e;
+
+    if ((e = time_event_queue_root(q))) {
+        struct timeval now;
+
+        gettimeofday(&now, NULL);
+
+        /* Check if expired */
+        if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
+
+            /* Make sure to move the entry away from the front */
+            e->last_run = now;
+            avahi_prio_queue_shuffle(q->prioq, e->node);
+
+            /* Run it */
+            assert(e->callback);
+            e->callback(e, e->userdata);
+
+            update_timeout(q);
+            return;
+        }
+    }
+
+    avahi_log_debug(__FILE__": Strange, expiration_event() called, but nothing really happened.");
+    update_timeout(q);
+}
+
+static void fix_expiry_time(AvahiTimeEvent *e) {
+    struct timeval now;
+    assert(e);
+
+    return; /*** DO WE REALLY NEED THIS? ***/
+
+    gettimeofday(&now, NULL);
+
+    if (avahi_timeval_compare(&now, &e->expiry) > 0)
+        e->expiry = now;
+}
+
+AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) {
+    AvahiTimeEventQueue *q;
+
+    if (!(q = avahi_new(AvahiTimeEventQueue, 1))) {
+        avahi_log_error(__FILE__": Out of memory");
+        goto oom;
+    }
+
+    q->poll_api = poll_api;
+
+    if (!(q->prioq = avahi_prio_queue_new(compare)))
+        goto oom;
+
+    if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q)))
+        goto oom;
+
+    return q;
+
+oom:
+
+    if (q) {
+        avahi_free(q);
+
+        if (q->prioq)
+            avahi_prio_queue_free(q->prioq);
+    }
+
+    return NULL;
+}
+
+void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
+    AvahiTimeEvent *e;
+
+    assert(q);
+
+    while ((e = time_event_queue_root(q)))
+        avahi_time_event_free(e);
+    avahi_prio_queue_free(q->prioq);
+
+    q->poll_api->timeout_free(q->timeout);
+
+    avahi_free(q);
+}
+
+AvahiTimeEvent* avahi_time_event_new(
+    AvahiTimeEventQueue *q,
+    const struct timeval *timeval,
+    AvahiTimeEventCallback callback,
+    void* userdata) {
+
+    AvahiTimeEvent *e;
+
+    assert(q);
+    assert(callback);
+    assert(userdata);
+
+    if (!(e = avahi_new(AvahiTimeEvent, 1))) {
+        avahi_log_error(__FILE__": Out of memory");
+        return NULL; /* OOM */
+    }
+
+    e->queue = q;
+    e->callback = callback;
+    e->userdata = userdata;
+
+    if (timeval)
+        e->expiry = *timeval;
+    else {
+        e->expiry.tv_sec = 0;
+        e->expiry.tv_usec = 0;
+    }
+
+    fix_expiry_time(e);
+
+    e->last_run.tv_sec = 0;
+    e->last_run.tv_usec = 0;
+
+    if (!(e->node = avahi_prio_queue_put(q->prioq, e))) {
+        avahi_free(e);
+        return NULL;
+    }
+
+    update_timeout(q);
+    return e;
+}
+
+void avahi_time_event_free(AvahiTimeEvent *e) {
+    AvahiTimeEventQueue *q;
+    assert(e);
+
+    q = e->queue;
+
+    avahi_prio_queue_remove(q->prioq, e->node);
+    avahi_free(e);
+
+    update_timeout(q);
+}
+
+void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) {
+    assert(e);
+    assert(timeval);
+
+    e->expiry = *timeval;
+    fix_expiry_time(e);
+    avahi_prio_queue_shuffle(e->queue->prioq, e->node);
+
+    update_timeout(e->queue);
+}
+