]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Object locks use events
authorMaria Matejka <mq@ucw.cz>
Tue, 24 Jan 2023 10:01:34 +0000 (11:01 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 24 Jan 2023 10:34:36 +0000 (11:34 +0100)
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.

nest/locks.c
nest/locks.h
proto/babel/babel.c
proto/bgp/bgp.c
proto/ospf/iface.c
proto/radv/radv.c
proto/rip/rip.c

index 812a65342268b9b97b3f19f1960c8e8b5e07377c..fb245cdcb43405aab21a6b95d360c26051c15108 100644 (file)
 #include "nest/iface.h"
 
 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
 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
 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;
 
+  OBJ_LOCK;
   DBG("olock: Freeing %p\n", l);
   switch (l->state)
     {
     case OLOCK_STATE_FREE:
       break;
     case OLOCK_STATE_LOCKED:
-    case OLOCK_STATE_EVENT:
+      /* Remove myself from the olock_list */
       rem_node(&l->n);
+
+      /* Maybe the notification is still pending. */
+      ev_postpone(&l->event);
+
+      /* Get new lock candidate */
       n = HEAD(l->waiters);
-      if (n->next)
+      if (NODE_VALID(n))
        {
-         DBG("olock: -> %p becomes locked\n", n);
-         q = SKIP_BACK(struct object_lock, n, n);
+         struct object_lock *q = SKIP_BACK(struct object_lock, n, n);
+
+         /* Remove this candidate from waiters list */
          rem_node(n);
+
+         /* Move waiter lists */
+         DBG("olock: -> %p becomes locked\n", n);
          add_tail_list(&q->waiters, &l->waiters);
-         q->state = OLOCK_STATE_EVENT;
+
+         /* Add the new olock to olock_list */
          add_head(&olock_list, n);
-         ev_schedule(olock_event);
+
+         /* Inform */
+         q->state = OLOCK_STATE_LOCKED;
+         ev_send(q->target, &q->event);
        }
       break;
     case OLOCK_STATE_WAITING:
+      /* Remove from the waiters list */
       rem_node(&l->n);
       break;
     default:
       ASSERT(0);
     }
+  OBJ_UNLOCK;
 }
 
 static void
@@ -140,6 +161,8 @@ olock_acquire(struct object_lock *l)
   node *n;
   struct object_lock *q;
 
+  OBJ_LOCK;
+
   WALK_LIST(n, olock_list)
     {
       q = SKIP_BACK(struct object_lock, n, n);
@@ -148,36 +171,19 @@ olock_acquire(struct object_lock *l)
          l->state = OLOCK_STATE_WAITING;
          add_tail(&q->waiters, &l->n);
          DBG("olock: %p waits\n", l);
+
+         OBJ_UNLOCK;
          return;
        }
     }
+
   DBG("olock: %p acquired immediately\n", l);
-  l->state = OLOCK_STATE_EVENT;
   add_head(&olock_list, &l->n);
-  ev_schedule(olock_event);
-}
 
-static void
-olock_run_event(void *unused UNUSED)
-{
-  node *n;
-  struct object_lock *q;
+  l->state = OLOCK_STATE_LOCKED;
+  ev_send(l->target, &l->event);
 
-  DBG("olock: Processing events\n");
-  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);
-    }
+  OBJ_UNLOCK;
 }
 
 /**
@@ -191,5 +197,5 @@ olock_init(void)
 {
   DBG("olock: init\n");
   init_list(&olock_list);
-  olock_event = ev_new_init(&root_pool, olock_run_event, NULL);
+  olock_domain = DOMAIN_NEW(attrs, "Object lock");
 }
index 37026c68c1a7dd82df8b3e9f3708d5d4ec96489e..04571e69ed8948220c8712e748e4f6876603451a 100644 (file)
@@ -31,8 +31,8 @@ struct object_lock {
   uint inst;           /* ... instance ID */
   struct iface *iface; /* ... interface */
   struct iface *vrf;   /* ... or VRF (if iface is unknown) */
