mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-13 22:58:42 +00:00
Object locks use events
Instead of calling custom hooks from object locks, we use standard event sending mechanism to inform protocols about object lock changes. As event sending is lockless, the unlocking protocol simply enqueues the appropriate event to the given loop when the locking is done.
This commit is contained in:
parent
3ac628e0f0
commit
f7c2a886c9
70
nest/locks.c
70
nest/locks.c
@ -37,7 +37,11 @@
|
|||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
|
|
||||||
static list olock_list;
|
static list olock_list;
|
||||||
static event *olock_event;
|
|
||||||
|
DEFINE_DOMAIN(attrs);
|
||||||
|
static DOMAIN(attrs) olock_domain;
|
||||||
|
#define OBJ_LOCK LOCK_DOMAIN(attrs, olock_domain)
|
||||||
|
#define OBJ_UNLOCK UNLOCK_DOMAIN(attrs, olock_domain)
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
olock_same(struct object_lock *x, struct object_lock *y)
|
olock_same(struct object_lock *x, struct object_lock *y)
|
||||||
@ -54,35 +58,52 @@ olock_same(struct object_lock *x, struct object_lock *y)
|
|||||||
static void
|
static void
|
||||||
olock_free(resource *r)
|
olock_free(resource *r)
|
||||||
{
|
{
|
||||||
struct object_lock *q, *l = (struct object_lock *) r;
|
/* Called externally from rfree() */
|
||||||
|
struct object_lock *l = SKIP_BACK(struct object_lock, r, r);
|
||||||
node *n;
|
node *n;
|
||||||
|
|
||||||
|
OBJ_LOCK;
|
||||||
DBG("olock: Freeing %p\n", l);
|
DBG("olock: Freeing %p\n", l);
|
||||||
switch (l->state)
|
switch (l->state)
|
||||||
{
|
{
|
||||||
case OLOCK_STATE_FREE:
|
case OLOCK_STATE_FREE:
|
||||||
break;
|
break;
|
||||||
case OLOCK_STATE_LOCKED:
|
case OLOCK_STATE_LOCKED:
|
||||||
case OLOCK_STATE_EVENT:
|
/* Remove myself from the olock_list */
|
||||||
rem_node(&l->n);
|
rem_node(&l->n);
|
||||||
|
|
||||||
|
/* Maybe the notification is still pending. */
|
||||||
|
ev_postpone(&l->event);
|
||||||
|
|
||||||
|
/* Get new lock candidate */
|
||||||
n = HEAD(l->waiters);
|
n = HEAD(l->waiters);
|
||||||
if (n->next)
|
if (NODE_VALID(n))
|
||||||
{
|
{
|
||||||
DBG("olock: -> %p becomes locked\n", n);
|
struct object_lock *q = SKIP_BACK(struct object_lock, n, n);
|
||||||
q = SKIP_BACK(struct object_lock, n, n);
|
|
||||||
|
/* Remove this candidate from waiters list */
|
||||||
rem_node(n);
|
rem_node(n);
|
||||||
|
|
||||||
|
/* Move waiter lists */
|
||||||
|
DBG("olock: -> %p becomes locked\n", n);
|
||||||
add_tail_list(&q->waiters, &l->waiters);
|
add_tail_list(&q->waiters, &l->waiters);
|
||||||
q->state = OLOCK_STATE_EVENT;
|
|
||||||
|
/* Add the new olock to olock_list */
|
||||||
add_head(&olock_list, n);
|
add_head(&olock_list, n);
|
||||||
ev_schedule(olock_event);
|
|
||||||
|
/* Inform */
|
||||||
|
q->state = OLOCK_STATE_LOCKED;
|
||||||
|
ev_send(q->target, &q->event);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OLOCK_STATE_WAITING:
|
case OLOCK_STATE_WAITING:
|
||||||
|
/* Remove from the waiters list */
|
||||||
rem_node(&l->n);
|
rem_node(&l->n);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
|
OBJ_UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -140,6 +161,8 @@ olock_acquire(struct object_lock *l)
|
|||||||
node *n;
|
node *n;
|
||||||
struct object_lock *q;
|
struct object_lock *q;
|
||||||
|
|
||||||
|
OBJ_LOCK;
|
||||||
|
|
||||||
WALK_LIST(n, olock_list)
|
WALK_LIST(n, olock_list)
|
||||||
{
|
{
|
||||||
q = SKIP_BACK(struct object_lock, n, n);
|
q = SKIP_BACK(struct object_lock, n, n);
|
||||||
@ -148,36 +171,19 @@ olock_acquire(struct object_lock *l)
|
|||||||
l->state = OLOCK_STATE_WAITING;
|
l->state = OLOCK_STATE_WAITING;
|
||||||
add_tail(&q->waiters, &l->n);
|
add_tail(&q->waiters, &l->n);
|
||||||
DBG("olock: %p waits\n", l);
|
DBG("olock: %p waits\n", l);
|
||||||
|
|
||||||
|
OBJ_UNLOCK;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG("olock: %p acquired immediately\n", l);
|
DBG("olock: %p acquired immediately\n", l);
|
||||||
l->state = OLOCK_STATE_EVENT;
|
|
||||||
add_head(&olock_list, &l->n);
|
add_head(&olock_list, &l->n);
|
||||||
ev_schedule(olock_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
l->state = OLOCK_STATE_LOCKED;
|
||||||
olock_run_event(void *unused UNUSED)
|
ev_send(l->target, &l->event);
|
||||||
{
|
|
||||||
node *n;
|
|
||||||
struct object_lock *q;
|
|
||||||
|
|
||||||
DBG("olock: Processing events\n");
|
OBJ_UNLOCK;
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
n = HEAD(olock_list);
|
|
||||||
if (!n->next)
|
|
||||||
break;
|
|
||||||
q = SKIP_BACK(struct object_lock, n, n);
|
|
||||||
if (q->state != OLOCK_STATE_EVENT)
|
|
||||||
break;
|
|
||||||
DBG("olock: %p locked\n", q);
|
|
||||||
q->state = OLOCK_STATE_LOCKED;
|
|
||||||
rem_node(&q->n);
|
|
||||||
add_tail(&olock_list, &q->n);
|
|
||||||
q->hook(q);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,5 +197,5 @@ olock_init(void)
|
|||||||
{
|
{
|
||||||
DBG("olock: init\n");
|
DBG("olock: init\n");
|
||||||
init_list(&olock_list);
|
init_list(&olock_list);
|
||||||
olock_event = ev_new_init(&root_pool, olock_run_event, NULL);
|
olock_domain = DOMAIN_NEW(attrs, "Object lock");
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ struct object_lock {
|
|||||||
uint inst; /* ... instance ID */
|
uint inst; /* ... instance ID */
|
||||||
struct iface *iface; /* ... interface */
|
struct iface *iface; /* ... interface */
|
||||||
struct iface *vrf; /* ... or VRF (if iface is unknown) */
|
struct iface *vrf; /* ... or VRF (if iface is unknown) */
|
||||||
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
event event; /* Enqueued when the lock succeeds */
|
||||||
void *data; /* User data */
|
event_list *target; /* Where to put the event */
|
||||||
/* ... internal to lock manager, don't touch ... */
|
/* ... internal to lock manager, don't touch ... */
|
||||||
node n; /* Node in list of olocks */
|
node n; /* Node in list of olocks */
|
||||||
int state; /* OLOCK_STATE_xxx */
|
int state; /* OLOCK_STATE_xxx */
|
||||||
@ -50,6 +50,5 @@ void olock_init(void);
|
|||||||
#define OLOCK_STATE_FREE 0
|
#define OLOCK_STATE_FREE 0
|
||||||
#define OLOCK_STATE_LOCKED 1
|
#define OLOCK_STATE_LOCKED 1
|
||||||
#define OLOCK_STATE_WAITING 2
|
#define OLOCK_STATE_WAITING 2
|
||||||
#define OLOCK_STATE_EVENT 3 /* waiting for unlock processing */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1761,9 +1761,9 @@ babel_find_iface(struct babel_proto *p, struct iface *what)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_iface_locked(struct object_lock *lock)
|
babel_iface_locked(void *_ifa)
|
||||||
{
|
{
|
||||||
struct babel_iface *ifa = lock->data;
|
struct babel_iface *ifa = _ifa;
|
||||||
struct babel_proto *p = ifa->proto;
|
struct babel_proto *p = ifa->proto;
|
||||||
|
|
||||||
if (!babel_open_socket(ifa))
|
if (!babel_open_socket(ifa))
|
||||||
@ -1818,8 +1818,11 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
|
|||||||
lock->addr = IP6_BABEL_ROUTERS;
|
lock->addr = IP6_BABEL_ROUTERS;
|
||||||
lock->port = ifa->cf->port;
|
lock->port = ifa->cf->port;
|
||||||
lock->iface = ifa->iface;
|
lock->iface = ifa->iface;
|
||||||
lock->hook = babel_iface_locked;
|
lock->event = (event) {
|
||||||
lock->data = ifa;
|
.hook = babel_iface_locked,
|
||||||
|
.data = ifa,
|
||||||
|
};
|
||||||
|
lock->target = &global_event_list;
|
||||||
|
|
||||||
olock_acquire(lock);
|
olock_acquire(lock);
|
||||||
}
|
}
|
||||||
|
@ -1528,9 +1528,9 @@ bgp_feed_end(struct channel *C)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_start_locked(struct object_lock *lock)
|
bgp_start_locked(void *_p)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = lock->data;
|
struct bgp_proto *p = _p;
|
||||||
const struct bgp_config *cf = p->cf;
|
const struct bgp_config *cf = p->cf;
|
||||||
|
|
||||||
if (p->p.proto_state != PS_START)
|
if (p->p.proto_state != PS_START)
|
||||||
@ -1637,8 +1637,11 @@ bgp_start(struct proto *P)
|
|||||||
lock->iface = p->cf->iface;
|
lock->iface = p->cf->iface;
|
||||||
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
|
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
|
||||||
lock->type = OBJLOCK_TCP;
|
lock->type = OBJLOCK_TCP;
|
||||||
lock->hook = bgp_start_locked;
|
lock->event = (event) {
|
||||||
lock->data = p;
|
.hook = bgp_start_locked,
|
||||||
|
.data = p,
|
||||||
|
};
|
||||||
|
lock->target = &global_event_list;
|
||||||
|
|
||||||
/* For dynamic BGP, we use inst 1 to avoid collisions with regular BGP */
|
/* For dynamic BGP, we use inst 1 to avoid collisions with regular BGP */
|
||||||
if (bgp_is_dynamic(p))
|
if (bgp_is_dynamic(p))
|
||||||
|
@ -484,9 +484,9 @@ ospf_iface_find(struct ospf_proto *p, struct iface *what)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_iface_add(struct object_lock *lock)
|
ospf_iface_add(void *_ifa)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa = lock->data;
|
struct ospf_iface *ifa = _ifa;
|
||||||
struct ospf_proto *p = ifa->oa->po;
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
|
|
||||||
/* Open socket if interface is not stub */
|
/* Open socket if interface is not stub */
|
||||||
@ -668,8 +668,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
|
|||||||
lock->port = OSPF_PROTO;
|
lock->port = OSPF_PROTO;
|
||||||
lock->inst = ifa->instance_id;
|
lock->inst = ifa->instance_id;
|
||||||
lock->iface = iface;
|
lock->iface = iface;
|
||||||
lock->data = ifa;
|
lock->event = (event) {
|
||||||
lock->hook = ospf_iface_add;
|
.hook = ospf_iface_add,
|
||||||
|
.data = ifa,
|
||||||
|
};
|
||||||
|
lock->target = &global_event_list;
|
||||||
|
|
||||||
olock_acquire(lock);
|
olock_acquire(lock);
|
||||||
}
|
}
|
||||||
|
@ -266,9 +266,9 @@ radv_iface_find(struct radv_proto *p, struct iface *what)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
radv_iface_add(struct object_lock *lock)
|
radv_iface_add(void *_ifa)
|
||||||
{
|
{
|
||||||
struct radv_iface *ifa = lock->data;
|
struct radv_iface *ifa = _ifa;
|
||||||
struct radv_proto *p = ifa->ra;
|
struct radv_proto *p = ifa->ra;
|
||||||
|
|
||||||
if (! radv_sk_open(ifa))
|
if (! radv_sk_open(ifa))
|
||||||
@ -305,8 +305,11 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf
|
|||||||
lock->type = OBJLOCK_IP;
|
lock->type = OBJLOCK_IP;
|
||||||
lock->port = ICMPV6_PROTO;
|
lock->port = ICMPV6_PROTO;
|
||||||
lock->iface = iface;
|
lock->iface = iface;
|
||||||
lock->data = ifa;
|
lock->event = (event) {
|
||||||
lock->hook = radv_iface_add;
|
.hook = radv_iface_add,
|
||||||
|
.data = ifa,
|
||||||
|
};
|
||||||
|
lock->target = &global_event_list;
|
||||||
ifa->lock = lock;
|
ifa->lock = lock;
|
||||||
|
|
||||||
olock_acquire(lock);
|
olock_acquire(lock);
|
||||||
|
@ -667,9 +667,9 @@ rip_iface_update_bfd(struct rip_iface *ifa)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rip_iface_locked(struct object_lock *lock)
|
rip_iface_locked(void *_ifa)
|
||||||
{
|
{
|
||||||
struct rip_iface *ifa = lock->data;
|
struct rip_iface *ifa = _ifa;
|
||||||
struct rip_proto *p = ifa->rip;
|
struct rip_proto *p = ifa->rip;
|
||||||
|
|
||||||
if (!rip_open_socket(ifa))
|
if (!rip_open_socket(ifa))
|
||||||
@ -731,8 +731,11 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
|
|||||||
lock->type = OBJLOCK_UDP;
|
lock->type = OBJLOCK_UDP;
|
||||||
lock->port = ic->port;
|
lock->port = ic->port;
|
||||||
lock->iface = iface;
|
lock->iface = iface;
|
||||||
lock->data = ifa;
|
lock->event = (event) {
|
||||||
lock->hook = rip_iface_locked;
|
.hook = rip_iface_locked,
|
||||||
|
.data = ifa,
|
||||||
|
};
|
||||||
|
lock->target = &global_event_list;
|
||||||
ifa->lock = lock;
|
ifa->lock = lock;
|
||||||
|
|
||||||
olock_acquire(lock);
|
olock_acquire(lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user