]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Timers: Split microsecond timers from BFD code to lib
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 30 May 2017 17:12:35 +0000 (19:12 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 7 Dec 2017 12:46:53 +0000 (13:46 +0100)
lib/Makefile
lib/timer.c [new file with mode: 0644]
lib/timer.h [new file with mode: 0644]
proto/bfd/io.c
proto/bfd/io.h
sysdep/unix/io.c
sysdep/unix/main.c

index 0c3528698fe02a26a6f6d7630e7b7618633a8f45..01f3114d65b8bcf23c9a702bbabfc67e656a0c4c 100644 (file)
@@ -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 (file)
index 0000000..00ac4b0
--- /dev/null
@@ -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 (file)
index 0000000..88c5354
--- /dev/null
@@ -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
index 8f4f50074c4d1248a7540ec87b2e912567629511..ab846113ce53b0afa0c6d57b44828ee3e5f1ac8a 100644 (file)
 #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
@@ -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
  */
@@ -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);
 }
 
@@ -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
  */
@@ -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;
index 45836f84adc024aa294435343f93900b3df1f403..ec706e9a81700fe5a7ac0d3bd42164ad2481c81d 100644 (file)
 #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);
index 0cf48c9dd9953c5ef3654ccd6d8bcca2a7277027..ebd380ba578d4422b93a25ded8d92251c2aff5a1 100644 (file)
@@ -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
  *
index c1b92b7eb64130962d287571b647fff1317f16d9..396310fd62b5777c2721aa780b70f9f3b7120c51 100644 (file)
@@ -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();