summaryrefslogtreecommitdiff
path: root/src/alarm.c
diff options
context:
space:
mode:
authorroot <root@build-vm.(none)>2010-06-14 15:51:25 -0700
committerroot <root@build-vm.(none)>2010-06-14 15:51:25 -0700
commitc4414d9a8b31bedfb7471cd2365aaf5ea5cf55d5 (patch)
tree86ee5befd8195f56dcd91f9fd4e06368bf507a11 /src/alarm.c
downloadconntrack-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.c150
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);
+}