summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/io-loop.h2
-rw-r--r--nest/proto.c2
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/rt-table.c2
-rw-r--r--proto/bfd/config.Y1
-rw-r--r--sysdep/unix/io-loop.c209
-rw-r--r--sysdep/unix/io-loop.h1
7 files changed, 128 insertions, 90 deletions
diff --git a/lib/io-loop.h b/lib/io-loop.h
index 502d77fc..877cd5ce 100644
--- a/lib/io-loop.h
+++ b/lib/io-loop.h
@@ -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
diff --git a/nest/proto.c b/nest/proto.c
index 21460e56..cd6a3faa 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -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);
diff --git a/nest/protocol.h b/nest/protocol.h
index fe987d17..01153162 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -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 */
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 54aa90a6..b18727b1 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -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);
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index 0d6e33fa..8e608bda 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -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;
diff --git a/sysdep/unix/io-loop.c b/sysdep/unix/io-loop.c
index 2532fe33..efb408e0 100644
--- a/sysdep/unix/io-loop.c
+++ b/sysdep/unix/io-loop.c
@@ -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
diff --git a/sysdep/unix/io-loop.h b/sysdep/unix/io-loop.h
index c531d43e..2b0b7ebf 100644
--- a/sysdep/unix/io-loop.h
+++ b/sysdep/unix/io-loop.h
@@ -78,6 +78,7 @@ struct bird_thread
struct rcu_thread rcu;
list loops;
+ struct birdloop_pickup_group *group;
pool *pool;
struct pfd *pfd;