]> git.meshlink.io Git - catta/blob - avahi-core/timeeventq.c
* add new priority parameter to avahi_glib_poll_new()
[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 void update_timeout(AvahiTimeEventQueue *q) {
63     AvahiTimeEvent *e;
64     assert(q);
65
66     if ((e = avahi_time_event_queue_root(q)))
67         q->poll_api->timeout_update(q->timeout, &e->expiry);
68     else
69         q->poll_api->timeout_update(q->timeout, NULL);
70 }
71
72 static void expiration_event(AvahiTimeout *timeout, void *userdata) {
73     struct timeval now;
74     AvahiTimeEventQueue *q = userdata;
75     AvahiTimeEvent *e;
76
77     gettimeofday(&now, NULL);
78     
79     if ((e = avahi_time_event_queue_root(q))) {
80
81         /* Check if expired */
82         if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
83
84             /* Make sure to move the entry away from the front */
85             e->last_run = now;
86             avahi_prio_queue_shuffle(q->prioq, e->node);
87
88             /* Run it */
89             assert(e->callback);
90             e->callback(e, e->userdata);
91         }
92     }
93
94     update_timeout(q);
95 }
96
97 static void fix_expiry_time(AvahiTimeEvent *e) {
98     struct timeval now;
99     assert(e);
100
101     gettimeofday(&now, NULL);
102
103     if (avahi_timeval_compare(&now, &e->expiry) > 0)
104         e->expiry = now;
105 }
106
107 AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) {
108     AvahiTimeEventQueue *q;
109
110     if (!(q = avahi_new(AvahiTimeEventQueue, 1))) {
111         avahi_log_error(__FILE__": Out of memory");
112         goto oom;
113     }
114
115     q->poll_api = poll_api;
116
117     if (!(q->prioq = avahi_prio_queue_new(compare)))
118         goto oom;
119
120     if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q))) 
121         goto oom;
122     
123     return q;
124
125 oom:
126
127     if (q) {
128         avahi_free(q);
129
130         if (q->prioq)
131             avahi_prio_queue_free(q->prioq);
132     }
133     
134     return NULL;
135 }
136
137 void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
138     AvahiTimeEvent *e;
139     
140     assert(q);
141
142     while ((e = avahi_time_event_queue_root(q)))
143         avahi_time_event_free(e);
144     avahi_prio_queue_free(q->prioq);
145
146     q->poll_api->timeout_free(q->timeout);
147     
148     avahi_free(q);
149 }
150
151 AvahiTimeEvent* avahi_time_event_new(
152     AvahiTimeEventQueue *q,
153     const struct timeval *timeval,
154     AvahiTimeEventCallback callback,
155     void* userdata) {
156     
157     AvahiTimeEvent *e;
158     
159     assert(q);
160     assert(callback);
161     assert(userdata);
162
163     if (!(e = avahi_new(AvahiTimeEvent, 1))) {
164         avahi_log_error(__FILE__": Out of memory");
165         return NULL; /* OOM */
166     }
167     
168     e->queue = q;
169     e->callback = callback;
170     e->userdata = userdata;
171
172     if (timeval)
173         e->expiry = *timeval;
174     else {
175         e->expiry.tv_sec = 0;
176         e->expiry.tv_usec = 0;
177     }
178     
179     fix_expiry_time(e);
180     
181     e->last_run.tv_sec = 0;
182     e->last_run.tv_usec = 0;
183
184     if (!(e->node = avahi_prio_queue_put(q->prioq, e))) {
185         avahi_free(e);
186         return NULL;
187     }
188
189     update_timeout(q);
190     return e;
191 }
192
193 void avahi_time_event_free(AvahiTimeEvent *e) {
194     AvahiTimeEventQueue *q;
195     assert(e);
196
197     q = e->queue;
198
199     avahi_prio_queue_remove(q->prioq, e->node);
200     avahi_free(e);
201
202     update_timeout(q);
203 }
204
205 void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) {
206     assert(e);
207     assert(timeval);
208
209     e->expiry = *timeval;
210     fix_expiry_time(e);
211     avahi_prio_queue_shuffle(e->queue->prioq, e->node);
212     
213     update_timeout(e->queue);
214 }
215
216 AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
217     assert(q);
218
219     return q->prioq->root ? q->prioq->root->data : NULL;
220 }
221
222 AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e) {
223     assert(e);
224
225     return e->node->next->data;
226 }
227
228