1 /*
2 * ivykis, an event handling library
3 * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek
4 * Dedicated to Marija Kulikova.
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * 2.1 as published by the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License version 2.1 for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License version 2.1 along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/time.h>
25 #include <time.h>
26 #include "iv_private.h"
27
28 #undef iv_validate_now
29
30
31 /* time handling ************************************************************/
iv_invalidate_now(void)32 void iv_invalidate_now(void)
33 {
34 struct iv_state *st = iv_get_state();
35
36 __iv_invalidate_now(st);
37 }
38
iv_validate_now(void)39 void iv_validate_now(void)
40 {
41 struct iv_state *st = iv_get_state();
42
43 if (!st->time_valid) {
44 st->time_valid = 1;
45 iv_time_get(&st->time);
46 }
47 }
48
__iv_now_location(void)49 const struct timespec *__iv_now_location(void)
50 {
51 struct iv_state *st = iv_get_state();
52
53 return &st->time;
54 }
55
__iv_now_location_valid(void)56 const struct timespec *__iv_now_location_valid(void)
57 {
58 struct iv_state *st = iv_get_state();
59
60 if (!st->time_valid) {
61 st->time_valid = 1;
62 iv_time_get(&st->time);
63 }
64
65 return &st->time;
66 }
67
68
69 /* internal use *************************************************************/
iv_timer_init(struct iv_state * st)70 void iv_timer_init(struct iv_state *st)
71 {
72 st->ratnode.timer_root = &st->ratnode.first_leaf;
73 }
74
iv_get_soonest_timeout(const struct iv_state * st)75 const struct timespec *iv_get_soonest_timeout(const struct iv_state *st)
76 {
77 if (st->num_timers) {
78 struct iv_timer_ *t = st->ratnode.first_leaf.child[1];
79
80 return &t->expires;
81 }
82
83 return NULL;
84 }
85
iv_run_timers(struct iv_state * st)86 void iv_run_timers(struct iv_state *st)
87 {
88 struct iv_list_head timers;
89
90 if (!st->num_timers)
91 return;
92
93 INIT_IV_LIST_HEAD(&timers);
94
95 if (!st->time_valid) {
96 st->time_valid = 1;
97 iv_time_get(&st->time);
98 }
99
100 while (st->num_timers) {
101 struct iv_timer_ *t = st->ratnode.first_leaf.child[1];
102
103 if (t->index != 1) {
104 iv_fatal("iv_run_timers: root timer has heap "
105 "index %d", t->index);
106 }
107
108 if (timespec_gt(&t->expires, &st->time))
109 break;
110 iv_timer_unregister((struct iv_timer *)t);
111
112 iv_list_add_tail(&t->list_expired, &timers);
113 t->index = 0;
114 }
115
116 while (!iv_list_empty(&timers)) {
117 struct iv_timer_ *t;
118
119 t = iv_list_entry(timers.next, struct iv_timer_, list_expired);
120
121 iv_list_del(&t->list_expired);
122 t->index = -1;
123
124 t->handler(t->cookie);
125 }
126 }
127
iv_timer_free_ratnode(struct iv_timer_ratnode * node,int depth)128 static void iv_timer_free_ratnode(struct iv_timer_ratnode *node, int depth)
129 {
130 if (depth) {
131 int i;
132
133 for (i = 0; i < IV_TIMER_SPLIT_NODES; i++) {
134 if (node->child[i] == NULL)
135 break;
136 iv_timer_free_ratnode(node->child[i], depth - 1);
137 }
138 }
139
140 free(node);
141 }
142
iv_timer_radix_tree_remove_level(struct iv_state * st)143 static void iv_timer_radix_tree_remove_level(struct iv_state *st)
144 {
145 struct iv_timer_ratnode *root;
146 int i;
147
148 st->rat_depth--;
149
150 root = st->ratnode.timer_root;
151 for (i = 1; i < IV_TIMER_SPLIT_NODES; i++) {
152 if (root->child[i] == NULL)
153 break;
154 iv_timer_free_ratnode(root->child[i], st->rat_depth);
155 }
156
157 st->ratnode.timer_root = root->child[0];
158 free(root);
159 }
160
iv_timer_deinit(struct iv_state * st)161 void iv_timer_deinit(struct iv_state *st)
162 {
163 while (st->rat_depth)
164 iv_timer_radix_tree_remove_level(st);
165
166 st->ratnode.timer_root = NULL;
167 }
168
169
170 /* public use ***************************************************************/
IV_TIMER_INIT(struct iv_timer * _t)171 void IV_TIMER_INIT(struct iv_timer *_t)
172 {
173 struct iv_timer_ *t = (struct iv_timer_ *)_t;
174
175 t->index = -1;
176 }
177
iv_timer_allocate_ratnode(void)178 static struct iv_timer_ratnode *iv_timer_allocate_ratnode(void)
179 {
180 struct iv_timer_ratnode *node;
181
182 node = calloc(1, sizeof(struct iv_timer_ratnode));
183 if (node == NULL)
184 iv_fatal("iv_timer_allocate_ratnode: out of memory");
185
186 return node;
187 }
188
iv_timer_get_node(struct iv_state * st,int index)189 static struct iv_timer_ **iv_timer_get_node(struct iv_state *st, int index)
190 {
191 struct iv_timer_ratnode *r;
192 int i;
193
194 if (index >> ((st->rat_depth + 1) * IV_TIMER_SPLIT_BITS) != 0) {
195 st->rat_depth++;
196
197 r = iv_timer_allocate_ratnode();
198 r->child[0] = st->ratnode.timer_root;
199 st->ratnode.timer_root = r;
200 }
201
202 r = st->ratnode.timer_root;
203 for (i = st->rat_depth; i > 0; i--) {
204 int bits;
205
206 bits = (index >> (i * IV_TIMER_SPLIT_BITS)) &
207 (IV_TIMER_SPLIT_NODES - 1);
208 if (r->child[bits] == NULL)
209 r->child[bits] = iv_timer_allocate_ratnode();
210 r = r->child[bits];
211 }
212
213 return (struct iv_timer_ **)
214 (r->child + (index & (IV_TIMER_SPLIT_NODES - 1)));
215 }
216
217 static inline int
timer_ptr_gt(const struct iv_timer_ * a,const struct iv_timer_ * b)218 timer_ptr_gt(const struct iv_timer_ *a, const struct iv_timer_ *b)
219 {
220 return timespec_gt(&a->expires, &b->expires);
221 }
222
pull_up(struct iv_state * st,int index,struct iv_timer_ ** i)223 static void pull_up(struct iv_state *st, int index, struct iv_timer_ **i)
224 {
225 while (index != 1) {
226 struct iv_timer_ *et;
227 int parent;
228 struct iv_timer_ **p;
229
230 parent = index / 2;
231 p = iv_timer_get_node(st, parent);
232
233 if (!timer_ptr_gt(*p, *i))
234 break;
235
236 et = *i;
237 *i = *p;
238 *p = et;
239
240 (*i)->index = index;
241 (*p)->index = parent;
242
243 index = parent;
244 i = p;
245 }
246 }
247
iv_timer_register(struct iv_timer * _t)248 void iv_timer_register(struct iv_timer *_t)
249 {
250 struct iv_state *st = iv_get_state();
251 struct iv_timer_ *t = (struct iv_timer_ *)_t;
252 struct iv_timer_ **p;
253 int index;
254
255 if (t->index != -1) {
256 iv_fatal("iv_timer_register: called with timer still "
257 "on the heap");
258 }
259
260 st->numobjs++;
261
262 index = ++st->num_timers;
263 p = iv_timer_get_node(st, index);
264 *p = t;
265 t->index = index;
266
267 pull_up(st, index, p);
268 }
269
push_down(struct iv_state * st,int index,struct iv_timer_ ** i)270 static void push_down(struct iv_state *st, int index, struct iv_timer_ **i)
271 {
272 while (1) {
273 struct iv_timer_ *et;
274 struct iv_timer_ **imin;
275 int index_min;
276
277 index_min = index;
278 imin = i;
279
280 if (2 * index <= st->num_timers) {
281 struct iv_timer_ **p;
282
283 p = iv_timer_get_node(st, 2 * index);
284 if (timer_ptr_gt(*imin, p[0])) {
285 index_min = 2 * index;
286 imin = p;
287 }
288 if (p[1] && timer_ptr_gt(*imin, p[1])) {
289 index_min = 2 * index + 1;
290 imin = p + 1;
291 }
292 }
293
294 if (index == index_min)
295 break;
296
297 et = *i;
298 *i = *imin;
299 *imin = et;
300
301 (*i)->index = index;
302 (*imin)->index = index_min;
303
304 index = index_min;
305 i = imin;
306 }
307 }
308
iv_timer_unregister(struct iv_timer * _t)309 void iv_timer_unregister(struct iv_timer *_t)
310 {
311 struct iv_state *st = iv_get_state();
312 struct iv_timer_ *t = (struct iv_timer_ *)_t;
313 struct iv_timer_ **m;
314 struct iv_timer_ **p;
315
316 if (t->index == -1) {
317 iv_fatal("iv_timer_unregister: called with timer not "
318 "on the heap");
319 }
320
321 if (t->index) {
322 if (t->index > st->num_timers) {
323 iv_fatal("iv_timer_unregister: timer index %d > %d",
324 t->index, st->num_timers);
325 }
326
327 p = iv_timer_get_node(st, t->index);
328 if (*p != t) {
329 iv_fatal("iv_timer_unregister: unregistered timer "
330 "index belonging to other timer");
331 }
332
333 m = iv_timer_get_node(st, st->num_timers);
334 *p = *m;
335 (*p)->index = t->index;
336 *m = NULL;
337
338 if (st->rat_depth > 0 &&
339 st->num_timers == (1 << (st->rat_depth *
340 IV_TIMER_SPLIT_BITS))) {
341 iv_timer_radix_tree_remove_level(st);
342 }
343 st->num_timers--;
344
345 if (p != m) {
346 pull_up(st, (*p)->index, p);
347 push_down(st, (*p)->index, p);
348 }
349
350 st->numobjs--;
351 } else {
352 iv_list_del(&t->list_expired);
353 }
354
355 t->index = -1;
356 }
357
iv_timer_registered(const struct iv_timer * _t)358 int iv_timer_registered(const struct iv_timer *_t)
359 {
360 struct iv_timer_ *t = (struct iv_timer_ *)_t;
361
362 return !(t->index == -1);
363 }
364