mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-31 14:11:54 +00:00
IO: added a specific loop pickup group for BFD; to be done better in future
This commit is contained in:
parent
61e64d6a41
commit
787fb56da3
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -78,6 +78,7 @@ struct bird_thread
|
||||
struct rcu_thread rcu;
|
||||
|
||||
list loops;
|
||||
struct birdloop_pickup_group *group;
|
||||
pool *pool;
|
||||
struct pfd *pfd;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user