diff options
Diffstat (limited to 'lib/qobj.c')
-rw-r--r-- | lib/qobj.c | 45 |
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); } |