summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2017-05-30 19:12:35 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2017-12-07 13:46:53 +0100
commit534215a18fb3fb7ce5b26c9e6ec1fdb32bf22ae6 (patch)
treeb805e7f9dcf6e999dfad01117bc72f4bee6f2a6d
parent7c454d918682c072a6ae6ad8e0cd8d35b9edd2aa (diff)
Timers: Split microsecond timers from BFD code to lib
-rw-r--r--lib/Makefile2
-rw-r--r--lib/timer.c207
-rw-r--r--lib/timer.h104
-rw-r--r--proto/bfd/io.c277
-rw-r--r--proto/bfd/io.h67
-rw-r--r--sysdep/unix/io.c42
-rw-r--r--sysdep/unix/main.c2
7 files changed, 379 insertions, 322 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 0c352869..01f3114d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,4 +1,4 @@
-src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
+src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)
diff --git a/lib/timer.c b/lib/timer.c
new file mode 100644
index 00000000..00ac4b03
--- /dev/null
+++ b/lib/timer.c
@@ -0,0 +1,207 @@
+/*
+ * BIRD -- Timers
+ *
+ * (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013--2017 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include <stdlib.h>
+
+#include "nest/bird.h"
+
+#include "lib/heap.h"
+#include "lib/resource.h"
+#include "lib/timer.h"
+
+
+struct timeloop main_timeloop;
+
+
+#ifdef USE_PTHREADS
+
+#include <pthread.h>
+
+/* Data accessed and modified from proto/bfd/io.c */
+pthread_key_t current_time_key;
+
+static inline struct timeloop *
+timeloop_current(void)
+{
+ return pthread_getspecific(current_time_key);
+}
+
+static inline void
+timeloop_init_current(void)
+{
+ pthread_key_create(&current_time_key, NULL);
+ pthread_setspecific(current_time_key, &main_timeloop);
+}
+
+void wakeup_kick_current(void);
+
+#else
+
+/* Just use main timelooop */
+static inline struct timeloop * timeloop_current(void) { return &main_timeloop; }
+static inline void timeloop_init_current(void) { }
+
+#endif
+
+btime
+current_time(void)
+{
+ return timeloop_current()->last_time;
+}
+
+
+#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
+#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
+ heap[a]->index = (a), heap[b]->index = (b))
+
+
+static void
+tm2_free(resource *r)
+{
+ timer2 *t = (timer2 *) r;
+
+ tm2_stop(t);
+}
+
+static void
+tm2_dump(resource *r)
+{
+ timer2 *t = (timer2 *) r;
+
+ debug("(code %p, data %p, ", t->hook, t->data);
+ if (t->randomize)
+ debug("rand %d, ", t->randomize);
+ if (t->recurrent)
+ debug("recur %d, ", t->recurrent);
+ if (t->expires)
+ debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
+ else
+ debug("inactive)\n");
+}
+
+
+static struct resclass tm2_class = {
+ "Timer",
+ sizeof(timer2),
+ tm2_free,
+ tm2_dump,
+ NULL,
+ NULL
+};
+
+timer2 *
+tm2_new(pool *p)
+{
+ timer2 *t = ralloc(p, &tm2_class);
+ t->index = -1;
+ return t;
+}
+
+void
+tm2_set(timer2 *t, btime when)
+{
+ struct timeloop *loop = timeloop_current();
+ uint tc = timers_count(loop);
+
+ if (!t->expires)
+ {
+ t->index = ++tc;
+ t->expires = when;
+ BUFFER_PUSH(loop->timers) = t;
+ HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP);
+ }
+ else if (t->expires < when)
+ {
+ t->expires = when;
+ HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
+ }
+ else if (t->expires > when)
+ {
+ t->expires = when;
+ HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
+ }
+
+#ifdef CONFIG_BFD
+ /* Hack to notify BFD loops */
+ if ((loop != &main_timeloop) && (t->index == 1))
+ wakeup_kick_current();
+#endif
+}
+
+void
+tm2_start(timer2 *t, btime after)
+{
+ tm2_set(t, current_time() + MAX(after, 0));
+}
+
+void
+tm2_stop(timer2 *t)
+{
+ if (!t->expires)
+ return;
+
+ struct timeloop *loop = timeloop_current();
+ uint tc = timers_count(loop);
+
+ HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
+ BUFFER_POP(loop->timers);
+
+ t->index = -1;
+ t->expires = 0;
+}
+
+void
+timers_init(struct timeloop *loop, pool *p)
+{
+ times_init(loop);
+
+ BUFFER_INIT(loop->timers, p, 4);
+ BUFFER_PUSH(loop->timers) = NULL;
+}
+
+void
+timers_fire(struct timeloop *loop)
+{
+ btime base_time;
+ timer2 *t;
+
+ times_update(loop);
+ base_time = loop->last_time;
+
+ while (t = timers_first(loop))
+ {
+ if (t->expires > base_time)
+ return;
+
+ if (t->recurrent)
+ {
+ btime when = t->expires + t->recurrent;
+
+ if (when <= loop->last_time)
+ when = loop->last_time + t->recurrent;
+
+ if (t->randomize)
+ when += random() % (t->randomize + 1);
+
+ tm2_set(t, when);
+ }
+ else
+ tm2_stop(t);
+
+ t->hook(t);
+ }
+}
+
+void
+timer_init(void)
+{
+ timers_init(&main_timeloop, &root_pool);
+ timeloop_init_current();
+}
diff --git a/lib/timer.h b/lib/timer.h
new file mode 100644
index 00000000..88c53547
--- /dev/null
+++ b/lib/timer.h
@@ -0,0 +1,104 @@
+/*
+ * BIRD -- Timers
+ *
+ * (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013--2017 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_TIMER2_H_
+#define _BIRD_TIMER2_H_
+
+#include "nest/bird.h"
+#include "lib/buffer.h"
+#include "lib/resource.h"
+
+
+typedef struct timer2
+{
+ resource r;
+ void (*hook)(struct timer2 *);
+ void *data;
+
+ btime expires; /* 0=inactive */
+ uint randomize; /* Amount of randomization */
+ uint recurrent; /* Timer recurrence */
+
+ int index;
+} timer2;
+
+struct timeloop
+{
+ BUFFER(timer2 *) timers;
+ btime last_time;
+ btime real_time;
+};
+
+static inline uint timers_count(struct timeloop *loop)
+{ return loop->timers.used - 1; }
+
+static inline timer2 *timers_first(struct timeloop *loop)
+{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
+
+extern struct timeloop main_timeloop;
+
+btime current_time(void);
+
+timer2 *tm2_new(pool *p);
+void tm2_set(timer2 *t, btime when);
+void tm2_start(timer2 *t, btime after);
+void tm2_stop(timer2 *t);
+
+static inline int
+tm2_active(timer2 *t)
+{
+ return t->expires != 0;
+}
+
+static inline btime
+tm2_remains(timer2 *t)
+{
+ btime now = current_time();
+ return (t->expires > now) ? (t->expires - now) : 0;
+}
+
+static inline timer2 *
+tm2_new_init(pool *p, void (*hook)(struct timer2 *), void *data, uint rec, uint rand)
+{
+ timer2 *t = tm2_new(p);
+ t->hook = hook;
+ t->data = data;
+ t->recurrent = rec;
+ t->randomize = rand;
+ return t;
+}
+
+static inline void
+tm2_set_max(timer2 *t, btime when)
+{
+ if (when > t->expires)
+ tm2_set(t, when);
+}
+
+/*
+static inline void
+tm2_start_max(timer2 *t, btime after)
+{
+ btime rem = tm2_remains(t);
+ tm2_start(t, MAX_(rem, after));
+}
+*/
+
+/* In sysdep code */
+void times_init(struct timeloop *loop);
+void times_update(struct timeloop *loop);
+
+/* For I/O loop */
+void timers_init(struct timeloop *loop, pool *p);
+void timers_fire(struct timeloop *loop);
+
+void timer_init(void);
+
+
+#endif
diff --git a/proto/bfd/io.c b/proto/bfd/io.c
index 8f4f5007..ab846113 100644
--- a/proto/bfd/io.c
+++ b/proto/bfd/io.c
@@ -18,10 +18,10 @@
#include "proto/bfd/io.h"
#include "lib/buffer.h"
-#include "lib/heap.h"
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
+#include "lib/timer.h"
#include "lib/socket.h"
@@ -31,16 +31,12 @@ struct birdloop
pthread_t thread;
pthread_mutex_t mutex;
- btime last_time;
- btime real_time;
- u8 use_monotonic_clock;
-
u8 stop_called;
u8 poll_active;
u8 wakeup_masked;
int wakeup_fds[2];
- BUFFER(timer2 *) timers;
+ struct timeloop time;
list event_list;
list sock_list;
uint sock_num;
@@ -57,6 +53,7 @@ struct birdloop
*/
static pthread_key_t current_loop_key;
+extern pthread_key_t current_time_key;
static inline struct birdloop *
birdloop_current(void)
@@ -68,6 +65,7 @@ static inline void
birdloop_set_current(struct birdloop *loop)
{
pthread_setspecific(current_loop_key, loop);
+ pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
}
static inline void
@@ -78,98 +76,6 @@ birdloop_init_current(void)
/*
- * Time clock
- */
-
-static void times_update_alt(struct birdloop *loop);
-
-static void
-times_init(struct birdloop *loop)
-{
- struct timespec ts;
- int rv;
-
- rv = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (rv < 0)
- {
- log(L_WARN "Monotonic clock is missing");
-
- loop->use_monotonic_clock = 0;
- loop->last_time = 0;
- loop->real_time = 0;
- times_update_alt(loop);
- return;
- }
-
- if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40)))
- log(L_WARN "Monotonic clock is crazy");
-
- loop->use_monotonic_clock = 1;
- loop->last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
- loop->real_time = 0;
-}
-
-static void
-times_update_pri(struct birdloop *loop)
-{
- struct timespec ts;
- int rv;
-
- rv = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (rv < 0)
- die("clock_gettime: %m");
-
- btime new_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
-
- if (new_time < loop->last_time)
- log(L_ERR "Monotonic clock is broken");
-
- loop->last_time = new_time;
- loop->real_time = 0;
-}
-
-static void
-times_update_alt(struct birdloop *loop)
-{
- struct timeval tv;
- int rv;
-
- rv = gettimeofday(&tv, NULL);
- if (rv < 0)
- die("gettimeofday: %m");
-
- btime new_time = ((s64) tv.tv_sec S) + tv.tv_usec;
- btime delta = new_time - loop->real_time;
-
- if ((delta < 0) || (delta > (60 S)))
- {
- if (loop->real_time)
- log(L_WARN "Time jump, delta %d us", (int) delta);
-
- delta = 100 MS;
- }
-
- loop->last_time += delta;
- loop->real_time = new_time;
-}
-
-static void
-times_update(struct birdloop *loop)
-{
- if (loop->use_monotonic_clock)
- times_update_pri(loop);
- else
- times_update_alt(loop);
-}
-
-btime
-current_time(void)
-{
- return birdloop_current()->last_time;
-}
-
-
-/*
* Wakeup code for birdloop
*/
@@ -238,7 +144,7 @@ wakeup_drain(struct birdloop *loop)
}
static inline void
-wakeup_do_kick(struct birdloop *loop)
+wakeup_do_kick(struct birdloop *loop)
{
pipe_kick(loop->wakeup_fds[1]);
}
@@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
loop->wakeup_masked = 2;
}
+/* For notifications from outside */
+void
+wakeup_kick_current(void)
+{
+ struct birdloop *loop = birdloop_current();
+
+ if (loop && loop->poll_active)
+ wakeup_kick(loop);
+}
+
/*
* Events
@@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
static void
events_fire(struct birdloop *loop)
{
- times_update(loop);
+ times_update(&loop->time);
ev_run_list(&loop->event_list);
}
@@ -292,154 +208,6 @@ ev2_schedule(event *e)
/*
- * Timers
- */
-
-#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
-#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
- heap[a]->index = (a), heap[b]->index = (b))
-
-static inline uint timers_count(struct birdloop *loop)
-{ return loop->timers.used - 1; }
-
-static inline timer2 *timers_first(struct birdloop *loop)
-{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
-
-
-static void
-tm2_free(resource *r)
-{
- timer2 *t = (timer2 *) r;
-
- tm2_stop(t);
-}
-
-static void
-tm2_dump(resource *r)
-{
- timer2 *t = (timer2 *) r;
-
- debug("(code %p, data %p, ", t->hook, t->data);
- if (t->randomize)
- debug("rand %d, ", t->randomize);
- if (t->recurrent)
- debug("recur %d, ", t->recurrent);
- if (t->expires)
- debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
- else
- debug("inactive)\n");
-}
-
-
-static struct resclass tm2_class = {
- "Timer",
- sizeof(timer2),
- tm2_free,
- tm2_dump,
- NULL,
- NULL
-};
-
-timer2 *
-tm2_new(pool *p)
-{
- timer2 *t = ralloc(p, &tm2_class);
- t->index = -1;
- return t;
-}
-
-void
-tm2_set(timer2 *t, btime when)
-{
- struct birdloop *loop = birdloop_current();
- uint tc = timers_count(loop);
-
- if (!t->expires)
- {
- t->index = ++tc;
- t->expires = when;
- BUFFER_PUSH(loop->timers) = t;
- HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP);
- }
- else if (t->expires < when)
- {
- t->expires = when;
- HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
- }
- else if (t->expires > when)
- {
- t->expires = when;
- HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
- }
-
- if (loop->poll_active && (t->index == 1))
- wakeup_kick(loop);
-}
-
-void
-tm2_start(timer2 *t, btime after)
-{
- tm2_set(t, current_time() + MAX(after, 0));
-}
-
-void
-tm2_stop(timer2 *t)
-{
- if (!t->expires)
- return;
-
- struct birdloop *loop = birdloop_current();
- uint tc = timers_count(loop);
-
- HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
- BUFFER_POP(loop->timers);
-
- t->index = -1;
- t->expires = 0;
-}
-
-static void
-timers_init(struct birdloop *loop)
-{
- BUFFER_INIT(loop->timers, loop->pool, 4);
- BUFFER_PUSH(loop->timers) = NULL;
-}
-
-static void
-timers_fire(struct birdloop *loop)
-{
- btime base_time;
- timer2 *t;
-
- times_update(loop);
- base_time = loop->last_time;
-
- while (t = timers_first(loop))
- {
- if (t->expires > base_time)
- return;
-
- if (t->recurrent)
- {
- btime when = t->expires + t->recurrent;
-
- if (when <= loop->last_time)
- when = loop->last_time + t->recurrent;
-
- if (t->randomize)
- when += random() % (t->randomize + 1);
-
- tm2_set(t, when);
- }
- else
- tm2_stop(t);
-
- t->hook(t);
- }
-}
-
-
-/*
* Sockets
*/
@@ -586,7 +354,7 @@ sockets_fire(struct birdloop *loop)
sock **psk = loop->poll_sk.data;
int poll_num = loop->poll_fd.used - 1;
- times_update(loop);
+ times_update(&loop->time);
/* Last fd is internal wakeup fd */
if (pfd[poll_num].revents & POLLIN)
@@ -634,11 +402,10 @@ birdloop_new(void)
loop->pool = p;
pthread_mutex_init(&loop->mutex, NULL);
- times_init(loop);
wakeup_init(loop);
events_init(loop);
- timers_init(loop);
+ timers_init(&loop->time, p);
sockets_init(loop);
return loop;
@@ -719,12 +486,12 @@ birdloop_main(void *arg)
while (1)
{
events_fire(loop);
- timers_fire(loop);
+ timers_fire(&loop->time);
- times_update(loop);
+ times_update(&loop->time);
if (events_waiting(loop))
timeout = 0;
- else if (t = timers_first(loop))
+ else if (t = timers_first(&loop->time))
timeout = (tm2_remains(t) TO_MS) + 1;
else
timeout = -1;
@@ -756,7 +523,7 @@ birdloop_main(void *arg)
if (rv)
sockets_fire(loop);
- timers_fire(loop);
+ timers_fire(&loop->time);
}
loop->stop_called = 0;
diff --git a/proto/bfd/io.h b/proto/bfd/io.h
index 45836f84..ec706e9a 100644
--- a/proto/bfd/io.h
+++ b/proto/bfd/io.h
@@ -11,80 +11,15 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
+#include "lib/timer.h"
#include "lib/socket.h"
-// #include "sysdep/unix/timer.h"
-typedef struct timer2
-{
- resource r;
- void (*hook)(struct timer2 *);
- void *data;
-
- btime expires; /* 0=inactive */
- uint randomize; /* Amount of randomization */
- uint recurrent; /* Timer recurrence */
-
- int index;
-} timer2;
-
-
-btime current_time(void);
-
void ev2_schedule(event *e);
-
-timer2 *tm2_new(pool *p);
-void tm2_set(timer2 *t, btime when);
-void tm2_start(timer2 *t, btime after);
-void tm2_stop(timer2 *t);
-
-static inline int
-tm2_active(timer2 *t)
-{
- return t->expires != 0;
-}
-
-static inline btime
-tm2_remains(timer2 *t)
-{
- btime now = current_time();
- return (t->expires > now) ? (t->expires - now) : 0;
-}
-
-static inline timer2 *
-tm2_new_init(pool *p, void (*hook)(struct timer2 *), void *data, uint rec, uint rand)
-{
- timer2 *t = tm2_new(p);
- t->hook = hook;
- t->data = data;
- t->recurrent = rec;
- t->randomize = rand;
- return t;
-}
-
-static inline void
-tm2_set_max(timer2 *t, btime when)
-{
- if (when > t->expires)
- tm2_set(t, when);
-}
-
-/*
-static inline void
-tm2_start_max(timer2 *t, btime after)
-{
- btime rem = tm2_remains(t);
- tm2_start(t, MAX_(rem, after));
-}
-*/
-
-
void sk_start(sock *s);
void sk_stop(sock *s);
-
-
struct birdloop *birdloop_new(void);
void birdloop_start(struct birdloop *loop);
void birdloop_stop(struct birdloop *loop);
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 0cf48c9d..ebd380ba 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -37,6 +37,7 @@
#include "sysdep/unix/timer.h"
#include "lib/socket.h"
#include "lib/event.h"
+#include "lib/timer.h"
#include "lib/string.h"
#include "nest/iface.h"
@@ -479,6 +480,47 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
}
+/*
+ * Time clock
+ */
+
+void
+times_init(struct timeloop *loop)
+{
+ struct timespec ts;
+ int rv;
+
+ rv = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (rv < 0)
+ die("Monotonic clock is missing");
+
+ if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40)))
+ log(L_WARN "Monotonic clock is crazy");
+
+ loop->last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
+ loop->real_time = 0;
+}
+
+void
+times_update(struct timeloop *loop)
+{
+ struct timespec ts;
+ int rv;
+
+ rv = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (rv < 0)
+ die("clock_gettime: %m");
+
+ btime new_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
+
+ if (new_time < loop->last_time)
+ log(L_ERR "Monotonic clock is broken");
+
+ loop->last_time = new_time;
+ loop->real_time = 0;
+}
+
+
/**
* DOC: Sockets
*
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index c1b92b7e..396310fd 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -27,6 +27,7 @@
#include "lib/resource.h"
#include "lib/socket.h"
#include "lib/event.h"
+#include "lib/timer.h"
#include "lib/string.h"
#include "nest/route.h"
#include "nest/protocol.h"
@@ -820,6 +821,7 @@ main(int argc, char **argv)
log_switch(debug_flag, NULL, NULL);
resource_init();
+ timer_init();
olock_init();
io_init();
rt_init();