summaryrefslogtreecommitdiff
path: root/lib/qobj.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2017-05-08 06:07:52 +0200
committerQuentin Young <qlyoung@users.noreply.github.com>2017-05-18 14:07:28 -0400
commit297c8f6a31979637c43227902a8b71f87088e46b (patch)
tree8f858104fd0d96b3a3f2ef5738db589ea3c35dc2 /lib/qobj.c
parentb85120bcb3af24cc35b97cf1fe0a96e54f3cbb6e (diff)
lib: qobj: MT-guard with rwlock
Make qobj_* calls MT-Safe/LF-Blocking. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'lib/qobj.c')
-rw-r--r--lib/qobj.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/lib/qobj.c b/lib/qobj.c
index fd7b4c8c5b..4cf7fbca7b 100644
--- a/lib/qobj.c
+++ b/lib/qobj.c
@@ -26,6 +26,7 @@
#include "log.h"
#include "qobj.h"
+static pthread_rwlock_t nodes_lock;
static struct hash *nodes = NULL;
static unsigned int qobj_key (void *data)
@@ -43,37 +44,61 @@ static int qobj_cmp (const void *a, const void *b)
void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type)
{
node->type = type;
+ pthread_rwlock_wrlock (&nodes_lock);
do
{
node->nid = (uint64_t)random();
node->nid ^= (uint64_t)random() << 32;
}
while (!node->nid || hash_get (nodes, node, hash_alloc_intern) != node);
+ pthread_rwlock_unlock (&nodes_lock);
}
void qobj_unreg(struct qobj_node *node)
{
+ pthread_rwlock_wrlock (&nodes_lock);
hash_release (nodes, node);
+ pthread_rwlock_unlock (&nodes_lock);
}
struct qobj_node *qobj_get(uint64_t id)
{
- struct qobj_node dummy = { .nid = id };
- return hash_lookup (nodes, &dummy);
+ struct qobj_node dummy = { .nid = id }, *rv;
+ pthread_rwlock_rdlock (&nodes_lock);
+ rv = hash_lookup (nodes, &dummy);
+ pthread_rwlock_unlock (&nodes_lock);
+ return rv;
}
void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type)
{
- struct qobj_node *node = qobj_get(id);
+ struct qobj_node dummy = { .nid = id };
+ struct qobj_node *node;
+ void *rv;
+
+ pthread_rwlock_rdlock (&nodes_lock);
+ node = hash_lookup (nodes, &dummy);
+
+ /* note: we explicitly hold the lock until after we have checked the type.
+ * if the caller holds a lock that for example prevents the deletion of
+ * route-maps, we can still race against a delete of something that isn't
+ * a route-map. */
if (!node || node->type != type)
- return NULL;
- return (char *)node - node->type->node_member_offset;
+ rv = NULL;
+ else
+ rv = (char *)node - node->type->node_member_offset;
+
+ pthread_rwlock_unlock (&nodes_lock);
+ return rv;
}
void qobj_init (void)
{
if (!nodes)
- nodes = hash_create (qobj_key, qobj_cmp);
+ {
+ pthread_rwlock_init (&nodes_lock, NULL);
+ nodes = hash_create (qobj_key, qobj_cmp);
+ }
}
void qobj_finish (void)
@@ -81,4 +106,5 @@ void qobj_finish (void)
hash_clean (nodes, NULL);
hash_free (nodes);
nodes = NULL;
+ pthread_rwlock_destroy (&nodes_lock);
}