]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
IO: added a specific loop pickup group for BFD; to be done better in future
authorMaria Matejka <mq@ucw.cz>
Mon, 17 Apr 2023 09:37:29 +0000 (11:37 +0200)
committerMaria Matejka <mq@ucw.cz>
Mon, 17 Apr 2023 11:30:14 +0000 (13:30 +0200)
lib/io-loop.h
nest/proto.c
nest/protocol.h
nest/rt-table.c
proto/bfd/config.Y
sysdep/unix/io-loop.c
sysdep/unix/io-loop.h

index 502d77fc59f577c4330192a95c37cef89d4d32bf..877cd5cec940892e4798ee6bc8bb33a94f5a3439 100644 (file)
@@ -17,7 +17,7 @@
 extern struct birdloop main_birdloop;
 
 /* Start a new birdloop owned by given pool and domain */
-struct birdloop *birdloop_new(pool *p, uint order, const char *name);
+struct birdloop *birdloop_new(pool *p, uint order, const char *name, btime max_latency);
 
 /* Stop the loop. At the end, the @stopped callback is called unlocked in tail
  * position to finish cleanup. Run birdloop_free() from that callback to free
index 21460e56c40e36bf2067e4698d3e99833d559e04..cd6a3faa6cb9b64063825ca7b6d5c7758a11cfeb 100644 (file)
@@ -1220,7 +1220,7 @@ proto_start(struct proto *p)
     p->gr_recovery = 1;
 
   if (p->cf->loop_order != DOMAIN_ORDER(the_bird))
-    p->loop = birdloop_new(p->pool, p->cf->loop_order, p->pool->name);
+    p->loop = birdloop_new(p->pool, p->cf->loop_order, p->pool->name, p->cf->loop_max_latency);
 
   p->iface_sub.target = proto_event_list(p);
 
index fe987d1793e9502dfc500114baba4aac92a1793e..01153162ff53292a0e86f03c70b22ba222ae8657 100644 (file)
@@ -106,6 +106,7 @@ struct proto_config {
   u32 debug, mrtdump;                  /* Debugging bitfields, both use D_* constants */
   u32 router_id;                       /* Protocol specific router ID */
   uint loop_order;                     /* Launch a birdloop on this locking level; use DOMAIN_ORDER(the_bird) for mainloop */
+  btime loop_max_latency;              /* Request this specific maximum latency of loop; zero to default */
 
   list channels;                       /* List of channel configs (struct channel_config) */
   struct iface *vrf;                   /* Related VRF instance, NULL if global */
index 54aa90a6fbcb9d5e71b138f0d33c0145d8bde1d7..b18727b1b8055331c92adaa77e0bdd942441d029 100644 (file)
@@ -2907,7 +2907,7 @@ rt_setup(pool *pp, struct rtable_config *cf)
   }
 
   /* Start the service thread */
-  t->loop = birdloop_new(p, DOMAIN_ORDER(service), mb_sprintf(p, "Routing table %s", t->name));
+  t->loop = birdloop_new(p, DOMAIN_ORDER(service), mb_sprintf(p, "Routing table %s", t->name), 0);
   birdloop_enter(t->loop);
   birdloop_flag_set_handler(t->loop, &t->fh);
   birdloop_leave(t->loop);
index 0d6e33faca465e365b8f43bebdbdd421ef132ad0..8e608bdac9d3704ee4f059e6983bc43377b427c3 100644 (file)
@@ -38,6 +38,7 @@ bfd_proto_start: proto_start BFD
 {
   this_proto = proto_config_new(&proto_bfd, $1);
   this_proto->loop_order = DOMAIN_ORDER(proto);
+  this_proto->loop_max_latency = 10 MS_;
   init_list(&BFD_CFG->patt_list);
   init_list(&BFD_CFG->neigh_list);
   BFD_CFG->accept_ipv4 = BFD_CFG->accept_ipv6 = 1;
index 2532fe337420d7b4ee47585d90fdfd3dbe09f72c..efb408e041cc1df459f29a1811e4b7246b56215c 100644 (file)
@@ -31,7 +31,7 @@
 
 #define THREAD_STACK_SIZE      65536   /* To be lowered in near future */
 
-static struct birdloop *birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup);
+static struct birdloop *birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup, struct birdloop_pickup_group *group);
 
 /*
  *     Nanosecond time for accounting purposes
@@ -497,14 +497,26 @@ sockets_fire(struct birdloop *loop)
  */
 
 DEFINE_DOMAIN(resource);
