bool replace;
bool lock;
pthread_mutex_t mutex;
+
+ TALLOC_CTX *node_ctx; //!< Freed last by the destructor, to ensure
+ //!< the tree is still functional.
};
#ifndef NDEBUG
talloc_free(data);
}
-/** Executes the free walker on a tree, and then frees the tree itself
+/** Free the rbtree cleaning up any nodes
+ *
+ * Walk the tree deleting nodes, then free any children of the tree.
*
- * @note If you don't require the free walker to execute, you can just
- * talloc_free the tree. All mutexes will be cleaned up.
+ * @note If the destructor of a talloc descendent needs to lookup any
+ * information in the tree, it will be unavailable at the point
+ * of freeing. We could fix this by introducing a pre-free callback
+ * which gets called before any of the nodes are deleted.
*
- * @param tree to free.
+ * @param[in] tree to tree.
+ * @return 0
*/
-void rbtree_free(rbtree_t *tree)
+static int _tree_free(rbtree_t *tree)
{
- if (!tree) return;
-
- if (tree->lock) pthread_mutex_lock(&tree->mutex);
-
/*
* walk the tree, deleting the nodes...
*/
#endif
tree->root = NULL;
- if (tree->lock) pthread_mutex_unlock(&tree->mutex);
-
- talloc_free(tree);
-}
+ /*
+ * Ensure all dependents on the tree run their
+ * destructors. The tree at this point should
+ * and any tree operations should be empty.
+ */
+ talloc_free_children(tree);
-static int _rbtree_free(rbtree_t *tree)
-{
+ /*
+ * Clear up locks.
+ */
if (tree->lock) pthread_mutex_destroy(&tree->mutex);
return 0;
/** Create a new RED-BLACK tree
*
+ * @note Due to the node memory being allocated from a different pool to the main
*/
rbtree_t *rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
{
tree->compare = compare;
tree->replace = (flags & RBTREE_FLAG_REPLACE) != 0 ? true : false;
tree->lock = (flags & RBTREE_FLAG_LOCK) != 0 ? true : false;
- if (tree->lock) {
- pthread_mutex_init(&tree->mutex, NULL);
- }
+ tree->node_ctx = talloc_new(tree);
+ if (tree->lock) pthread_mutex_init(&tree->mutex, NULL);
- talloc_set_destructor(tree, _rbtree_free);
+ talloc_set_destructor(tree, _tree_free);
tree->free = node_free;
return tree;
{
rbnode_t *current, *parent, *x;
+ if (!tree->root) return NULL;
+
if (tree->lock) pthread_mutex_lock(&tree->mutex);
/* find where node belongs */
}
/* setup new node */
- x = talloc_zero(tree, rbnode_t);
+ x = talloc_zero(tree->node_ctx, rbnode_t);
if (!x) {
fr_strerror_printf("No memory for new rbtree node");
if (tree->lock) pthread_mutex_unlock(&tree->mutex);
bool rbtree_insert(rbtree_t *tree, void *data)
{
+ if (!tree->root) return NULL;
+
if (rbtree_insert_node(tree, data)) return true;
return false;
}
if (tree->lock) pthread_mutex_unlock(&tree->mutex);
}
}
-void rbtree_delete(rbtree_t *tree, rbnode_t *z) {
+
+void rbtree_delete(rbtree_t *tree, rbnode_t *z)
+{
+ if (!tree->root) return;
+
rbtree_delete_internal(tree, z, false);
}
*/
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
{
- rbnode_t *node = rbtree_find(tree, data);
+ rbnode_t *node;
+
+ if (!tree->root) return false;
+ node = rbtree_find(tree, data);
if (!node) return false;
rbtree_delete(tree, node);
{
rbnode_t *current;
+ if (!tree->root) return NULL;
+
if (tree->lock) pthread_mutex_lock(&tree->mutex);
current = tree->root;
{
rbnode_t *x;
+ if (!tree->root) return NULL;
+
x = rbtree_find(tree, data);
if (!x) return NULL;
{
#ifdef WITH_PROXY
# ifdef WITH_STATS
- rbtree_free(home_servers_bynumber);
+ talloc_free(home_servers_bynumber);
home_servers_bynumber = NULL;
# endif
- rbtree_free(home_servers_byname);
+ talloc_free(home_servers_byname);
home_servers_byname = NULL;
- rbtree_free(home_servers_byaddr);
+ talloc_free(home_servers_byaddr);
home_servers_byaddr = NULL;
- rbtree_free(home_pools_byname);
+ talloc_free(home_pools_byname);
home_pools_byname = NULL;
#endif
- rbtree_free(realms_byname);
+ talloc_free(realms_byname);
realms_byname = NULL;
realm_pool_free(NULL);