mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
TMP: lockfree usecount and spinhash use callbacks
This commit is contained in:
parent
83045e9a1f
commit
6223c4066c
18
lib/hash.h
18
lib/hash.h
@ -218,8 +218,7 @@ struct { \
|
|||||||
uint cur_order, new_order; \
|
uint cur_order, new_order; \
|
||||||
struct { type *data; rw_spinlock lock; } *cur, *new; \
|
struct { type *data; rw_spinlock lock; } *cur, *new; \
|
||||||
pool *pool; \
|
pool *pool; \
|
||||||
event rehash; \
|
callback rehash; \
|
||||||
event_list *target; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPINHASH_INIT(v,id,_pool,_target) \
|
#define SPINHASH_INIT(v,id,_pool,_target) \
|
||||||
@ -230,19 +229,18 @@ struct { \
|
|||||||
(v).cur = mb_allocz(_pool, (1U << id##_ORDER) * sizeof *(v).cur); \
|
(v).cur = mb_allocz(_pool, (1U << id##_ORDER) * sizeof *(v).cur); \
|
||||||
(v).new = NULL; \
|
(v).new = NULL; \
|
||||||
(v).pool = _pool; \
|
(v).pool = _pool; \
|
||||||
(v).rehash = (event) { .hook = id##_REHASH, .data = &(v), }; \
|
if (_target) callback_init(&(v).rehash, id##_REHASH, _target); \
|
||||||
(v).target = _target; \
|
|
||||||
})
|
})
|
||||||
|
|
||||||
#define SPINHASH_FREE(v) \
|
#define SPINHASH_FREE(v) \
|
||||||
({ \
|
({ \
|
||||||
ev_postpone(&(v).rehash); \
|
callback_cancel(&(v).rehash); \
|
||||||
mb_free((v).cur); \
|
mb_free((v).cur); \
|
||||||
ASSERT_DIE((v).new == NULL); \
|
ASSERT_DIE((v).new == NULL); \
|
||||||
(v).cur = NULL; \
|
(v).cur = NULL; \
|
||||||
(v).cur_order = 0; \
|
(v).cur_order = 0; \
|
||||||
(v).pool = NULL; \
|
(v).pool = NULL; \
|
||||||
(v).target = NULL; \
|
(v).rehash = (callback) {}; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define SPINHASH_BEGIN_CHAIN(v,id,rw,n,key...) \
|
#define SPINHASH_BEGIN_CHAIN(v,id,rw,n,key...) \
|
||||||
@ -367,12 +365,12 @@ struct { \
|
|||||||
})
|
})
|
||||||
|
|
||||||
#define SPINHASH_REQUEST_REHASH(v,id,count) \
|
#define SPINHASH_REQUEST_REHASH(v,id,count) \
|
||||||
if (SPINHASH_CHECK_REHASH(v,id,count) && (v).target) \
|
if ((v).rehash.target && SPINHASH_CHECK_REHASH(v,id,count)) \
|
||||||
ev_send((v).target, &(v).rehash);
|
callback_activate(&(v).rehash); \
|
||||||
|
|
||||||
#define SPINHASH_DEFINE_REHASH_FN(id,type) \
|
#define SPINHASH_DEFINE_REHASH_FN(id,type) \
|
||||||
static void id##_REHASH(void *_v) { \
|
static void id##_REHASH(callback *cb) { \
|
||||||
SPINHASH(type) *v = _v; \
|
SKIP_BACK_DECLARE(SPINHASH(type), v, rehash, cb); \
|
||||||
SPINHASH_REHASH_FN_BODY(v,id,type); \
|
SPINHASH_REHASH_FN_BODY(v,id,type); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
void lfuc_unlock_deferred(struct deferred_call *dc)
|
void lfuc_unlock_deferred(struct deferred_call *dc)
|
||||||
{
|
{
|
||||||
SKIP_BACK_DECLARE(struct lfuc_unlock_queue_item, luqi, dc, dc);
|
SKIP_BACK_DECLARE(struct lfuc_unlock_queue_item, luqi, dc, dc);
|
||||||
lfuc_unlock_immediately(luqi->c, luqi->el, luqi->ev);
|
lfuc_unlock_immediately(luqi->c, luqi->cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -67,7 +67,7 @@ static inline u64 lfuc_lock_revive(struct lfuc *c)
|
|||||||
* If the usecount reaches zero, a prune event is run to possibly free the object.
|
* If the usecount reaches zero, a prune event is run to possibly free the object.
|
||||||
* The prune event MUST use lfuc_finished() to check the object state.
|
* The prune event MUST use lfuc_finished() to check the object state.
|
||||||
*/
|
*/
|
||||||
static inline void lfuc_unlock_immediately(struct lfuc *c, event_list *el, event *ev)
|
static inline void lfuc_unlock_immediately(struct lfuc *c, struct callback *cb)
|
||||||
{
|
{
|
||||||
/* Unlocking is tricky. We do it lockless so at the same time, the prune
|
/* Unlocking is tricky. We do it lockless so at the same time, the prune
|
||||||
* event may be running, therefore if the unlock gets us to zero, it must be
|
* event may be running, therefore if the unlock gets us to zero, it must be
|
||||||
@ -98,7 +98,7 @@ static inline void lfuc_unlock_immediately(struct lfuc *c, event_list *el, event
|
|||||||
if (uc == pending)
|
if (uc == pending)
|
||||||
/* If we're the last unlocker (every owner is already unlocking), schedule
|
/* If we're the last unlocker (every owner is already unlocking), schedule
|
||||||
* the owner's prune event */
|
* the owner's prune event */
|
||||||
ev_send(el, ev);
|
callback_activate(cb);
|
||||||
else
|
else
|
||||||
ASSERT_DIE(uc > pending);
|
ASSERT_DIE(uc > pending);
|
||||||
|
|
||||||
@ -112,19 +112,17 @@ static inline void lfuc_unlock_immediately(struct lfuc *c, event_list *el, event
|
|||||||
struct lfuc_unlock_queue_item {
|
struct lfuc_unlock_queue_item {
|
||||||
struct deferred_call dc;
|
struct deferred_call dc;
|
||||||
struct lfuc *c;
|
struct lfuc *c;
|
||||||
event_list *el;
|
struct callback *cb;
|
||||||
event *ev;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void lfuc_unlock_deferred(struct deferred_call *dc);
|
void lfuc_unlock_deferred(struct deferred_call *dc);
|
||||||
|
|
||||||
static inline void lfuc_unlock(struct lfuc *c, event_list *el, event *ev)
|
static inline void lfuc_unlock(struct lfuc *c, struct callback *cb)
|
||||||
{
|
{
|
||||||
struct lfuc_unlock_queue_item luqi = {
|
struct lfuc_unlock_queue_item luqi = {
|
||||||
.dc.hook = lfuc_unlock_deferred,
|
.dc.hook = lfuc_unlock_deferred,
|
||||||
.c = c,
|
.c = c,
|
||||||
.el = el,
|
.cb = cb,
|
||||||
.ev = ev,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
defer_call(&luqi.dc, sizeof luqi);
|
defer_call(&luqi.dc, sizeof luqi);
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
#define NETINDEX_REHASH netindex_rehash
|
#define NETINDEX_REHASH netindex_rehash
|
||||||
#define NETINDEX_PARAMS /8, *2, 2, 2, 12, 28
|
#define NETINDEX_PARAMS /8, *2, 2, 2, 12, 28
|
||||||
|
|
||||||
static void NETINDEX_REHASH(void *_v) {
|
static void NETINDEX_REHASH(callback *cb) {
|
||||||
log(L_TRACE "Netindex rehash: begin");
|
log(L_TRACE "Netindex rehash: begin");
|
||||||
netindex_spinhash *v = _v;
|
SKIP_BACK_DECLARE(netindex_spinhash, v, rehash, cb);
|
||||||
int step;
|
int step;
|
||||||
{
|
{
|
||||||
NH_LOCK(SKIP_BACK(netindex_hash, hash, v), _);
|
NH_LOCK(SKIP_BACK(netindex_hash, hash, v), _);
|
||||||
@ -43,7 +43,7 @@ static void NETINDEX_REHASH(void *_v) {
|
|||||||
log(L_TRACE "Netindex rehash: done");
|
log(L_TRACE "Netindex rehash: done");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netindex_hash_cleanup(void *netindex_hash);
|
static void netindex_hash_cleanup(callback *cb);
|
||||||
|
|
||||||
static struct netindex *
|
static struct netindex *
|
||||||
net_lock_revive_unlock(netindex_hash *h, struct netindex *i)
|
net_lock_revive_unlock(netindex_hash *h, struct netindex *i)
|
||||||
@ -52,7 +52,7 @@ net_lock_revive_unlock(netindex_hash *h, struct netindex *i)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
lfuc_lock_revive(&i->uc);
|
lfuc_lock_revive(&i->uc);
|
||||||
lfuc_unlock(&i->uc, h->cleanup_list, &h->cleanup_event);
|
lfuc_unlock(&i->uc, &h->cleanup);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ net_lock_revive_unlock(netindex_hash *h, struct netindex *i)
|
|||||||
* Index initialization
|
* Index initialization
|
||||||
*/
|
*/
|
||||||
netindex_hash *
|
netindex_hash *
|
||||||
netindex_hash_new(pool *sp, event_list *cleanup_target, u8 type)
|
netindex_hash_new(pool *sp, struct birdloop *cleanup_target, u8 type)
|
||||||
{
|
{
|
||||||
DOMAIN(attrs) dom = DOMAIN_NEW_RCU_SYNC(attrs);
|
DOMAIN(attrs) dom = DOMAIN_NEW_RCU_SYNC(attrs);
|
||||||
LOCK_DOMAIN(attrs, dom);
|
LOCK_DOMAIN(attrs, dom);
|
||||||
@ -82,8 +82,7 @@ netindex_hash_new(pool *sp, event_list *cleanup_target, u8 type)
|
|||||||
|
|
||||||
hmap_init(&nh->id_map, nh->pool, 128);
|
hmap_init(&nh->id_map, nh->pool, 128);
|
||||||
|
|
||||||
nh->cleanup_list = cleanup_target;
|
callback_init(&nh->cleanup, netindex_hash_cleanup, cleanup_target);
|
||||||
nh->cleanup_event = (event) { .hook = netindex_hash_cleanup, nh };
|
|
||||||
|
|
||||||
UNLOCK_DOMAIN(attrs, dom);
|
UNLOCK_DOMAIN(attrs, dom);
|
||||||
return SKIP_BACK(netindex_hash, priv, nh);
|
return SKIP_BACK(netindex_hash, priv, nh);
|
||||||
@ -123,9 +122,9 @@ netindex_hash_cleanup_removed(struct netindex_hash_private *nh, struct netindex
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netindex_hash_cleanup(void *_nh)
|
netindex_hash_cleanup(callback *cb)
|
||||||
{
|
{
|
||||||
struct netindex_hash_private *nh = _nh;
|
SKIP_BACK_DECLARE(struct netindex_hash_private, nh, cleanup, cb);
|
||||||
|
|
||||||
DOMAIN(attrs) dom = nh->lock;
|
DOMAIN(attrs) dom = nh->lock;
|
||||||
LOCK_DOMAIN(attrs, dom);
|
LOCK_DOMAIN(attrs, dom);
|
||||||
@ -176,16 +175,16 @@ netindex_hash_cleanup(void *_nh)
|
|||||||
kept += netindex_hash_cleanup_removed(nh, block, removed, removed_cnt);
|
kept += netindex_hash_cleanup_removed(nh, block, removed, removed_cnt);
|
||||||
|
|
||||||
/* Return now unless we're deleted */
|
/* Return now unless we're deleted */
|
||||||
if (kept || !nh->deleted_event)
|
if (kept || !nh->deleted)
|
||||||
{
|
{
|
||||||
UNLOCK_DOMAIN(attrs, dom);
|
UNLOCK_DOMAIN(attrs, dom);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ev_postpone(&nh->cleanup_event);
|
callback_cancel(&nh->cleanup);
|
||||||
|
|
||||||
event *e = nh->deleted_event;
|
/* Store the callback */
|
||||||
event_list *t = nh->deleted_target;
|
callback *cd = nh->deleted;
|
||||||
|
|
||||||
/* Check cleanliness */
|
/* Check cleanliness */
|
||||||
SPINHASH_WALK(nh->hash, NETINDEX, i)
|
SPINHASH_WALK(nh->hash, NETINDEX, i)
|
||||||
@ -203,18 +202,16 @@ netindex_hash_cleanup(void *_nh)
|
|||||||
DOMAIN_FREE(attrs, dom);
|
DOMAIN_FREE(attrs, dom);
|
||||||
|
|
||||||
/* Notify the requestor */
|
/* Notify the requestor */
|
||||||
ev_send(t, e);
|
callback_activate(cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
netindex_hash_delete(netindex_hash *h, event *e, event_list *t)
|
netindex_hash_delete(netindex_hash *h, callback *cb)
|
||||||
{
|
{
|
||||||
NH_LOCK(h, hp);
|
NH_LOCK(h, hp);
|
||||||
|
|
||||||
hp->deleted_event = e;
|
hp->deleted = cb;
|
||||||
hp->deleted_target = t;
|
callback_activate(&hp->cleanup);
|
||||||
|
|
||||||
ev_send(hp->cleanup_list, &hp->cleanup_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -243,7 +240,7 @@ net_validate_index(netindex_hash *h, struct netindex *ni)
|
|||||||
static struct netindex *
|
static struct netindex *
|
||||||
net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n)
|
net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n)
|
||||||
{
|
{
|
||||||
ASSERT_DIE(!hp->deleted_event);
|
ASSERT_DIE(!hp->deleted);
|
||||||
|
|
||||||
u32 i = hmap_first_zero(&hp->id_map);
|
u32 i = hmap_first_zero(&hp->id_map);
|
||||||
hmap_set(&hp->id_map, i);
|
hmap_set(&hp->id_map, i);
|
||||||
@ -302,7 +299,7 @@ void net_lock_index(netindex_hash *h UNUSED, struct netindex *i)
|
|||||||
void net_unlock_index(netindex_hash *h, struct netindex *i)
|
void net_unlock_index(netindex_hash *h, struct netindex *i)
|
||||||
{
|
{
|
||||||
// log(L_TRACE "Unlock index %p", i);
|
// log(L_TRACE "Unlock index %p", i);
|
||||||
lfuc_unlock(&i->uc, h->cleanup_list, &h->cleanup_event);
|
lfuc_unlock(&i->uc, &h->cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct netindex *
|
struct netindex *
|
||||||
|
@ -28,8 +28,8 @@ struct netindex {
|
|||||||
typedef union netindex_hash netindex_hash;
|
typedef union netindex_hash netindex_hash;
|
||||||
|
|
||||||
/* Initialization and teardown */
|
/* Initialization and teardown */
|
||||||
netindex_hash *netindex_hash_new(pool *, event_list *, u8);
|
netindex_hash *netindex_hash_new(pool *, struct birdloop *, u8);
|
||||||
void netindex_hash_delete(netindex_hash *, event *, event_list *);
|
void netindex_hash_delete(netindex_hash *, callback *);
|
||||||
|
|
||||||
/* Find/get/resolve index; pointer valid until end of task */
|
/* Find/get/resolve index; pointer valid until end of task */
|
||||||
struct netindex *net_find_index(netindex_hash *, const net_addr *);
|
struct netindex *net_find_index(netindex_hash *, const net_addr *);
|
||||||
|
@ -15,8 +15,7 @@ typedef SPINHASH(struct netindex) netindex_spinhash;
|
|||||||
|
|
||||||
#define NETINDEX_HASH_PUBLIC \
|
#define NETINDEX_HASH_PUBLIC \
|
||||||
DOMAIN(attrs) lock; /* Assigned lock */ \
|
DOMAIN(attrs) lock; /* Assigned lock */ \
|
||||||
event_list *cleanup_list; /* Cleanup event list */ \
|
callback cleanup; /* Usecount cleanup */ \
|
||||||
event cleanup_event; /* Cleanup event */ \
|
|
||||||
u8 net_type; /* Which NET_* is stored */ \
|
u8 net_type; /* Which NET_* is stored */ \
|
||||||
uint _Atomic block_size; /* How big block is */ \
|
uint _Atomic block_size; /* How big block is */ \
|
||||||
struct netindex * _Atomic * _Atomic block; /* u32 to netindex */ \
|
struct netindex * _Atomic * _Atomic block; /* u32 to netindex */ \
|
||||||
@ -29,8 +28,7 @@ struct netindex_hash_private {
|
|||||||
slab *slab;
|
slab *slab;
|
||||||
struct hmap id_map;
|
struct hmap id_map;
|
||||||
u32 block_epoch;
|
u32 block_epoch;
|
||||||
event *deleted_event;
|
callback *deleted;
|
||||||
event_list *deleted_target;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union netindex_hash {
|
typedef union netindex_hash {
|
||||||
|
@ -87,8 +87,7 @@ struct rte_owner {
|
|||||||
u32 hash_key;
|
u32 hash_key;
|
||||||
u32 uc;
|
u32 uc;
|
||||||
u32 debug;
|
u32 debug;
|
||||||
event_list *list;
|
struct callback *prune_callback;
|
||||||
event *prune;
|
|
||||||
event *stop;
|
event *stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ static inline void rt_lock_source(struct rte_src *src)
|
|||||||
|
|
||||||
static inline void rt_unlock_source(struct rte_src *src)
|
static inline void rt_unlock_source(struct rte_src *src)
|
||||||
{
|
{
|
||||||
lfuc_unlock(&src->uc, src->owner->list, src->owner->prune);
|
lfuc_unlock(&src->uc, src->owner->prune_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RT_SOURCE_DEBUG
|
#ifdef RT_SOURCE_DEBUG
|
||||||
|
15
nest/mpls.c
15
nest/mpls.c
@ -93,7 +93,7 @@ static void mpls_remove_range(struct mpls_range *r);
|
|||||||
static void mpls_cleanup_ranges(void *_domain);
|
static void mpls_cleanup_ranges(void *_domain);
|
||||||
|
|
||||||
static void mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
|
static void mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
|
||||||
static void mpls_fec_map_cleanup(void *_m);
|
static void mpls_fec_map_cleanup(callback *cb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MPLS domain
|
* MPLS domain
|
||||||
@ -659,7 +659,7 @@ mpls_channel_shutdown(struct channel *C)
|
|||||||
if (!c->rts)
|
if (!c->rts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ev_send_loop(c->mpls_map->loop, c->mpls_map->cleanup_event);
|
callback_activate(&c->mpls_map->cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -792,8 +792,7 @@ mpls_fec_map_new(pool *pp, struct birdloop *loop, struct channel *C, uint rts)
|
|||||||
DBGL("New FEC Map %p", m);
|
DBGL("New FEC Map %p", m);
|
||||||
|
|
||||||
m->pool = p;
|
m->pool = p;
|
||||||
m->loop = loop;
|
callback_init(&m->cleanup, mpls_fec_map_cleanup, loop);
|
||||||
m->cleanup_event = ev_new_init(p, mpls_fec_map_cleanup, m);
|
|
||||||
m->channel = C;
|
m->channel = C;
|
||||||
channel_add_obstacle(C);
|
channel_add_obstacle(C);
|
||||||
|
|
||||||
@ -881,9 +880,9 @@ mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mpls_fec_map_cleanup(void *_m)
|
mpls_fec_map_cleanup(callback *cb)
|
||||||
{
|
{
|
||||||
struct mpls_fec_map *m = _m;
|
SKIP_BACK_DECLARE(struct mpls_fec_map, m, cleanup, cb);
|
||||||
_Bool finished = (m->channel->channel_state == CS_STOP);
|
_Bool finished = (m->channel->channel_state == CS_STOP);
|
||||||
HASH_WALK_DELSAFE(m->label_hash, next_l, fec)
|
HASH_WALK_DELSAFE(m->label_hash, next_l, fec)
|
||||||
if (lfuc_finished(&fec->uc))
|
if (lfuc_finished(&fec->uc))
|
||||||
@ -896,7 +895,7 @@ mpls_fec_map_cleanup(void *_m)
|
|||||||
|
|
||||||
if (finished)
|
if (finished)
|
||||||
{
|
{
|
||||||
ev_postpone(m->cleanup_event);
|
callback_cancel(&m->cleanup);
|
||||||
channel_del_obstacle(m->channel);
|
channel_del_obstacle(m->channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1193,7 +1192,7 @@ inline void mpls_lock_fec(struct mpls_fec *fec)
|
|||||||
|
|
||||||
inline void mpls_unlock_fec(struct mpls_fec *fec)
|
inline void mpls_unlock_fec(struct mpls_fec *fec)
|
||||||
{
|
{
|
||||||
lfuc_unlock(&fec->uc, birdloop_event_list(fec->map->loop), fec->map->cleanup_event);
|
lfuc_unlock(&fec->uc, &fec->map->cleanup);
|
||||||
DBGL("Unlocked FEC %p %u (deferred)", fec, fec->label);
|
DBGL("Unlocked FEC %p %u (deferred)", fec, fec->label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +124,7 @@ struct mpls_fec {
|
|||||||
|
|
||||||
struct mpls_fec_map {
|
struct mpls_fec_map {
|
||||||
pool *pool; /* Pool for FEC map */
|
pool *pool; /* Pool for FEC map */
|
||||||
struct birdloop *loop; /* Owner's loop for sending events */
|
callback cleanup; /* Callback for unlocked FEC cleanup */
|
||||||
event *cleanup_event; /* Event for unlocked FEC cleanup */
|
|
||||||
slab *slabs[4]; /* Slabs for FEC allocation */
|
slab *slabs[4]; /* Slabs for FEC allocation */
|
||||||
HASH(struct mpls_fec) net_hash; /* Hash table for MPLS_POLICY_PREFIX FECs */
|
HASH(struct mpls_fec) net_hash; /* Hash table for MPLS_POLICY_PREFIX FECs */
|
||||||
HASH(struct mpls_fec) attrs_hash; /* Hash table for MPLS_POLICY_AGGREGATE FECs */
|
HASH(struct mpls_fec) attrs_hash; /* Hash table for MPLS_POLICY_AGGREGATE FECs */
|
||||||
|
Loading…
Reference in New Issue
Block a user