-static DOMAIN(resource) birdloop_domain;
-static list birdloop_pickup;
-static list bird_thread_pickup;
+
+struct birdloop_pickup_group {
+  DOMAIN(resource) domain;
+  list loops;
+  list threads;
+  btime max_latency;
+} pickup_groups[2] = {
+  {
+    /* all zeroes */
+  },
+  {
+    /* FIXME: make this dynamic, now it copies the loop_max_latency value from proto/bfd/config.Y */
+    .max_latency = 10 MS,
+  },
+};
 
 static _Thread_local struct bird_thread *this_thread;
 
 static void
-birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr)
+birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr, struct birdloop_pickup_group *group)
 {
   struct bird_thread *old = loop->thread;
   ASSERT_DIE(!thr != !old);
@@ -530,9 +542,9 @@ birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr)
   {
     old->loop_count--;
 
-    LOCK_DOMAIN(resource, birdloop_domain);
-    add_tail(&birdloop_pickup, &loop->n);
-    UNLOCK_DOMAIN(resource, birdloop_domain);
+    LOCK_DOMAIN(resource, group->domain);
+    add_tail(&group->loops, &loop->n);
+    UNLOCK_DOMAIN(resource, group->domain);
   }
 
   /* Finished */
@@ -543,54 +555,54 @@ birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr)
 }
 
 static struct birdloop *
-birdloop_take(void)
+birdloop_take(struct birdloop_pickup_group *group)
 {
   struct birdloop *loop = NULL;
 
-  LOCK_DOMAIN(resource, birdloop_domain);
-  if (!EMPTY_LIST(birdloop_pickup))
+  LOCK_DOMAIN(resource, group->domain);
+  if (!EMPTY_LIST(group->loops))
   {
     /* Take the first loop from the pickup list and unlock */
-    loop = SKIP_BACK(struct birdloop, n, HEAD(birdloop_pickup));
+    loop = SKIP_BACK(struct birdloop, n, HEAD(group->loops));
     rem_node(&loop->n);
-    UNLOCK_DOMAIN(resource, birdloop_domain);
+    UNLOCK_DOMAIN(resource, group->domain);
 
-    birdloop_set_thread(loop, this_thread);
+    birdloop_set_thread(loop, this_thread, group);
 
     /* This thread goes to the end of the pickup list */
-    LOCK_DOMAIN(resource, birdloop_domain);
+    LOCK_DOMAIN(resource, group->domain);
     rem_node(&this_thread->n);
-    add_tail(&bird_thread_pickup, &this_thread->n);
+    add_tail(&group->threads, &this_thread->n);
 
     /* If there are more loops to be picked up, wakeup the next thread in order */
-    if (!EMPTY_LIST(birdloop_pickup))
-      wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(bird_thread_pickup)));
+    if (!EMPTY_LIST(group->loops))
+      wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
   }
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  UNLOCK_DOMAIN(resource, group->domain);
 
   return loop;
 }
 
 static void
-birdloop_drop(struct birdloop *loop)
+birdloop_drop(struct birdloop *loop, struct birdloop_pickup_group *group)
 {
   /* Remove loop from this thread's list */
   rem_node(&loop->n);
 
   /* Unset loop's thread */
   if (birdloop_inside(loop))
-    birdloop_set_thread(loop, NULL);
+    birdloop_set_thread(loop, NULL, group);
   else
   {
     birdloop_enter(loop);
-    birdloop_set_thread(loop, NULL);
+    birdloop_set_thread(loop, NULL, group);
     birdloop_leave(loop);
   }
 
   /* Put loop into pickup list */
-  LOCK_DOMAIN(resource, birdloop_domain);
-  add_tail(&birdloop_pickup, &loop->n);
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  LOCK_DOMAIN(resource, group->domain);
+  add_tail(&group->loops, &loop->n);
+  UNLOCK_DOMAIN(resource, group->domain);
 }
 
 static int