-  void (*hook)(struct object_lock *);  /* Called when the lock succeeds */
-  void *data;          /* User data */
+  event event;         /* Enqueued when the lock succeeds */
+  event_list *target;  /* Where to put the event */
   /* ... internal to lock manager, don't touch ... */
   node n;              /* Node in list of olocks */
   int state;           /* OLOCK_STATE_xxx */
@@ -50,6 +50,5 @@ void olock_init(void);
 #define OLOCK_STATE_FREE 0
 #define OLOCK_STATE_LOCKED 1
 #define OLOCK_STATE_WAITING 2
-#define OLOCK_STATE_EVENT 3            /* waiting for unlock processing */
 
 #endif
index a3a52f73715537a9929b5775e8baaeaeb413822c..4db7c66f0874fde0d89a2a0e07f376e985f97a36 100644 (file)
@@ -1761,9 +1761,9 @@ babel_find_iface(struct babel_proto *p, struct iface *what)
 }
 
 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;
 
   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->port = ifa->cf->port;
   lock->iface = ifa->iface;
-  lock->hook = babel_iface_locked;
-  lock->data = ifa;
+  lock->event = (event) {
+    .hook = babel_iface_locked,
+    .data = ifa,
+  };
+  lock->target = &global_event_list;
 
   olock_acquire(lock);
 }
index 48e98bdfa317d608efd7858049ad4527e34b66fa..c74b827358c738041f28a257f0108d78cc47cc5c 100644 (file)
@@ -1528,9 +1528,9 @@ bgp_feed_end(struct channel *C)
 
 
 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;
 
   if (p->p.proto_state != PS_START)
@@ -1637,8 +1637,11 @@ bgp_start(struct proto *P)
   lock->iface = p->cf->iface;
   lock->vrf = p->cf->iface ? NULL : p->p.vrf;
   lock->type = OBJLOCK_TCP;
-  lock->hook = bgp_start_locked;
-  lock->data = p;
+  lock->event = (event) {
+    .hook = bgp_start_locked,
+    .data = p,
+  };
+  lock->target = &global_event_list;
 
   /* For dynamic BGP, we use inst 1 to avoid collisions with regular BGP */
   if (bgp_is_dynamic(p))
index 84c53aa138440a1538c56035a22ae3b9c764cdeb..59255350860affd468cb593d1bfacbaa61e3e3a6 100644 (file)
@@ -484,9 +484,9 @@ ospf_iface_find(struct ospf_proto *p, struct iface *what)
 }
 
 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;
 
   /* 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->inst = ifa->instance_id;
   lock->iface = iface;
-  lock->data = ifa;
-  lock->hook = ospf_iface_add;
+  lock->event = (event) {
+    .hook = ospf_iface_add,
+    .data = ifa,
+  };
+  lock->target = &global_event_list;
 
   olock_acquire(lock);
 }
index 8929e8ef821b0d9fa38ffde822e977301aba374b..b7c8d7be950afe87dbd322f4c84b4a925ac0e1a6 100644 (file)
@@ -266,9 +266,9 @@ radv_iface_find(struct radv_proto *p, struct iface *what)
 }
 
 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;
 
   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->port = ICMPV6_PROTO;
   lock->iface = iface;
-  lock->data = ifa;
-  lock->hook = radv_iface_add;
+  lock->event = (event) {
+    .hook = radv_iface_add,
+    .data = ifa,
+  };
+  lock->target = &global_event_list;
   ifa->lock = lock;
 
   olock_acquire(lock);
index bd087246bb37bdcfa526dd561bd729ba4df86ee2..b3a4e81e15a7fb55615ed069a4fd7c124a56763d 100644 (file)
@@ -667,9 +667,9 @@ rip_iface_update_bfd(struct rip_iface *ifa)
 
 
 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;
 
   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->port = ic->port;
   lock->iface = iface;
-  lock->data = ifa;
-  lock->hook = rip_iface_locked;
+  lock->event = (event) {
+    .hook = rip_iface_locked,
+    .data = ifa,
+  };
+  lock->target = &global_event_list;
   ifa->lock = lock;
 
   olock_acquire(lock);