diff --git a/lib/birdlib.h b/lib/birdlib.h index d7b394ce..3f65b8c2 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -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_ diff --git a/sysdep/unix/io-loop.c b/sysdep/unix/io-loop.c index 0e2396f7..2532fe33 100644 --- a/sysdep/unix/io-loop.c +++ b/sysdep/unix/io-loop.c @@ -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; diff --git a/sysdep/unix/io-loop.h b/sysdep/unix/io-loop.h index 7ec903af..c531d43e 100644 --- a/sysdep/unix/io-loop.h +++ b/sysdep/unix/io-loop.h @@ -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