@@ -615,7 +627,7 @@ bird_thread_main(void *arg)
   tmp_init(thr->pool);
   init_list(&thr->loops);
 
-  thr->meta = birdloop_new_internal(thr->pool, DOMAIN_ORDER(meta), "Thread Meta", 0);
+  thr->meta = birdloop_new_internal(thr->pool, DOMAIN_ORDER(meta), "Thread Meta", 0, thr->group);
   thr->meta->thread = thr;
   birdloop_enter(thr->meta);
 
@@ -632,7 +644,7 @@ bird_thread_main(void *arg)
     int timeout;
 
     /* Pickup new loops */
-    struct birdloop *loop = birdloop_take();
+    struct birdloop *loop = birdloop_take(thr->group);
     if (loop)
     {
       birdloop_enter(loop);
@@ -738,23 +750,23 @@ bird_thread_cleanup(void *_thr)
 }
 
 static struct bird_thread *
-bird_thread_start(btime max_latency)
+bird_thread_start(struct birdloop_pickup_group *group)
 {
   ASSERT_DIE(birdloop_inside(&main_birdloop));
+  ASSERT_DIE(DOMAIN_IS_LOCKED(resource, group->domain));
 
   pool *p = rp_new(&root_pool, "Thread");
 
   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;
+  thr->group = group;
+  thr->max_latency_ns = (group->max_latency ?: 5 S) TO_NS;
 
   wakeup_init(thr);
   ev_init_list(&thr->priority_events, NULL, "Thread direct event list");
 
-  LOCK_DOMAIN(resource, birdloop_domain);
-  add_tail(&bird_thread_pickup, &thr->n);
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  add_tail(&group->threads, &thr->n);
 
   int e = 0;
 
@@ -782,8 +794,9 @@ static uint thread_dropper_goal;
 static void
 bird_thread_shutdown(void * _ UNUSED)
 {
-  LOCK_DOMAIN(resource, birdloop_domain);
-  int dif = list_length(&bird_thread_pickup) - thread_dropper_goal;
+  struct birdloop_pickup_group *group = this_thread->group;
+  LOCK_DOMAIN(resource, group->domain);
+  int dif = list_length(&group->threads) - thread_dropper_goal;
   struct birdloop *tdl_stop = NULL;
 
   if (dif > 0)
@@ -794,7 +807,7 @@ bird_thread_shutdown(void * _ UNUSED)
     thread_dropper = NULL;
   }
 
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  UNLOCK_DOMAIN(resource, group->domain);
 
   DBG("Thread pickup size differs from dropper goal by %d%s\n", dif, tdl_stop ? ", stopping" : "");
 
@@ -807,18 +820,18 @@ bird_thread_shutdown(void * _ UNUSED)
   struct bird_thread *thr = this_thread;
 
   /* Leave the thread-picker list to get no more loops */
-  LOCK_DOMAIN(resource, birdloop_domain);
+  LOCK_DOMAIN(resource, group->domain);
   rem_node(&thr->n);
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  UNLOCK_DOMAIN(resource, group->domain);
 
   /* Drop loops including the thread dropper itself */
   while (!EMPTY_LIST(thr->loops))
-    birdloop_drop(HEAD(thr->loops));
+    birdloop_drop(HEAD(thr->loops), group);
 
   /* Let others know about new loops */
-  if (!EMPTY_LIST(birdloop_pickup))
-    wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(bird_thread_pickup)));
-  UNLOCK_DOMAIN(resource, birdloop_domain);
+  if (!EMPTY_LIST(group->loops))
+    wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
+  UNLOCK_DOMAIN(resource, group->domain);
 
   /* Leave the thread-dropper loop as we aren't going to return. */
   birdloop_leave(thread_dropper);
