diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2017-05-08 06:07:52 +0200 |
|---|---|---|
| committer | Quentin Young <qlyoung@users.noreply.github.com> | 2017-05-18 14:07:28 -0400 |
| commit | 297c8f6a31979637c43227902a8b71f87088e46b (patch) | |
| tree | 8f858104fd0d96b3a3f2ef5738db589ea3c35dc2 /lib/qobj.c | |
| parent | b85120bcb3af24cc35b97cf1fe0a96e54f3cbb6e (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.c | 38 |
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); } |
