summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria Matejka <mq@jmq.cz>2021-12-01 21:52:55 +0000
committerMaria Matejka <mq@jmq.cz>2021-12-01 21:52:55 +0000
commitb2bac7ae91253b0bd27e9b03ec5fc30ac1522928 (patch)
tree8d8d18cbeaa5516fe5dd498fa53a355b078f6b8c
parent387b279f605c096c6ecb16d6608c700c533edb13 (diff)
Faster shutdown and cleanups by freeing route attributes strictly from main loop
-rw-r--r--nest/route.h14
-rw-r--r--nest/rt-attr.c80
-rw-r--r--sysdep/unix/coroutine.c3
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);
}