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