]> git.meshlink.io Git - catta/blob - avahi-core/timeeventq.c
implement new main loop abstraction layer
[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 <avahi-common/timeval.h>
27 #include "timeeventq.h"
28
29 static gint compare(gconstpointer _a, gconstpointer _b) {
30     const AvahiTimeEvent *a = _a,  *b = _b;
31     gint ret;
32
33     if ((ret = avahi_timeval_compare(&a->expiry, &b->expiry)) != 0)
34         return ret;
35
36     /* If both exevents are scheduled for the same time, put the entry
37      * that has been run earlier the last time first. */
38     return avahi_timeval_compare(&a->last_run, &b->last_run);
39 }
40
41 static void source_get_timeval(GSource *source, struct timeval *tv) {
42     GTimeVal gtv;
43     
44     g_assert(source);
45     g_assert(tv);
46
47     g_source_get_current_time(source, &gtv);
48     tv->tv_sec = gtv.tv_sec;
49     tv->tv_usec = gtv.tv_usec;
50 }
51
52 static gboolean prepare_func(GSource *source, gint *timeout) {
53     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
54     AvahiTimeEvent *e;
55     struct timeval now;
56
57     g_assert(source);
58     g_assert(timeout);
59
60     if (!q->prioq->root) {
61         *timeout = -1;
62         return FALSE;
63     }
64     
65     e = q->prioq->root->data;
66     g_assert(e);
67
68     source_get_timeval(source, &now);
69
70     if (avahi_timeval_compare(&now, &e->expiry) >= 0 &&  /* Time elapsed */
71         avahi_timeval_compare(&now, &e->last_run) != 0   /* Not yet run */) {
72         *timeout = -1;
73         return TRUE;
74     }
75
76     *timeout = (gint) (avahi_timeval_diff(&e->expiry, &now)/1000);
77
78     /* Wait at least 1 msec */
79     if (*timeout <= 0)
80         *timeout = 1;
81     
82     return FALSE;
83 }
84
85 static gboolean check_func(GSource *source) {
86     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
87     AvahiTimeEvent *e;
88     struct timeval now;
89
90     g_assert(source);
91
92     if (!q->prioq->root)
93         return FALSE;
94
95     e = q->prioq->root->data;
96     g_assert(e);
97
98     source_get_timeval(source, &now);
99     
100     return
101         avahi_timeval_compare(&now, &e->expiry) >= 0 && /* Time elapsed */
102         avahi_timeval_compare(&now, &e->last_run) != 0;  /* Not yet run */
103 }
104
105 static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
106     AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
107     struct timeval now;
108
109     g_assert(source);
110
111     source_get_timeval(source, &now);
112
113     while (q->prioq->root) {
114         AvahiTimeEvent *e = q->prioq->root->data;
115
116         /* Not yet expired */
117         if (avahi_timeval_compare(&now, &e->expiry) < 0)
118             break;
119
120         /* Already ran */
121         if (avahi_timeval_compare(&now, &e->last_run) == 0)
122             break;
123
124         /* Make sure to move the entry away from the front */
125         e->last_run = now;
126         avahi_prio_queue_shuffle(q->prioq, e->node);
127
128         /* Run it */
129         g_assert(e->callback);
130         e->callback(e, e->userdata);
131     }
132
133     return TRUE;
134 }
135
136 static void fix_expiry_time(AvahiTimeEvent *e) {
137     struct timeval now;
138     g_assert(e);
139
140     source_get_timeval(&e->queue->source, &now);
141
142     if (avahi_timeval_compare(&now, &e->expiry) > 0)
143         e->expiry = now;
144     
145 }
146
147 AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority) {
148     AvahiTimeEventQueue *q;
149
150     static GSourceFuncs source_funcs = {
151         prepare_func,
152         check_func,
153         dispatch_func,
154         NULL,
155         NULL,
156         NULL
157     };
158
159     q = (AvahiTimeEventQueue*) g_source_new(&source_funcs, sizeof(AvahiTimeEventQueue));
160     q->prioq = avahi_prio_queue_new(compare);
161
162     g_source_set_priority((GSource*) q, priority);
163     
164     g_source_attach(&q->source, context);
165     
166     return q;
167 }
168
169 void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
170     g_assert(q);
171
172     while (q->prioq->root)
173         avahi_time_event_queue_remove(q, q->prioq->root->data);
174     avahi_prio_queue_free(q->prioq);
175
176     g_source_destroy(&q->source);
177     g_source_unref(&q->source);
178 }
179
180 AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const struct timeval *timeval, AvahiTimeEventCallback callback, gpointer userdata) {
181     AvahiTimeEvent *e;
182     
183     g_assert(q);
184     g_assert(timeval);
185     g_assert(callback);
186     g_assert(userdata);
187
188     e = g_new(AvahiTimeEvent, 1);
189     e->queue = q;
190     e->callback = callback;
191     e->userdata = userdata;
192
193     e->expiry = *timeval;
194     fix_expiry_time(e);
195     
196     e->last_run.tv_sec = 0;
197     e->last_run.tv_usec = 0;
198
199     e->node = avahi_prio_queue_put(q->prioq, e);
200     
201     return e;
202 }
203
204 void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e) {
205     g_assert(q);
206     g_assert(e);
207     g_assert(e->queue == q);
208
209     avahi_prio_queue_remove(q->prioq, e->node);
210     g_free(e);
211 }
212
213 void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const struct timeval *timeval) {
214     g_assert(q);
215     g_assert(e);
216     g_assert(e->queue == q);
217     g_assert(timeval);
218
219     e->expiry = *timeval;
220     fix_expiry_time(e);
221
222     avahi_prio_queue_shuffle(q->prioq, e->node);
223 }
224
225 AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
226     g_assert(q);
227
228     return q->prioq->root ? q->prioq->root->data : NULL;
229 }
230
231 AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e) {
232     g_assert(e);
233
234     return e->node->next->data;
235 }
236
237