diff options
Diffstat (limited to 'trunk/avahi-core/timeeventq.c')
-rw-r--r-- | trunk/avahi-core/timeeventq.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/trunk/avahi-core/timeeventq.c b/trunk/avahi-core/timeeventq.c new file mode 100644 index 0000000..17334ee --- /dev/null +++ b/trunk/avahi-core/timeeventq.c @@ -0,0 +1,227 @@ +/* $Id$ */ + +/*** + 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-common/timeval.h> +#include <avahi-common/malloc.h> + +#include "timeeventq.h" +#include "log.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); +} + |