mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Timers: Split microsecond timers from BFD code to lib
This commit is contained in:
parent
7c454d9186
commit
534215a18f
@ -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)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
|
|
||||||
|
207
lib/timer.c
Normal file
207
lib/timer.c
Normal file
@ -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();
|
||||||
|
}
|
104
lib/timer.h
Normal file
104
lib/timer.h
Normal file
@ -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
|
275
proto/bfd/io.c
275
proto/bfd/io.c
@ -18,10 +18,10 @@
|
|||||||
#include "proto/bfd/io.h"
|
#include "proto/bfd/io.h"
|
||||||
|
|
||||||
#include "lib/buffer.h"
|
#include "lib/buffer.h"
|
||||||
#include "lib/heap.h"
|
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
#include "lib/timer.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
|
|
||||||
|
|
||||||
@ -31,16 +31,12 @@ struct birdloop
|
|||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
btime last_time;
|
|
||||||
btime real_time;
|
|
||||||
u8 use_monotonic_clock;
|
|
||||||
|
|
||||||
u8 stop_called;
|
u8 stop_called;
|
||||||
u8 poll_active;
|
u8 poll_active;
|
||||||
u8 wakeup_masked;
|
u8 wakeup_masked;
|
||||||
int wakeup_fds[2];
|
int wakeup_fds[2];
|
||||||
|
|
||||||
BUFFER(timer2 *) timers;
|
struct timeloop time;
|
||||||
list event_list;
|
list event_list;
|
||||||
list sock_list;
|
list sock_list;
|
||||||
uint sock_num;
|
uint sock_num;
|
||||||
@ -57,6 +53,7 @@ struct birdloop
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static pthread_key_t current_loop_key;
|
static pthread_key_t current_loop_key;
|
||||||
|
extern pthread_key_t current_time_key;
|
||||||
|
|
||||||
static inline struct birdloop *
|
static inline struct birdloop *
|
||||||
birdloop_current(void)
|
birdloop_current(void)
|
||||||
@ -68,6 +65,7 @@ static inline void
|
|||||||
birdloop_set_current(struct birdloop *loop)
|
birdloop_set_current(struct birdloop *loop)
|
||||||
{
|
{
|
||||||
pthread_setspecific(current_loop_key, loop);
|
pthread_setspecific(current_loop_key, loop);
|
||||||
|
pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -77,98 +75,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
|
* Wakeup code for birdloop
|
||||||
*/
|
*/
|
||||||
@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
|
|||||||
loop->wakeup_masked = 2;
|
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
|
* Events
|
||||||
@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
|
|||||||
static void
|
static void
|
||||||
events_fire(struct birdloop *loop)
|
events_fire(struct birdloop *loop)
|
||||||
{
|
{
|
||||||
times_update(loop);
|
times_update(&loop->time);
|
||||||
ev_run_list(&loop->event_list);
|
ev_run_list(&loop->event_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,154 +207,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
|
* Sockets
|
||||||
*/
|
*/
|
||||||
@ -586,7 +354,7 @@ sockets_fire(struct birdloop *loop)
|
|||||||
sock **psk = loop->poll_sk.data;
|
sock **psk = loop->poll_sk.data;
|
||||||
int poll_num = loop->poll_fd.used - 1;
|
int poll_num = loop->poll_fd.used - 1;
|
||||||
|
|
||||||
times_update(loop);
|
times_update(&loop->time);
|
||||||
|
|
||||||
/* Last fd is internal wakeup fd */
|
/* Last fd is internal wakeup fd */
|
||||||
if (pfd[poll_num].revents & POLLIN)
|
if (pfd[poll_num].revents & POLLIN)
|
||||||
@ -634,11 +402,10 @@ birdloop_new(void)
|
|||||||
loop->pool = p;
|
loop->pool = p;
|
||||||
pthread_mutex_init(&loop->mutex, NULL);
|
pthread_mutex_init(&loop->mutex, NULL);
|
||||||
|
|
||||||
times_init(loop);
|
|
||||||
wakeup_init(loop);
|
wakeup_init(loop);
|
||||||
|
|
||||||
events_init(loop);
|
events_init(loop);
|
||||||
timers_init(loop);
|
timers_init(&loop->time, p);
|
||||||
sockets_init(loop);
|
sockets_init(loop);
|
||||||
|
|
||||||
return loop;
|
return loop;
|
||||||
@ -719,12 +486,12 @@ birdloop_main(void *arg)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
events_fire(loop);
|
events_fire(loop);
|
||||||
timers_fire(loop);
|
timers_fire(&loop->time);
|
||||||
|
|
||||||
times_update(loop);
|
times_update(&loop->time);
|
||||||
if (events_waiting(loop))
|
if (events_waiting(loop))
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
else if (t = timers_first(loop))
|
else if (t = timers_first(&loop->time))
|
||||||
timeout = (tm2_remains(t) TO_MS) + 1;
|
timeout = (tm2_remains(t) TO_MS) + 1;
|
||||||
else
|
else
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
@ -756,7 +523,7 @@ birdloop_main(void *arg)
|
|||||||
if (rv)
|
if (rv)
|
||||||
sockets_fire(loop);
|
sockets_fire(loop);
|
||||||
|
|
||||||
timers_fire(loop);
|
timers_fire(&loop->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop->stop_called = 0;
|
loop->stop_called = 0;
|
||||||
|
@ -11,80 +11,15 @@
|
|||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
#include "lib/timer.h"
|
||||||
#include "lib/socket.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);
|
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_start(sock *s);
|
||||||
void sk_stop(sock *s);
|
void sk_stop(sock *s);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct birdloop *birdloop_new(void);
|
struct birdloop *birdloop_new(void);
|
||||||
void birdloop_start(struct birdloop *loop);
|
void birdloop_start(struct birdloop *loop);
|
||||||
void birdloop_stop(struct birdloop *loop);
|
void birdloop_stop(struct birdloop *loop);
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "sysdep/unix/timer.h"
|
#include "sysdep/unix/timer.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
#include "lib/timer.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "nest/iface.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
|
* DOC: Sockets
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
#include "lib/timer.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "nest/route.h"
|
#include "nest/route.h"
|
||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
@ -820,6 +821,7 @@ main(int argc, char **argv)
|
|||||||
log_switch(debug_flag, NULL, NULL);
|
log_switch(debug_flag, NULL, NULL);
|
||||||
|
|
||||||
resource_init();
|
resource_init();
|
||||||
|
timer_init();
|
||||||
olock_init();
|
olock_init();
|
||||||
io_init();
|
io_init();
|
||||||
rt_init();
|
rt_init();
|
||||||
|
Loading…
Reference in New Issue
Block a user