0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 07:31:54 +00:00

Route attribute usecount doesn't need to synchronize on unlock

This commit is contained in:
Maria Matejka 2024-06-20 20:37:21 +02:00
parent 2c4b368176
commit 4998ca5554

View File

@ -1733,8 +1733,8 @@ ea_lookup_slow(ea_list *o, u32 squash_upto, enum ea_stored oid)
return r->l; return r->l;
} }
#define EA_UC_SUB (1ULL << 56) #define EA_UC_SUB (1ULL << 44)
#define EA_UC_IN_PROGRESS(x) ((x) >> 56) #define EA_UC_IN_PROGRESS(x) ((x) >> 44)
#define EA_UC_ASSIGNED(x) ((x) & (EA_UC_SUB-1)) #define EA_UC_ASSIGNED(x) ((x) & (EA_UC_SUB-1))
#define EA_UC_DONE(x) (EA_UC_ASSIGNED(x) == EA_UC_IN_PROGRESS(x)) #define EA_UC_DONE(x) (EA_UC_ASSIGNED(x) == EA_UC_IN_PROGRESS(x))
@ -1744,11 +1744,8 @@ ea_free_deferred(struct deferred_call *dc)
{ {
struct ea_storage *r = ea_get_storage(SKIP_BACK(struct ea_free_deferred, dc, dc)->attrs); struct ea_storage *r = ea_get_storage(SKIP_BACK(struct ea_free_deferred, dc, dc)->attrs);
/* Wait until the previous free has ended */ /* Indicate free intent */
u64 prev; u64 prev = atomic_fetch_add_explicit(&r->uc, EA_UC_SUB, memory_order_acq_rel);
do prev = atomic_fetch_or_explicit(&r->uc, EA_UC_SUB, memory_order_acq_rel);
while (prev & EA_UC_SUB);
prev |= EA_UC_SUB; prev |= EA_UC_SUB;
if (!EA_UC_DONE(prev)) if (!EA_UC_DONE(prev))
@ -1759,6 +1756,18 @@ ea_free_deferred(struct deferred_call *dc)
return; return;
} }
/* Wait for others to finish */
while (EA_UC_DONE(prev) && (EA_UC_IN_PROGRESS(prev) > 1))
prev = atomic_load_explicit(&r->uc, memory_order_acquire);
if (!EA_UC_DONE(prev))
{
/* Somebody else has found us inbetween, no need to free */
ASSERT_DIE(EA_UC_IN_PROGRESS(prev) < EA_UC_ASSIGNED(prev));
atomic_fetch_sub_explicit(&r->uc, EA_UC_SUB + 1, memory_order_acq_rel);
return;
}
/* We are the last one to free this ea */ /* We are the last one to free this ea */
RTA_LOCK; RTA_LOCK;
@ -1767,16 +1776,16 @@ ea_free_deferred(struct deferred_call *dc)
/* Somebody has cloned this rta inbetween. This sometimes happens. */ /* Somebody has cloned this rta inbetween. This sometimes happens. */
prev = atomic_load_explicit(&r->uc, memory_order_acquire); prev = atomic_load_explicit(&r->uc, memory_order_acquire);
if (!EA_UC_DONE(prev)) if (!EA_UC_DONE(prev) || (EA_UC_IN_PROGRESS(prev) > 1))
{ {
/* Reinsert the ea */ /* Reinsert the ea and go away */
SPINHASH_INSERT(rta_hash_table, RTAH, r); SPINHASH_INSERT(rta_hash_table, RTAH, r);
atomic_fetch_sub_explicit(&r->uc, EA_UC_SUB + 1, memory_order_acq_rel); atomic_fetch_sub_explicit(&r->uc, EA_UC_SUB + 1, memory_order_acq_rel);
RTA_UNLOCK; RTA_UNLOCK;
return; return;
} }
/* Fine, wait until everybody is actually done */ /* Fine, now everybody is actually done */
ASSERT_DIE(atomic_load_explicit(&r->uc, memory_order_acquire) == EA_UC_SUB + 1); ASSERT_DIE(atomic_load_explicit(&r->uc, memory_order_acquire) == EA_UC_SUB + 1);
/* And now we can free the object, finally */ /* And now we can free the object, finally */