nodeleaf_t * MOD_BuildBrushes (hull_t *hull) { int numnodes = hull->lastclipnode + 1; int i, j, side; nodeleaf_t *nodeleafs; clipleaf_t *root; // this will be carved into all the actual leafs nodeleafs = calloc (numnodes, sizeof (nodeleaf_t)); root = alloc_leaf (); carve_leaf (hull, nodeleafs, root, hull->firstclipnode); for (i = 0; i < numnodes; i++) { for (j = 0; j < 2; j++) { clipleaf_t *leaf = nodeleafs[i].leafs[j]; clipport_t *p; if (!leaf) continue; for (p = leaf->portals; p; p = p->next[side]) { side = p->leafs[1] == leaf; if (p->edges) continue; p->edges = WindingVectors (p->winding, 0); } } } return nodeleafs; }
static bool find_leaf_calc_offset_recur( extbmp_t *ebmp, word untagged_w, tnode_t *tree, int depth, word start_addr_of_node_coverage, leaf_t **leaf_recv, word *first_addr_for_leaf, bool alloc_if_unfound ) { bool retval; dbmsg( "find_leaf_calc_offset_recur" "( ebmp, 0x%08x, " "tree, depth=%d, " "start_addr=0x%08x, " "leaf_recv, first_addr_for_leaf, " "alloc_if_unfound=%s )", untagged_w, depth, start_addr_of_node_coverage, (alloc_if_unfound?"TRUE":"FALSE") ); assert2( tree != NULL ); if (depth == 0) { assert2( tree->metadata.tag == tag_leaf ); *leaf_recv = &tree->leaf; *first_addr_for_leaf = start_addr_of_node_coverage; return TRUE; } else { inode_t *inode; int idx; word *new_start_addr; word *new_addr_limit; assert2( tree->metadata.tag == tag_inode ); inode = &tree->inode; idx = ( ((untagged_w - start_addr_of_node_coverage) / sizeof(word)) / inode->address_words_per_child ); assert2( idx >= 0 ); assert2( idx < ebmp->entries_per_inode ); new_start_addr = ((word*)start_addr_of_node_coverage + idx * inode->address_words_per_child ); new_addr_limit = (new_start_addr + inode->address_words_per_child ); assert2( new_start_addr <= (word*)untagged_w ); assert2( (word*)untagged_w < new_addr_limit ); if (inode->nodes[ idx ] == NULL) { if (alloc_if_unfound) { if (depth == 1) { assert( (new_start_addr + (ADDRS_PER_WORD*ebmp->leaf_words)) == new_addr_limit ); inode->nodes[ idx ] = alloc_leaf( ebmp, (word)new_start_addr, (word)new_addr_limit ); assert2( inode->nodes[idx]->metadata.tag == tag_leaf ); } else { inode->nodes[ idx ] = alloc_inode( ebmp, inode->address_words_per_child, (word)new_start_addr, (word)new_addr_limit ); assert2( inode->nodes[idx]->metadata.tag == tag_inode ); } } else { return FALSE; } } assert2( inode->nodes[ idx ] != NULL ); assert2( ((depth > 1) && (inode->nodes[ idx ]->metadata.tag == tag_inode)) || ((depth == 1) && (inode->nodes[ idx ]->metadata.tag == tag_leaf)) ); retval = find_leaf_calc_offset_recur( ebmp, untagged_w, inode->nodes[ idx ], depth-1, (word)new_start_addr, leaf_recv, first_addr_for_leaf, alloc_if_unfound ); assert2( tree->metadata.tag == tag_inode ); return retval; } }
static clipleaf_t * carve_leaf (hull_t *hull, nodeleaf_t *nodeleafs, clipleaf_t *leaf, int num) { mclipnode_t *node; plane_t *plane; winding_t *winding, *fw, *bw; clipport_t *portal; clipport_t *new_portal; clipport_t *next_portal; clipleaf_t *other_leaf; clipleaf_t *new_leaf; plane_t clipplane; int side; if (num < 0) { // we've hit a leaf. all done leaf->contents = num; return leaf; } node = hull->clipnodes + num; plane = hull->planes + node->planenum; winding = BaseWindingForPlane (plane); for (portal = leaf->portals; portal; portal = portal->next[side]) { clipplane = hull->planes[portal->planenum]; side = (portal->leafs[1] == leaf); if (side) PlaneFlip (&clipplane, &clipplane); winding = ClipWinding (winding, &clipplane, true); } new_leaf = alloc_leaf (); portal = leaf->portals; leaf->portals = 0; for (; portal; portal = next_portal) { side = (portal->leafs[1] == leaf); next_portal = portal->next[side]; other_leaf = portal->leafs[!side]; remove_portal (portal, other_leaf); DivideWinding (portal->winding, plane, &fw, &bw); if (!fw) { if (side) add_portal (portal, other_leaf, new_leaf); else add_portal (portal, new_leaf, other_leaf); continue; } if (!bw) { if (side) add_portal (portal, other_leaf, leaf); else add_portal (portal, leaf, other_leaf); continue; } new_portal = alloc_portal (); new_portal->planenum = portal->planenum; new_portal->winding = bw; FreeWinding (portal->winding); portal->winding = fw; if (side) { add_portal (portal, other_leaf, leaf); add_portal (new_portal, other_leaf, new_leaf); } else { add_portal (portal, leaf, other_leaf); add_portal (new_portal, new_leaf, other_leaf); } } new_portal = alloc_portal (); new_portal->planenum = node->planenum; new_portal->winding = winding; add_portal (new_portal, leaf, new_leaf); nodeleafs[num].leafs[0] = carve_leaf (hull, nodeleafs, leaf, node->children[0]); nodeleafs[num].leafs[1] = carve_leaf (hull, nodeleafs, new_leaf, node->children[1]); return 0; }
/* * Before calling this you must have stocked the preload area by * calling skiplist_preload, and you must have kept preemption * off. preload_token comes from skiplist_preload, pass in * exactly what preload gave you. * * 'slot' will be inserted into the skiplist, returning 0 * on success or < 0 on failure * * If 'cache' isn't null, we try to insert into cache first. * When we return a reference to the leaf where the insertion * was done is added. * * More details in the comments below. */ int skiplist_insert(struct sl_list *list, struct sl_slot *slot, int preload_token, struct sl_leaf **cache) { struct sl_node *p; struct sl_node *ins_locked = NULL; struct sl_leaf *leaf; unsigned long key = slot->key; unsigned long size = slot->size; unsigned long min_key; unsigned long max_key; int level; int ret; int err; rcu_read_lock(); ret = -EEXIST; /* try our cache first */ if (cache && *cache) { leaf = *cache; skiplist_wait_pending_insert(&leaf->node); err = verify_key_in_path(list, &leaf->node, key, size); if (err == -EEXIST) { ret = -EEXIST; goto fail; } else if (err == 0) { ins_locked = &leaf->node; level = 0; goto find_or_add; } else { invalidate_cache(cache); } } again: p = list->head; level = list->level; do { while (1) { leaf = sl_next_leaf(list, p, level); if (!leaf) { skiplist_wait_pending_insert(p); /* * if we're at level 0 and p points to * the head, the list is just empty. If * we're not at level 0 yet, keep walking * down. */ if (p == list->head || level != 0) break; err = verify_key_in_path(list, p, key, size); if (err == -EEXIST) { ret = -EEXIST; goto fail; } else if (err) { goto again; } leaf = sl_next_leaf(list, p, level); if (leaf) { sl_unlock_node(p); goto again; } /* * p was the last leaf on the bottom level, * We're here because 'key' was bigger than the * max key in p. find_or_add will append into * the last leaf. */ ins_locked = p; goto find_or_add; } max_key = sl_max_key(leaf); /* * strictly speaking this test is covered again below. * But usually we have to walk forward through the * pointers, so this is the most common condition. Try * it first. */ if (key >= max_key) goto next; min_key = sl_min_key(leaf); if (key < min_key) { /* * our key is smaller than the smallest key in * leaf. If we're not in level 0 yet, we don't * want to cross over into the leaf */ if (level != 0) break; p = &leaf->node; skiplist_wait_pending_insert(p); err = verify_key_in_path(list, p, key, size); if (err == -EEXIST) { ret = -EEXIST; goto fail; } else if (err) { goto again; } if (key >= sl_min_key(leaf)) { sl_unlock_node(p); goto again; } /* * we are in level 0, prepend our key * into this leaf */ ins_locked = p; goto find_or_add; } if (key < sl_max_key(leaf)) { /* * our key is smaller than the max * and bigger than the min, this is * the one true leaf for our key no * matter what level we're in */ p = &leaf->node; skiplist_wait_pending_insert(p); sl_lock_node(p); if (sl_node_dead(p) || key >= sl_max_key(leaf) || key < sl_min_key(leaf)) { sl_unlock_node(p); goto again; } ins_locked = p; goto find_or_add; } next: p = &leaf->node; } level--; } while (level >= 0); /* * we only get here if the list is completely empty. FIXME * this can be folded into the find_or_add code below */ sl_lock_node(list->head); if (list->head->ptrs[0].next != NULL) { sl_unlock_node(list->head); goto again; } atomic_inc(&slot->refs); leaf = alloc_leaf(slot, key, preload_token); level = leaf->node.level; leaf->node.pending = SKIPLIST_PENDING_INSERT; sl_lock_node(&leaf->node); if (level > list->level) list->level++; cache_leaf(leaf, cache); /* unlocks the leaf and the list head */ sl_link_after_node(list, &leaf->node, list->head, level); ret = 0; rcu_read_unlock(); return ret; find_or_add: leaf = sl_entry(ins_locked); /* ins_locked is unlocked */ ret = find_or_add_key(list, key, size, leaf, slot, preload_token, cache); fail: rcu_read_unlock(); return ret; }