]> 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>
Thu, 26 Jan 2023 12:22:28 +0000 (13:22 +0100)
Instead of calling custom hooks from object locks, we use standard event
sending mechanism to inform protocols about object lock changes. This is
a backport from version 3 where these events are passed across threads.

This implementation of object locks doesn't use mutexes to lock the
whole data structure. In version 3, this data structure may get accessed
from multiple threads and must be protected by mutex.

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..e378fb1fd07196bdf986a1c3bd45e00eec39bf63 100644 (file)
@@ -37,7 +37,6 @@
 #include "nest/iface.h"
 
 static list olock_list;
-static event *olock_event;
 
 static inline int
 olock_same(struct object_lock *x, struct object_lock *y)
@@ -54,7 +53,8 @@ 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;
 
   DBG("olock: Freeing %p\n", l);
@@ -63,21 +63,35 @@ olock_free(resource *r)
     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_schedule(&q->event);
        }
       break;
     case OLOCK_STATE_WAITING:
+      /* Remove from the waiters list */
       rem_node(&l->n);
       break;
     default:
@@ -148,36 +162,16 @@ olock_acquire(struct object_lock *l)
          l->state = OLOCK_STATE_WAITING;
          add_tail(&q->waiters, &l->n);
          DBG("olock: %p waits\n", l);
+
          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;
-
-  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);
-    }
+  l->state = OLOCK_STATE_LOCKED;
+  ev_schedule(&l->event);
 }
 
 /**
@@ -191,5 +185,4 @@ olock_init(void)
 {
   DBG("olock: init\n");
   init_list(&olock_list);
-  olock_event = ev_new_init(&root_pool, olock_run_event, NULL);
 }
index 37026c68c1a7dd82df8b3e9f3708d5d4ec96489e..0cb33db9a35e2d85fa93dad0acba8feb148c448f 100644 (file)
@@ -31,8 +31,7 @@ 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 */
   /* ... internal to lock manager, don't touch ... */
   node n;              /* Node in list of olocks */
   int state;           /* OLOCK_STATE_xxx */
@@ -50,6 +49,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 ad7981f6087ca77728ceb5079c094f916c5a95be..e1b31e86346419efb81877905eb4548e7c08a035 100644 (file)
@@ -1762,9 +1762,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))
@@ -1819,8 +1819,10 @@ 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,
+  };
 
   olock_acquire(lock);
 }
index 2e442e16ad39693fa078c6237bffcd7187a2bf5a..5b0569ae0122a30c00316d103f340e8fd28593d1 100644 (file)
@@ -1467,9 +1467,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)
@@ -1574,8 +1574,10 @@ 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,
+  };
 
   /* For dynamic BGP, we use inst 1 to avoid collisions with regular BGP */
   if (bgp_is_dynamic(p))
index 84c53aa138440a1538c56035a22ae3b9c764cdeb..c7a6d3d4d630783728b978b9d20113247e86ed41 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,10 @@ 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,
+  };
 
   olock_acquire(lock);
 }
index 8b547f6d79b9419851decbc8d4a3adb145ff544e..ee1da36c55d7e9dfd21cbf5e97d2d256af167db3 100644 (file)
@@ -263,9 +263,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))
@@ -302,8 +302,10 @@ 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,
+  };
   ifa->lock = lock;
 
   olock_acquire(lock);
index ca21884630e0cd00535a2d5a32013b9b96bc6105..93b0d5280215b1ea3e7d3cf3353fccec686e40a7 100644 (file)
@@ -656,9 +656,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))
@@ -720,8 +720,10 @@ 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,
+  };
   ifa->lock = lock;
 
   olock_acquire(lock);