diff options
author | Maria Matejka <mq@jmq.cz> | 2021-12-01 21:52:55 +0000 |
---|---|---|
committer | Maria Matejka <mq@jmq.cz> | 2021-12-01 21:52:55 +0000 |
commit | b2bac7ae91253b0bd27e9b03ec5fc30ac1522928 (patch) | |
tree | 8d8d18cbeaa5516fe5dd498fa53a355b078f6b8c | |
parent | 387b279f605c096c6ecb16d6608c700c533edb13 (diff) |
Faster shutdown and cleanups by freeing route attributes strictly from main loop
-rw-r--r-- | nest/route.h | 14 | ||||
-rw-r--r-- | nest/rt-attr.c | 80 | ||||
-rw-r--r-- | sysdep/unix/coroutine.c | 3 |
3 files changed, 66 insertions, 31 deletions
diff --git a/nest/route.h b/nest/route.h index afd7a783..9093108b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -883,14 +883,22 @@ static inline rta *rta_clone(rta *r) { return r; } -void rta__free(rta *r); +#define RTA_OBSOLETE_LIMIT 512 + +extern _Atomic u32 rta_obsolete_count; +extern event rta_cleanup_event; + static inline void rta_free(rta *r) { if (!r) return; u32 uc = atomic_fetch_sub_explicit(&r->uc, 1, memory_order_acq_rel); - if (uc == 1) - rta__free(r); + if (uc > 1) + return; + + u32 obs = atomic_fetch_add_explicit(&rta_obsolete_count, 1, memory_order_acq_rel); + if (obs == RTA_OBSOLETE_LIMIT) + ev_send(&global_work_list, &rta_cleanup_event); } rta *rta_do_cow(rta *o, linpool *lp); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 357cd216..be563491 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1384,52 +1384,78 @@ rta_lookup(rta *o) return r; } -void -rta__free(rta *a) +static void +rta_cleanup(void *data UNUSED) { - ASSERT(a->cached); + u32 count = 0; + rta *ax[RTA_OBSOLETE_LIMIT]; RTA_LOCK; struct rta_cache *c = atomic_load_explicit(&rta_cache, memory_order_acquire); - if (atomic_load_explicit(&a->uc, memory_order_acquire)) - { - /* Acquired inbetween */ - RTA_UNLOCK; - return; - } + for(u32 h=0; h<c->size; h++) + for(rta *a = atomic_load_explicit(&c->table[h], memory_order_acquire), *next; + a; + a = next) + { + next = atomic_load_explicit(&a->next, memory_order_acquire); + if (atomic_load_explicit(&a->uc, memory_order_acquire) > 0) + continue; - /* Relink the forward pointer */ - rta *next = atomic_load_explicit(&a->next, memory_order_acquire); - atomic_store_explicit(a->pprev, next, memory_order_release); + /* Check if the cleanup fits in the buffer */ + if (count == RTA_OBSOLETE_LIMIT) + { + ev_send(&global_work_list, &rta_cleanup_event); + goto wait; + } - /* Relink the backwards pointer */ - if (next) - next->pprev = a->pprev; + /* Relink the forward pointer */ + atomic_store_explicit(a->pprev, next, memory_order_release); + /* Relink the backwards pointer */ + if (next) + next->pprev = a->pprev; + + /* Store for freeing and go to the next */ + ax[count++] = a; + a = next; + } + +wait: /* Wait until nobody knows about us */ synchronize_rcu(); - if (atomic_load_explicit(&a->uc, memory_order_acquire)) + u32 freed = 0; + + for (u32 i=0; i<count; i++) { + rta *a = ax[i]; /* Acquired inbetween, relink back */ - rta_insert(a, c); - RTA_UNLOCK; - return; + if (atomic_load_explicit(&a->uc, memory_order_acquire)) + { + rta_insert(a, c); + continue; + } + + /* Cleared to free the memory */ + rt_unlock_hostentry(a->hostentry); + if (a->nh.next) + nexthop_free(a->nh.next); + ea_free(a->eattrs); + a->cached = 0; + c->count--; + sl_free(rta_slab(a), a); + freed++; } - /* Cleared to free the memory */ - rt_unlock_hostentry(a->hostentry); - if (a->nh.next) - nexthop_free(a->nh.next); - ea_free(a->eattrs); - a->cached = 0; - c->count--; - sl_free(rta_slab(a), a); + atomic_fetch_sub_explicit(&rta_obsolete_count, freed, memory_order_release); RTA_UNLOCK; } +_Atomic u32 rta_obsolete_count; +event rta_cleanup_event = { .hook = rta_cleanup, .list = &global_work_list }; + rta * rta_do_cow(rta *o, linpool *lp) { diff --git a/sysdep/unix/coroutine.c b/sysdep/unix/coroutine.c index e4657157..4747d01a 100644 --- a/sysdep/unix/coroutine.c +++ b/sysdep/unix/coroutine.c @@ -201,5 +201,6 @@ struct coroutine *coro_run(pool *p, void (*entry)(void *), void *data) void coro_yield(void) { - usleep(100); + const struct timespec req = { .tv_nsec = 100 }; + nanosleep(&req, NULL); } |