diff options
author | root <root@build-vm.(none)> | 2010-06-14 15:51:25 -0700 |
---|---|---|
committer | root <root@build-vm.(none)> | 2010-06-14 15:51:25 -0700 |
commit | c4414d9a8b31bedfb7471cd2365aaf5ea5cf55d5 (patch) | |
tree | 86ee5befd8195f56dcd91f9fd4e06368bf507a11 /src/alarm.c | |
download | conntrack-tools-c4414d9a8b31bedfb7471cd2365aaf5ea5cf55d5.tar.gz conntrack-tools-c4414d9a8b31bedfb7471cd2365aaf5ea5cf55d5.zip |
debian conntrack 0.9.14-2
Diffstat (limited to 'src/alarm.c')
-rw-r--r-- | src/alarm.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/alarm.c b/src/alarm.c new file mode 100644 index 0000000..006721a --- /dev/null +++ b/src/alarm.c @@ -0,0 +1,150 @@ +/* + * (C) 2006-2008 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "alarm.h" +#include "date.h" +#include <stdlib.h> +#include <limits.h> + +static struct rb_root alarm_root = RB_ROOT; + +void init_alarm(struct alarm_block *t, + void *data, + void (*fcn)(struct alarm_block *a, void *data)) +{ + /* initialize the head to check whether a node is inserted */ + RB_CLEAR_NODE(&t->node); + timerclear(&t->tv); + t->data = data; + t->function = fcn; +} + +static void __add_alarm(struct alarm_block *alarm) +{ + struct rb_node **new = &(alarm_root.rb_node); + struct rb_node *parent = NULL; + + while (*new) { + struct alarm_block *this; + + this = container_of(*new, struct alarm_block, node); + + parent = *new; + if (timercmp(&alarm->tv, &this->tv, <)) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + rb_link_node(&alarm->node, parent, new); + rb_insert_color(&alarm->node, &alarm_root); +} + +void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc) +{ + struct timeval tv; + + del_alarm(alarm); + alarm->tv.tv_sec = sc; + alarm->tv.tv_usec = usc; + gettimeofday_cached(&tv); + timeradd(&alarm->tv, &tv, &alarm->tv); + __add_alarm(alarm); +} + +void del_alarm(struct alarm_block *alarm) +{ + /* don't remove a non-inserted node */ + if (!RB_EMPTY_NODE(&alarm->node)) { + rb_erase(&alarm->node, &alarm_root); + RB_CLEAR_NODE(&alarm->node); + } +} + +int alarm_pending(struct alarm_block *alarm) +{ + if (RB_EMPTY_NODE(&alarm->node)) + return 0; + + return 1; +} + +static struct timeval * +calculate_next_run(struct timeval *cand, + struct timeval *tv, + struct timeval *next_run) +{ + if (cand->tv_sec != LONG_MAX) { + if (timercmp(cand, tv, >)) + timersub(cand, tv, next_run); + else { + /* loop again inmediately */ + next_run->tv_sec = 0; + next_run->tv_usec = 0; + } + return next_run; + } + return NULL; +} + +struct timeval * +get_next_alarm_run(struct timeval *next_run) +{ + struct rb_node *node; + struct timeval tv; + + gettimeofday_cached(&tv); + + node = rb_first(&alarm_root); + if (node) { + struct alarm_block *this; + this = container_of(node, struct alarm_block, node); + return calculate_next_run(&this->tv, &tv, next_run); + } + return NULL; +} + +struct timeval * +do_alarm_run(struct timeval *next_run) +{ + struct list_head alarm_run_queue; + struct rb_node *node; + struct alarm_block *this, *tmp; + struct timeval tv; + + gettimeofday_cached(&tv); + + INIT_LIST_HEAD(&alarm_run_queue); + for (node = rb_first(&alarm_root); node; node = rb_next(node)) { + this = container_of(node, struct alarm_block, node); + + if (timercmp(&this->tv, &tv, >)) + break; + + list_add(&this->list, &alarm_run_queue); + } + + /* must be safe as entries can vanish from the callback */ + list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) { + rb_erase(&this->node, &alarm_root); + RB_CLEAR_NODE(&this->node); + this->function(this, this->data); + } + + return get_next_alarm_run(next_run); +} |