/** * b1_node_free() - destroy a node * @node: node to destroy * * This destroys the given node and releases all linked resources. This implies * a call to b1_node_destroy(), if not already done by the caller. * * Return: NULL is returned. */ _c_public_ B1Node *b1_node_free(B1Node *node) { CRBNode *n; if (!node) return NULL; assert(node->owner); b1_node_release(node); while ((n = c_rbtree_first(&node->implementations))) { B1Implementation *implementation = c_container_of(n, B1Implementation, rb); c_rbtree_remove(&node->implementations, n); b1_interface_unref(implementation->interface); free(implementation); } /* if the node name is set, it means this node is owned by a message or * peer object, which will be responsibly for cleaning it up */ if (!node->name && node->id != BUS1_HANDLE_INVALID) { b1_node_destroy(node); c_rbtree_remove(&node->owner->nodes, &node->rb); } b1_peer_unref(node->owner); free(node); return NULL; }
/* verify that all API calls are exported */ static void test_api(void) { CRBTree t = {}; CRBNode n = C_RBNODE_INIT(n); assert(!c_rbnode_is_linked(&n)); /* init, is_linked, add, remove, remove_init */ c_rbtree_add(&t, NULL, &t.root, &n); assert(c_rbnode_is_linked(&n)); c_rbtree_remove_init(&t, &n); assert(!c_rbnode_is_linked(&n)); c_rbtree_add(&t, NULL, &t.root, &n); assert(c_rbnode_is_linked(&n)); c_rbtree_remove(&t, &n); assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */ c_rbnode_init(&n); assert(!c_rbnode_is_linked(&n)); /* first, last, leftmost, rightmost, next, prev */ assert(!c_rbtree_first(&t)); assert(!c_rbtree_last(&t)); assert(&n == c_rbnode_leftmost(&n)); assert(&n == c_rbnode_rightmost(&n)); assert(!c_rbnode_next(&n)); assert(!c_rbnode_prev(&n)); }
/** * b1_handle_unref() - release reference * @handle: handle to release reference to, or NULL * * Release a single reference to an handle. If this is the last reference, the * handle is freed. * * If NULL is passed, this is a no-op. * * Return: NULL is returned. */ _c_public_ B1Handle *b1_handle_unref(B1Handle *handle) { if (!handle) return NULL; assert(handle->n_ref > 0); if (--handle->n_ref > 0) return NULL; b1_handle_release(handle); if (handle->id != BUS1_HANDLE_INVALID) { assert(handle->holder); c_rbtree_remove(&handle->holder->handles, &handle->rb); } b1_peer_unref(handle->holder); free(handle); return NULL; }
/* run some pseudo-random tests on the tree */ static void test_shuffle(void) { CRBNode *nodes[256]; CRBTree t = {}; unsigned int i, j; size_t n; /* allocate and initialize all nodes */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { nodes[i] = malloc(sizeof(*nodes[i])); assert(nodes[i]); c_rbnode_init(nodes[i]); } /* shuffle nodes and validate *empty* tree */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); n = validate(&t); assert(n == 0); /* add all nodes and validate after each insertion */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { insert(&t, nodes[i]); n = validate(&t); assert(n == i + 1); } /* shuffle nodes again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* remove all nodes (in different order) and validate on each round */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { c_rbtree_remove(&t, nodes[i]); n = validate(&t); assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); c_rbnode_init(nodes[i]); } /* shuffle nodes and validate *empty* tree again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); n = validate(&t); assert(n == 0); /* add all nodes again */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { insert(&t, nodes[i]); n = validate(&t); assert(n == i + 1); } /* 4 times, remove half of the nodes and add them again */ for (j = 0; j < 4; ++j) { /* shuffle nodes again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* remove half of the nodes */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { c_rbtree_remove(&t, nodes[i]); n = validate(&t); assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); c_rbnode_init(nodes[i]); } /* shuffle the removed half */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2); /* add the removed half again */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { insert(&t, nodes[i]); n = validate(&t); assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1); } } /* shuffle nodes again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* remove all */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { c_rbtree_remove(&t, nodes[i]); n = validate(&t); assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); c_rbnode_init(nodes[i]); } /* free nodes again */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) free(nodes[i]); }