diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-05-30 19:12:35 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-12-07 13:46:53 +0100 |
commit | 534215a18fb3fb7ce5b26c9e6ec1fdb32bf22ae6 (patch) | |
tree | b805e7f9dcf6e999dfad01117bc72f4bee6f2a6d /lib/timer.c | |
parent | 7c454d918682c072a6ae6ad8e0cd8d35b9edd2aa (diff) |
Timers: Split microsecond timers from BFD code to lib
Diffstat (limited to 'lib/timer.c')
-rw-r--r-- | lib/timer.c | 207 |
1 files changed, 207 insertions, 0 deletions
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(¤t_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(); +} |