summaryrefslogtreecommitdiffstats
path: root/lib/qobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qobj.c')
-rw-r--r--lib/qobj.c45
1 files changed, 35 insertions, 10 deletions
diff --git a/lib/qobj.c b/lib/qobj.c
index 8a386d248..4cf7fbca7 100644
--- a/lib/qobj.c
+++ b/lib/qobj.c
@@ -13,10 +13,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with Quagga; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
@@ -27,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)
@@ -44,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)
@@ -82,4 +106,5 @@ void qobj_finish (void)
hash_clean (nodes, NULL);
hash_free (nodes);
nodes = NULL;
+ pthread_rwlock_destroy (&nodes_lock);
}