]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Loop: keep running the same loop for some time if there is work to do
authorMaria Matejka <mq@ucw.cz>
Thu, 6 Apr 2023 18:18:04 +0000 (20:18 +0200)
committerMaria Matejka <mq@ucw.cz>
Thu, 6 Apr 2023 18:18:04 +0000 (20:18 +0200)
lib/birdlib.h
sysdep/unix/io-loop.c
sysdep/unix/io-loop.h

index d7b394ceca5b571a569e9fc12e1ae44bd8e31e64..3f65b8c2a5cf1bae532053fad54028c02fd72b22 100644 (file)
@@ -115,6 +115,7 @@ typedef s64 btime;
 #define TO_S   /1000000
 #define TO_MS  /1000
 #define TO_US  /1
+#define TO_NS  * (btime) 1000
 
 #ifndef PARSER
 #define S      S_
index 0e2396f7dfb246a603095c33486b052d925bdf5c..2532fe337420d7b4ee47585d90fdfd3dbe09f72c 100644 (file)
@@ -67,9 +67,14 @@ _Thread_local struct birdloop *birdloop_current;
 static _Thread_local struct birdloop *birdloop_wakeup_masked;
 static _Thread_local uint birdloop_wakeup_masked_count;
 
-#define LOOP_TRACE(loop, fmt, args...) do { if (config && config->latency_debug) log(L_TRACE "%s (%p): " fmt, domain_name((loop)->time.domain), (loop), ##args); } while (0)
+#define LOOP_NAME(loop)                        domain_name((loop)->time.domain)
+
+#define LOOP_TRACE(loop, fmt, args...) do { if (config && config->latency_debug) log(L_TRACE "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args); } while (0)
 #define THREAD_TRACE(...)              do { if (config && config->latency_debug) log(L_TRACE "Thread: " __VA_ARGS__); } while (0)
 
+#define LOOP_WARN(loop, fmt, args...)  log(L_TRACE "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args)
+
+
 event_list *
 birdloop_event_list(struct birdloop *loop)
 {
@@ -436,7 +441,7 @@ sockets_fire(struct birdloop *loop)
   if (EMPTY_LIST(loop->sock_list))
     return 0;
 
-  int sch = 0;
+  int repeat = 0;
 
   times_update();
 
@@ -454,6 +459,7 @@ sockets_fire(struct birdloop *loop)
 
       if (rev & POLLOUT)
       {
+       /* Write everything. */
        while ((s == loop->sock_active) && (e = sk_write(s)))
          ;
 
@@ -461,12 +467,14 @@ sockets_fire(struct birdloop *loop)
          continue;
 
        if (!sk_tx_pending(s))
-         sch++;
+         loop->thread->sock_changed++;
       }
 
       if (rev & POLLIN)
-       while (e && (s == loop->sock_active) && s->rx_hook)
-         e = sk_read(s, rev);
+       /* Read just one packet and request repeat. */
+       if ((s == loop->sock_active) && s->rx_hook)
+         if (sk_read(s, rev))
+           repeat++;
 
       if (s != loop->sock_active)
        continue;
@@ -481,7 +489,7 @@ sockets_fire(struct birdloop *loop)
     loop->sock_active = sk_next(s);
   }
 
-  return sch;
+  return repeat;
 }
 
 /*
@@ -498,6 +506,9 @@ static _Thread_local struct bird_thread *this_thread;
 static void
 birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr)
 {
+  struct bird_thread *old = loop->thread;
+  ASSERT_DIE(!thr != !old);
+
   /* Signal our moving effort */
   u32 ltt = atomic_fetch_or_explicit(&loop->thread_transition, LTT_MOVE, memory_order_acq_rel);
   ASSERT_DIE((ltt & LTT_MOVE) == 0);
@@ -511,9 +522,14 @@ birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr)
   /* Now we are free of running pings */
 
   if (loop->thread = thr)
