cosmetics
[tomato.git] / release / src / router / openvpn / schedule.c
blob724613e43b890fdce06f5b17a86b65f9f0eec13c
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "syshead.h"
27 #if P2MP_SERVER
29 #include "buffer.h"
30 #include "misc.h"
31 #include "crypto.h"
32 #include "schedule.h"
34 #include "memdbg.h"
36 #ifdef SCHEDULE_TEST
38 struct status
40 int sru;
41 int ins;
42 int coll;
43 int lsteps;
46 static struct status z;
48 #endif
50 #ifdef ENABLE_DEBUG
51 static void
52 schedule_entry_debug_info (const char *caller, const struct schedule_entry *e)
54 struct gc_arena gc = gc_new ();
55 if (e)
57 dmsg (D_SCHEDULER, "SCHEDULE: %s wakeup=[%s] pri=%u",
58 caller,
59 tv_string_abs (&e->tv, &gc),
60 e->pri);
62 else
64 dmsg (D_SCHEDULER, "SCHEDULE: %s NULL",
65 caller);
67 gc_free (&gc);
69 #endif
71 static inline void
72 schedule_set_pri (struct schedule_entry *e)
74 e->pri = random ();
75 if (e->pri < 1)
76 e->pri = 1;
79 /* This is the master key comparison routine. A key is
80 * simply a struct timeval containing the absolute time for
81 * an event. The unique treap priority (pri) is used to ensure
82 * that keys do not collide.
84 static inline int
85 schedule_entry_compare (const struct schedule_entry *e1,
86 const struct schedule_entry *e2)
88 if (e1->tv.tv_sec < e2->tv.tv_sec)
89 return -1;
90 else if (e1->tv.tv_sec > e2->tv.tv_sec)
91 return 1;
92 else
94 if (e1->tv.tv_usec < e2->tv.tv_usec)
95 return -1;
96 else if (e1->tv.tv_usec > e2->tv.tv_usec)
97 return 1;
98 else
100 if (e1->pri < e2->pri)
101 return -1;
102 else if (e1->pri > e2->pri)
103 return 1;
104 else
105 return 0;
111 * Detach a btree node from its parent
113 static inline void
114 schedule_detach_parent (struct schedule *s, struct schedule_entry *e)
116 if (e)
118 if (e->parent)
120 if (e->parent->lt == e)
121 e->parent->lt = NULL;
122 else if (e->parent->gt == e)
123 e->parent->gt = NULL;
124 else
126 /* parent <-> child linkage is corrupted */
127 ASSERT (0);
129 e->parent = NULL;
131 else
133 if (s->root == e) /* last element deleted, tree is empty */
134 s->root = NULL;
141 * Given a binary search tree, move a node toward the root
142 * while still maintaining the correct ordering relationships
143 * within the tree. This function is the workhorse
144 * of the tree balancer.
146 * This code will break on key collisions, which shouldn't
147 * happen because the treap priority is considered part of the key
148 * and is guaranteed to be unique.
150 static void
151 schedule_rotate_up (struct schedule *s, struct schedule_entry *e)
153 if (e && e->parent)
155 struct schedule_entry *lt = e->lt;
156 struct schedule_entry *gt = e->gt;
157 struct schedule_entry *p = e->parent;
158 struct schedule_entry *gp = p->parent;
160 if (gp) /* if grandparent exists, modify its child link */
162 if (gp->gt == p)
163 gp->gt = e;
164 else if (gp->lt == p)
165 gp->lt = e;
166 else
168 ASSERT (0);
171 else /* no grandparent, now we are the root */
173 s->root = e;
176 /* grandparent is now our parent */
177 e->parent = gp;
179 /* parent is now our child */
180 p->parent = e;
182 /* reorient former parent's links
183 to reflect new position in the tree */
184 if (p->gt == e)
186 e->lt = p;
187 p->gt = lt;
188 if (lt)
189 lt->parent = p;
191 else if (p->lt == e)
193 e->gt = p;
194 p->lt = gt;
195 if (gt)
196 gt->parent = p;
198 else
200 /* parent <-> child linkage is corrupted */
201 ASSERT (0);
204 #ifdef SCHEDULE_TEST
205 ++z.sru;
206 #endif
211 * This is the treap deletion algorithm:
213 * Rotate lesser-priority children up in the tree
214 * until we are childless. Then delete.
216 void
217 schedule_remove_node (struct schedule *s, struct schedule_entry *e)
219 while (e->lt || e->gt)
221 if (e->lt)
223 if (e->gt)
225 if (e->lt->pri < e->gt->pri)
226 schedule_rotate_up (s, e->lt);
227 else
228 schedule_rotate_up (s, e->gt);
230 else
231 schedule_rotate_up (s, e->lt);
233 else if (e->gt)
234 schedule_rotate_up (s, e->gt);
237 schedule_detach_parent (s, e);
238 e->pri = 0;
242 * Trivially add a node to a binary search tree without
243 * regard for balance.
245 static void
246 schedule_insert (struct schedule *s, struct schedule_entry *e)
248 struct schedule_entry *c = s->root;
249 while (true)
251 const int comp = schedule_entry_compare (e, c);
253 #ifdef SCHEDULE_TEST
254 ++z.ins;
255 #endif
257 if (comp == -1)
259 if (c->lt)
261 c = c->lt;
262 continue;
264 else
266 c->lt = e;
267 e->parent = c;
268 break;
271 else if (comp == 1)
273 if (c->gt)
275 c = c->gt;
276 continue;
278 else
280 c->gt = e;
281 e->parent = c;
282 break;
285 else
287 /* rare key/priority collision -- no big deal,
288 just choose another priority and retry */
289 #ifdef SCHEDULE_TEST
290 ++z.coll;
291 #endif
292 schedule_set_pri (e);
293 /* msg (M_INFO, "PRI COLLISION pri=%u", e->pri); */
294 c = s->root;
295 continue;
301 * Given an element, remove it from the btree if it's already
302 * there and re-insert it based on its current key.
304 void
305 schedule_add_modify (struct schedule *s, struct schedule_entry *e)
307 #ifdef ENABLE_DEBUG
308 if (check_debug_level (D_SCHEDULER))
309 schedule_entry_debug_info ("schedule_add_modify", e);
310 #endif
312 /* already in tree, remove */
313 if (IN_TREE (e))
314 schedule_remove_node (s, e);
316 /* set random priority */
317 schedule_set_pri (e);
319 if (s->root)
320 schedule_insert (s, e); /* trivial insert into tree */
321 else
322 s->root = e; /* tree was empty, we are the first element */
324 /* This is the magic of the randomized treap algorithm which
325 keeps the tree balanced. Move the node up the tree until
326 its own priority is greater than that of its parent */
327 while (e->parent && e->parent->pri > e->pri)
328 schedule_rotate_up (s, e);
332 * Find the earliest event to be scheduled
334 struct schedule_entry *
335 schedule_find_least (struct schedule_entry *e)
337 if (e)
339 while (e->lt)
341 #ifdef SCHEDULE_TEST
342 ++z.lsteps;
343 #endif
344 e = e->lt;
348 #ifdef ENABLE_DEBUG
349 if (check_debug_level (D_SCHEDULER))
350 schedule_entry_debug_info ("schedule_find_least", e);
351 #endif
353 return e;
357 * Public functions below this point
360 struct schedule *
361 schedule_init (void)
363 struct schedule *s;
365 ALLOC_OBJ_CLEAR (s, struct schedule);
366 mutex_init (&s->mutex);
367 return s;
370 void
371 schedule_free (struct schedule *s)
373 mutex_destroy (&s->mutex);
374 free (s);
377 void
378 schedule_remove_entry (struct schedule *s, struct schedule_entry *e)
380 mutex_lock (&s->mutex);
381 s->earliest_wakeup = NULL; /* invalidate cache */
382 schedule_remove_node (s, e);
383 mutex_unlock (&s->mutex);
387 * Debug functions below this point
390 #ifdef SCHEDULE_TEST
392 static inline struct schedule_entry *
393 schedule_find_earliest_wakeup (struct schedule *s)
395 return schedule_find_least (s->root);
399 * Recursively check that the treap (btree) is
400 * internally consistent.
403 schedule_debug_entry (const struct schedule_entry* e,
404 int depth,
405 int *count,
406 struct timeval *least,
407 const struct timeval *min,
408 const struct timeval *max)
410 struct gc_arena gc = gc_new ();
411 int maxdepth = depth;
412 if (e)
414 int d;
416 ASSERT (e != e->lt);
417 ASSERT (e != e->gt);
418 ASSERT (e != e->parent);
419 ASSERT (!e->parent || e->parent != e->lt);
420 ASSERT (!e->parent || e->parent != e->gt);
421 ASSERT (!e->lt || e->lt != e->gt);
423 if (e->lt)
425 ASSERT (e->lt->parent == e);
426 ASSERT (schedule_entry_compare (e->lt, e) == -1);
427 ASSERT (e->lt->pri >= e->pri);
430 if (e->gt)
432 ASSERT (e->gt->parent == e);
433 ASSERT (schedule_entry_compare (e->gt, e));
434 ASSERT (e->gt->pri >= e->pri);
437 ASSERT (tv_le (min, &e->tv));
438 ASSERT (tv_le (&e->tv, max));
440 if (count)
441 ++(*count);
443 if (least && tv_lt (&e->tv, least))
444 *least = e->tv;
446 d = schedule_debug_entry (e->lt, depth+1, count, least, min, &e->tv);
447 if (d > maxdepth)
448 maxdepth = d;
450 d = schedule_debug_entry (e->gt, depth+1, count, least, &e->tv, max);
451 if (d > maxdepth)
452 maxdepth = d;
454 gc_free (&gc);
455 return maxdepth;
459 schedule_debug (struct schedule *s, int *count, struct timeval *least)
461 struct timeval min;
462 struct timeval max;
464 min.tv_sec = 0;
465 min.tv_usec = 0;
466 max.tv_sec = 0x7FFFFFFF;
467 max.tv_usec = 0x7FFFFFFF;
469 if (s->root)
471 ASSERT (s->root->parent == NULL);
473 return schedule_debug_entry (s->root, 0, count, least, &min, &max);
476 #if 1
478 void
479 tv_randomize (struct timeval *tv)
481 tv->tv_sec += random() % 100;
482 tv->tv_usec = random () % 100;
485 #else
487 void
488 tv_randomize (struct timeval *tv)
490 struct gc_arena gc = gc_new ();
491 long int choice = get_random ();
492 if ((choice & 0xFF) == 0)
493 tv->tv_usec += ((choice >> 8) & 0xFF);
494 else
495 prng_bytes ((uint8_t *)tv, sizeof (struct timeval));
496 gc_free (&gc);
499 #endif
501 void
502 schedule_verify (struct schedule *s)
504 struct gc_arena gc = gc_new ();
505 struct timeval least;
506 int count;
507 int maxlev;
508 struct schedule_entry* e;
509 const struct status zz = z;
511 least.tv_sec = least.tv_usec = 0x7FFFFFFF;
513 count = 0;
515 maxlev = schedule_debug (s, &count, &least);
517 e = schedule_find_earliest_wakeup (s);
519 if (e)
521 printf ("Verification Phase count=%d maxlev=%d sru=%d ins=%d coll=%d ls=%d l=%s",
522 count,
523 maxlev,
524 zz.sru,
525 zz.ins,
526 zz.coll,
527 zz.lsteps,
528 tv_string (&e->tv, &gc));
530 if (!tv_eq (&least, &e->tv))
531 printf (" [COMPUTED DIFFERENT MIN VALUES!]");
533 printf ("\n");
536 CLEAR (z);
537 gc_free (&gc);
540 void
541 schedule_randomize_array (struct schedule_entry **array, int size)
543 int i;
544 for (i = 0; i < size; ++i)
546 const int src = get_random () % size;
547 struct schedule_entry *tmp = array [i];
548 if (i != src)
550 array [i] = array [src];
551 array [src] = tmp;
556 void
557 schedule_print_work (struct schedule_entry *e, int indent)
559 struct gc_arena gc = gc_new ();
560 int i;
561 for (i = 0; i < indent; ++i)
562 printf (" ");
563 if (e)
565 printf ("%s [%u] e=" ptr_format ", p=" ptr_format " lt=" ptr_format " gt=" ptr_format "\n",
566 tv_string (&e->tv, &gc),
567 e->pri,
568 (ptr_type)e,
569 (ptr_type)e->parent,
570 (ptr_type)e->lt,
571 (ptr_type)e->gt);
572 schedule_print_work (e->lt, indent+1);
573 schedule_print_work (e->gt, indent+1);
575 else
576 printf ("NULL\n");
577 gc_free (&gc);
580 void
581 schedule_print (struct schedule *s)
583 printf ("*************************\n");
584 schedule_print_work (s->root, 0);
587 void
588 schedule_test (void)
590 struct gc_arena gc = gc_new ();
591 int n = 1000;
592 int n_mod = 25;
594 int i, j;
595 struct schedule_entry **array;
596 struct schedule *s = schedule_init ();
597 struct schedule_entry* e;
599 CLEAR (z);
600 ALLOC_ARRAY (array, struct schedule_entry *, n);
602 printf ("Creation/Insertion Phase\n");
604 for (i = 0; i < n; ++i)
606 ALLOC_OBJ_CLEAR (array[i], struct schedule_entry);
607 tv_randomize (&array[i]->tv);
608 /*schedule_print (s);*/
609 /*schedule_verify (s);*/
610 schedule_add_modify (s, array[i]);
613 schedule_randomize_array (array, n);
615 /*schedule_print (s);*/
616 schedule_verify (s);
618 for (j = 1; j <= n_mod; ++j)
620 printf ("Modification Phase Pass %d\n", j);
622 for (i = 0; i < n; ++i)
624 e = schedule_find_earliest_wakeup (s);
625 /*printf ("BEFORE %s\n", tv_string (&e->tv, &gc));*/
626 tv_randomize (&e->tv);
627 /*printf ("AFTER %s\n", tv_string (&e->tv, &gc));*/
628 schedule_add_modify (s, e);
629 /*schedule_verify (s);*/
630 /*schedule_print (s);*/
632 schedule_verify (s);
633 /*schedule_print (s);*/
636 /*printf ("INS=%d\n", z.ins);*/
638 while ((e = schedule_find_earliest_wakeup (s)))
640 schedule_remove_node (s, e);
641 /*schedule_verify (s);*/
643 schedule_verify (s);
645 printf ("S->ROOT is %s\n", s->root ? "NOT NULL" : "NULL");
647 for (i = 0; i < n; ++i)
649 free (array[i]);
651 free (array);
652 free (s);
653 gc_free (&gc);
656 #endif
657 #endif