1/* $Id$ */ 2 3/*** 4 This file is part of avahi. 5 6 avahi is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 avahi is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with avahi; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 USA. 20***/ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <assert.h> 27#include <stdlib.h> 28 29#include <avahi-common/timeval.h> 30#include <avahi-common/malloc.h> 31 32#include "timeeventq.h" 33#include "log.h" 34 35struct AvahiTimeEvent { 36 AvahiTimeEventQueue *queue; 37 AvahiPrioQueueNode *node; 38 struct timeval expiry; 39 struct timeval last_run; 40 AvahiTimeEventCallback callback; 41 void* userdata; 42}; 43 44struct AvahiTimeEventQueue { 45 const AvahiPoll *poll_api; 46 AvahiPrioQueue *prioq; 47 AvahiTimeout *timeout; 48}; 49 50static int compare(const void* _a, const void* _b) { 51 const AvahiTimeEvent *a = _a, *b = _b; 52 int ret; 53 54 if ((ret = avahi_timeval_compare(&a->expiry, &b->expiry)) != 0) 55 return ret; 56 57 /* If both exevents are scheduled for the same time, put the entry 58 * that has been run earlier the last time first. */ 59 return avahi_timeval_compare(&a->last_run, &b->last_run); 60} 61 62static AvahiTimeEvent* time_event_queue_root(AvahiTimeEventQueue *q) { 63 assert(q); 64 65 return q->prioq->root ? q->prioq->root->data : NULL; 66} 67 68static void update_timeout(AvahiTimeEventQueue *q) { 69 AvahiTimeEvent *e; 70 assert(q); 71 72 if ((e = time_event_queue_root(q))) 73 q->poll_api->timeout_update(q->timeout, &e->expiry); 74 else 75 q->poll_api->timeout_update(q->timeout, NULL); 76} 77 78static void expiration_event(AVAHI_GCC_UNUSED AvahiTimeout *timeout, void *userdata) { 79 AvahiTimeEventQueue *q = userdata; 80 AvahiTimeEvent *e; 81 82 if ((e = time_event_queue_root(q))) { 83 struct timeval now; 84 85 gettimeofday(&now, NULL); 86 87 /* Check if expired */ 88 if (avahi_timeval_compare(&now, &e->expiry) >= 0) { 89 90 /* Make sure to move the entry away from the front */ 91 e->last_run = now; 92 avahi_prio_queue_shuffle(q->prioq, e->node); 93 94 /* Run it */ 95 assert(e->callback); 96 e->callback(e, e->userdata); 97 98 update_timeout(q); 99 return; 100 } 101 } 102 103 avahi_log_debug(__FILE__": Strange, expiration_event() called, but nothing really happened."); 104 update_timeout(q); 105} 106 107static void fix_expiry_time(AvahiTimeEvent *e) { 108 struct timeval now; 109 assert(e); 110 111 return; /*** DO WE REALLY NEED THIS? ***/ 112 113 gettimeofday(&now, NULL); 114 115 if (avahi_timeval_compare(&now, &e->expiry) > 0) 116 e->expiry = now; 117} 118 119AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) { 120 AvahiTimeEventQueue *q; 121 122 if (!(q = avahi_new(AvahiTimeEventQueue, 1))) { 123 avahi_log_error(__FILE__": Out of memory"); 124 goto oom; 125 } 126 127 q->poll_api = poll_api; 128 129 if (!(q->prioq = avahi_prio_queue_new(compare))) 130 goto oom; 131 132 if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q))) 133 goto oom; 134 135 return q; 136 137oom: 138 139 if (q) { 140 avahi_free(q); 141 142 if (q->prioq) 143 avahi_prio_queue_free(q->prioq); 144 } 145 146 return NULL; 147} 148 149void avahi_time_event_queue_free(AvahiTimeEventQueue *q) { 150 AvahiTimeEvent *e; 151 152 assert(q); 153 154 while ((e = time_event_queue_root(q))) 155 avahi_time_event_free(e); 156 avahi_prio_queue_free(q->prioq); 157 158 q->poll_api->timeout_free(q->timeout); 159 160 avahi_free(q); 161} 162 163AvahiTimeEvent* avahi_time_event_new( 164 AvahiTimeEventQueue *q, 165 const struct timeval *timeval, 166 AvahiTimeEventCallback callback, 167 void* userdata) { 168 169 AvahiTimeEvent *e; 170 171 assert(q); 172 assert(callback); 173 assert(userdata); 174 175 if (!(e = avahi_new(AvahiTimeEvent, 1))) { 176 avahi_log_error(__FILE__": Out of memory"); 177 return NULL; /* OOM */ 178 } 179 180 e->queue = q; 181 e->callback = callback; 182 e->userdata = userdata; 183 184 if (timeval) 185 e->expiry = *timeval; 186 else { 187 e->expiry.tv_sec = 0; 188 e->expiry.tv_usec = 0; 189 } 190 191 fix_expiry_time(e); 192 193 e->last_run.tv_sec = 0; 194 e->last_run.tv_usec = 0; 195 196 if (!(e->node = avahi_prio_queue_put(q->prioq, e))) { 197 avahi_free(e); 198 return NULL; 199 } 200 201 update_timeout(q); 202 return e; 203} 204 205void avahi_time_event_free(AvahiTimeEvent *e) { 206 AvahiTimeEventQueue *q; 207 assert(e); 208 209 q = e->queue; 210 211 avahi_prio_queue_remove(q->prioq, e->node); 212 avahi_free(e); 213 214 update_timeout(q); 215} 216 217void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) { 218 assert(e); 219 assert(timeval); 220 221 e->expiry = *timeval; 222 fix_expiry_time(e); 223 avahi_prio_queue_shuffle(e->queue->prioq, e->node); 224 225 update_timeout(e->queue); 226} 227 228