+  {
     add_tail(&thr->loops, &loop->n);
+    thr->loop_count++;
+  }
   else
   {
+    old->loop_count--;
+
     LOCK_DOMAIN(resource, birdloop_domain);
     add_tail(&birdloop_pickup, &loop->n);
     UNLOCK_DOMAIN(resource, birdloop_domain);
@@ -612,6 +628,7 @@ bird_thread_main(void *arg)
 
   while (1)
   {
+    u64 thr_loop_start = ns_now();
     int timeout;
 
     /* Pickup new loops */
@@ -627,6 +644,11 @@ bird_thread_main(void *arg)
     /* Schedule all loops with timed out timers */
     timers_fire(&thr->meta->time, 0);
 
+    /* Compute maximal time per loop */
+    u64 thr_before_run = ns_now();
+    if (thr->loop_count > 0)
+      thr->max_loop_time_ns = (thr->max_latency_ns / 2 - (thr_before_run - thr_loop_start)) / (u64) thr->loop_count;
+
     /* Run all scheduled loops */
     int more_events = ev_run_list(&thr->meta->event_list);
     if (more_events)
@@ -716,7 +738,7 @@ bird_thread_cleanup(void *_thr)
 }
 
 static struct bird_thread *
-bird_thread_start(void)
+bird_thread_start(btime max_latency)
 {
   ASSERT_DIE(birdloop_inside(&main_birdloop));
 
@@ -725,6 +747,7 @@ bird_thread_start(void)
   struct bird_thread *thr = mb_allocz(p, sizeof(*thr));
   thr->pool = p;
   thr->cleanup_event = (event) { .hook = bird_thread_cleanup, .data = thr, };
+  thr->max_latency_ns = max_latency TO_NS;
 
   wakeup_init(thr);
   ev_init_list(&thr->priority_events, NULL, "Thread direct event list");
@@ -839,7 +862,7 @@ bird_thread_commit(struct config *new, struct config *old UNUSED)
 
     if (dif < 0)
     {
-      bird_thread_start();
+      bird_thread_start(5 S);
       continue;
     }
 
@@ -1061,30 +1084,40 @@ birdloop_run(void *_loop)
   /* Run priority events before the loop is executed */
   ev_run_list(&this_thread->priority_events);
 
+  u64 start_time = ns_now();
+  u64 end_time = start_time + this_thread->max_loop_time_ns;
+
   struct birdloop *loop = _loop;
   birdloop_enter(loop);
 
-  LOOP_TRACE(loop, "Regular run");
+  u64 locked_time = ns_now(), task_done_time;
+  if (locked_time > end_time)
+    LOOP_WARN(loop, "locked %luns after its scheduled end time", locked_time - end_time);
 
-  if (loop->stopped)
-    /* Birdloop left inside the helper function */
-    return birdloop_stop_internal(loop);
+  uint repeat, loop_runs = 0;
+  do {
+    repeat = 0;
+    LOOP_TRACE(loop, "Regular run");
+    loop_runs++;
 
-  /* Process sockets */
-  this_thread->sock_changed += sockets_fire(loop);
+    if (loop->stopped)
+      /* Birdloop left inside the helper function */
+      return birdloop_stop_internal(loop);
 
-  /* Run timers */
-  timers_fire(&loop->time, 0);
+    /* Process sockets */
+    repeat += sockets_fire(loop);
 
-  /* Run flag handlers */
-  if (birdloop_process_flags(loop))
-  {
-    LOOP_TRACE(loop, "Flag processing needs another run");
-    ev_send_loop(this_thread->meta, &loop->event);
-  }
+    /* Run timers */
+    timers_fire(&loop->time, 0);
 
-  /* Run events */
-  ev_run_list(&loop->event_list);
+    /* Run flag handlers */
+    repeat += birdloop_process_flags(loop);
+
+    /* Run events */
+    repeat += ev_run_list(&loop->event_list);
+
+    /* Check end time */
+  } while (((task_done_time = ns_now()) < end_time) && repeat);
 
   /* Request meta timer */
   timer *t = timers_first(&loop->time);
@@ -1093,6 +1126,10 @@ birdloop_run(void *_loop)
   else
     tm_stop(&loop->timer);
 
+  /* Request re-run if needed */
+  if (repeat)
+    ev_send_loop(this_thread->meta, &loop->event);
+
   /* Collect socket change requests */
   this_thread->sock_changed += loop->sock_changed;
   loop->sock_changed = 0;
index 7ec903af9b002afdcc91c2529db1ccf5067a2f95..c531d43efc0e723671c3fa689320827c8d3ac4fb 100644 (file)
@@ -84,6 +84,10 @@ struct bird_thread
   event cleanup_event;
 
   int sock_changed;
+  uint loop_count;
+
+  u64 max_latency_ns;
+  u64 max_loop_time_ns;
 };
 
 #endif