Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
  }
}
Esempio n. 3
0
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;
}
Esempio n. 4
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;
}