/** * b1_node_implement() - implement interface on node * @node: node to operate on * @interface: interface to implement * * Extend @node to support the interface given as @interface. From then on, the * node will dispatch incoming method calls on this interface. * * This fails, if the given interface is already implemented by @node. * * Return: 0 on success, negative error code on failure. */ _c_public_ int b1_node_implement(B1Node *node, B1Interface *interface) { B1Implementation *implementation; CRBNode **slot, *p; assert(node); assert(interface); if (node->live || node->slot) return -EBUSY; slot = c_rbtree_find_slot(&node->implementations, implementations_compare, interface->name, &p); if (!slot) return -ENOTUNIQ; implementation = calloc(1, sizeof(*implementation)); if (!implementation) return -ENOMEM; c_rbnode_init(&implementation->rb); implementation->interface = b1_interface_ref(interface); interface->implemented = true; c_rbtree_add(&node->implementations, p, slot, &implementation->rb); return 0; }
static void test_parent_start(TestContext *ctx) { size_t i; /* * Generate a tree with @n_nodes entries. We store the entries in * @ctx->node_mem, generate a randomized access-map in @ctx->nodes * (i.e., an array of pointers to entries in @ctx->node_mem, but in * random order), and a temporary cache for free use in the parent. * * All this is stored in a MAP_SHARED memory region so it is equivalent * in child and parent. */ ctx->n_nodes = 32; ctx->mapsize = sizeof(CRBTree); ctx->mapsize += ctx->n_nodes * sizeof(TestNode); ctx->mapsize += ctx->n_nodes * sizeof(CRBNode*); ctx->mapsize += ctx->n_nodes * sizeof(CRBNode*); ctx->map = mmap(NULL, ctx->mapsize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); c_assert(ctx->map != MAP_FAILED); ctx->tree = (void *)ctx->map; ctx->node_mem = (void *)(ctx->tree + 1); ctx->nodes = (void *)(ctx->node_mem + ctx->n_nodes); ctx->cache = (void *)(ctx->nodes + ctx->n_nodes); for (i = 0; i < ctx->n_nodes; ++i) { ctx->nodes[i] = &ctx->node_mem[i].rb; c_rbnode_init(ctx->nodes[i]); } shuffle(ctx->nodes, ctx->n_nodes); }
/* 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)); }
/* run tests against the c_rbtree_find*() helpers */ static void test_map(void) { CRBNode **slot, *p; CRBTree t = {}; Node *nodes[2048]; unsigned long i; /* allocate and initialize all nodes */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { nodes[i] = malloc(sizeof(*nodes[i])); assert(nodes[i]); nodes[i]->key = i; c_rbnode_init(&nodes[i]->rb); } /* shuffle nodes */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* add all nodes, and verify that each node is linked */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { assert(!c_rbnode_is_linked(&nodes[i]->rb)); assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p); assert(slot); c_rbtree_add(&t, p, slot, &nodes[i]->rb); assert(c_rbnode_is_linked(&nodes[i]->rb)); assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); } /* shuffle nodes again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* remove all nodes (in different order) */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { assert(c_rbnode_is_linked(&nodes[i]->rb)); assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); c_rbtree_remove_init(&t, &nodes[i]->rb); assert(!c_rbnode_is_linked(&nodes[i]->rb)); assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); } /* free nodes again */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) free(nodes[i]); }
int b1_handle_new(B1Peer *peer, uint64_t id, B1Handle **handlep) { _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL; assert(peer); assert(handlep); handle = calloc(1, sizeof(*handle)); if (!handle) return -ENOMEM; handle->n_ref = 1; handle->holder = b1_peer_ref(peer); handle->id = id; handle->marked = false; c_rbnode_init(&handle->rb); *handlep = handle; handle = NULL; return 0; }
static int b1_handle_new(B1Peer *peer, B1Handle **handlep) { _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL; assert(peer); assert(handlep); handle = calloc(1, sizeof(*handle)); if (!handle) return -ENOMEM; handle->ref = (CRef)C_REF_INIT; handle->holder = b1_peer_ref(peer); handle->id = BUS1_HANDLE_INVALID; handle->marked = false; handle->live = false; c_rbnode_init(&handle->rb); *handlep = handle; handle = NULL; return 0; }
/** * b1_node_new() - create a new node for a peer * @peer: the owning peer * @nodep: pointer to the new node object * * Return: 0 on success, and a negative error code on failure. */ _c_public_ int b1_node_new(B1Peer *peer, B1Node **nodep) { _c_cleanup_(b1_node_freep) B1Node *node = NULL; int r; node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; node->id = BUS1_HANDLE_INVALID; node->owner = b1_peer_ref(peer); c_rbnode_init(&node->rb_nodes); r = b1_handle_new(peer, &node->handle); if (r < 0) return r; node->handle->node = node; *nodep = node; node = NULL; return 0; }
/* 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]); }