@@ -855,26 +868,30 @@ bird_thread_commit(struct config *new, struct config *old UNUSED)
 
   while (1)
   {
-    LOCK_DOMAIN(resource, birdloop_domain);
-    int dif = list_length(&bird_thread_pickup) - (thread_dropper_goal = new->thread_count);
+    struct birdloop_pickup_group *group = &pickup_groups[0];
+    LOCK_DOMAIN(resource, group->domain);
+
+    int dif = list_length(&group->threads) - (thread_dropper_goal = new->thread_count);
     _Bool thread_dropper_running = !!thread_dropper;
-    UNLOCK_DOMAIN(resource, birdloop_domain);
 
     if (dif < 0)
     {
-      bird_thread_start(5 S);
+      bird_thread_start(group);
+      UNLOCK_DOMAIN(resource, group->domain);
       continue;
     }
 
+    UNLOCK_DOMAIN(resource, group->domain);
+
     if ((dif > 0) && !thread_dropper_running)
     {
-      struct birdloop *tdl = birdloop_new(&root_pool, DOMAIN_ORDER(control), "Thread dropper");
+      struct birdloop *tdl = birdloop_new(&root_pool, DOMAIN_ORDER(control), "Thread dropper", group->max_latency);
       event *tde = ev_new_init(tdl->pool, bird_thread_shutdown, NULL);
 
-      LOCK_DOMAIN(resource, birdloop_domain);
+      LOCK_DOMAIN(resource, group->domain);
       thread_dropper = tdl;
       thread_dropper_event = tde;
-      UNLOCK_DOMAIN(resource, birdloop_domain);
+      UNLOCK_DOMAIN(resource, group->domain);
 
       ev_send_loop(thread_dropper, thread_dropper_event);
     }
@@ -945,26 +962,31 @@ bird_thread_show(void *data)
   {
     the_bird_lock();
 
-    LOCK_DOMAIN(resource, birdloop_domain);
-    if (!EMPTY_LIST(birdloop_pickup))
-      if (tsd->show_loops)
-      {
-       cli_printf(tsd->cli, -1026, "Unassigned loops");
-       WALK_LIST(loop, birdloop_pickup)
-         cli_printf(tsd->cli, -1026, "  Loop %s time: %t", domain_name(loop->time.domain), loop->total_time_spent_ns NS);
-      }
-      else
-      {
-       uint count = 0;
-       u64 total_time_ns = 0;
-       WALK_LIST(loop, birdloop_pickup)
+    for (int i=0; i<2; i++)
+    {
+      struct birdloop_pickup_group *group = &pickup_groups[i];
+
+      LOCK_DOMAIN(resource, group->domain);
+      if (!EMPTY_LIST(group->loops))
+       if (tsd->show_loops)
        {
-         count++;
-         total_time_ns += loop->total_time_spent_ns;
+         cli_printf(tsd->cli, -1026, "Unassigned loops");
+         WALK_LIST(loop, group->loops)
+           cli_printf(tsd->cli, -1026, "  Loop %s time: %t", domain_name(loop->time.domain), loop->total_time_spent_ns NS);
        }
-       cli_printf(tsd->cli, -1026, "Unassigned loops: %d, total time %t", count, total_time_ns NS);
-      }
-    UNLOCK_DOMAIN(resource, birdloop_domain);
+       else
+       {
+         uint count = 0;
+         u64 total_time_ns = 0;
+         WALK_LIST(loop, group->loops)
+         {
+           count++;
+           total_time_ns += loop->total_time_spent_ns;
+         }
+         cli_printf(tsd->cli, -1026, "Unassigned loops: %d, total time %t", count, total_time_ns NS);
+       }
+      UNLOCK_DOMAIN(resource, group->domain);
+    }
 
     cli_write_trigger(tsd->cli);
     DOMAIN_FREE(control, tsd->lock);
@@ -989,19 +1011,24 @@ cmd_show_threads(int show_loops)
   this_cli->cont = bird_thread_show_cli_cont;
   this_cli->cleanup = bird_thread_show_cli_cleanup;
 
-  LOCK_DOMAIN(control, tsd->lock);
-  LOCK_DOMAIN(resource, birdloop_domain);
-
-  struct bird_thread *thr;
-  WALK_LIST(thr, bird_thread_pickup)
+  for (int i=0; i<2; i++)
   {
-    tsd->total++;
-    ev_send(&thr->priority_events, ev_new_init(p, bird_thread_show, tsd));
-    wakeup_do_kick(thr);
-  }
+    struct birdloop_pickup_group *group = &pickup_groups[i];
 
-  UNLOCK_DOMAIN(resource, birdloop_domain);
-  UNLOCK_DOMAIN(control, tsd->lock);
+    LOCK_DOMAIN(control, tsd->lock);
+    LOCK_DOMAIN(resource, group->domain);
+
+    struct bird_thread *thr;
+    WALK_LIST(thr, group->threads)
+    {
+      tsd->total++;
+      ev_send(&thr->priority_events, ev_new_init(p, bird_thread_show, tsd));
+      wakeup_do_kick(thr);
+    }
+
+    UNLOCK_DOMAIN(resource, group->domain);
+    UNLOCK_DOMAIN(control, tsd->lock);
+  }
 }
 
 /*
@@ -1018,9 +1045,14 @@ birdloop_init(void)
 {
   ns_init();
 
-  birdloop_domain = DOMAIN_NEW(resource, "Loop Pickup");
-  init_list(&birdloop_pickup);
-  init_list(&bird_thread_pickup);
+  for (int i=0; i<2; i++)
+  {
+    struct birdloop_pickup_group *group = &pickup_groups[i];
+
+    group->domain = DOMAIN_NEW(resource, "Loop Pickup");
+    init_list(&group->loops);
+    init_list(&group->threads);
+  }
 
   wakeup_init(main_birdloop.thread);
 
@@ -1146,7 +1178,7 @@ birdloop_run_timer(timer *tm)
 }
 
 static struct birdloop *
-birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup)
+birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup, struct birdloop_pickup_group *group)
 {
   struct domain_generic *dg = domain_new(name, order);
 
@@ -1170,10 +1202,13 @@ birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup
 
   if (request_pickup)
   {
-    LOCK_DOMAIN(resource, birdloop_domain);
-    add_tail(&birdloop_pickup, &loop->n);
-    wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(bird_thread_pickup)));
-    UNLOCK_DOMAIN(resource, birdloop_domain);
+    LOCK_DOMAIN(resource, group->domain);
+    add_tail(&group->loops, &loop->n);
+    if (EMPTY_LIST(group->threads))
+      bird_thread_start(group);
+
+    wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
+    UNLOCK_DOMAIN(resource, group->domain);
   }
   else
     loop->n.next = loop->n.prev = &loop->n;
@@ -1184,9 +1219,9 @@ birdloop_new_internal(pool *pp, uint order, const char *name, int request_pickup
 }
 
 struct birdloop *
-birdloop_new(pool *pp, uint order, const char *name)
+birdloop_new(pool *pp, uint order, const char *name, btime max_latency)
 {
-  return birdloop_new_internal(pp, order, name, 1);
+  return birdloop_new_internal(pp, order, name, 1, max_latency ? &pickup_groups[1] : &pickup_groups[0]);
 }
 
 static void
index c531d43efc0e723671c3fa689320827c8d3ac4fb..2b0b7ebf194472ec4abcdaedc0e1df7b62139be3 100644 (file)
@@ -78,6 +78,7 @@ struct bird_thread
   struct rcu_thread rcu;
 
   list loops;
+  struct birdloop_pickup_group *group;
   pool *pool;
   struct pfd *pfd;