]> git.meshlink.io Git - catta/blob - avahi-core/timeeventq.c
* avahi-utils: replace python avahi-browse with a version written in C.
[catta] / avahi-core / timeeventq.c
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
35 struct AvahiTimeEvent {
36     AvahiTimeEventQueue *queue;
37     AvahiPrioQueueNode *node;
38     struct timeval expiry;
39     struct timeval last_run;
40     AvahiTimeEventCallback callback;
41     void* userdata;
42 };
43
44 struct AvahiTimeEventQueue {
45     const AvahiPoll *poll_api;
46     AvahiPrioQueue *prioq;
47     AvahiTimeout *timeout;
48 };
49
50 static 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
62 static AvahiTimeEvent* time_event_queue_root(AvahiTimeEventQueue *q) {
63     assert(q);
64
65     return q->prioq->root ? q->prioq->root->data : NULL;
66 }
67
68 static 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
78 static 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
107 static 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
119 AvahiTimeEventQueue* 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
137 oom:
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
149 void 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
163 AvahiTimeEvent* 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
205 void 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
217 void 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