mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-04 20:51:28 +00:00
kvm tools: Add interval red-black tree helper
Interval rb-tree allows to directly store interval ranges and quickly lookup an overlap with a single point or a range. The helper is based on the kernel rb-tree implementation (located in <linux/rbtree.h>) which alows for the augmention of the classical rb-tree to be used as an interval tree. Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
@@ -42,6 +42,7 @@ OBJS += mptable.o
|
||||
OBJS += threadpool.o
|
||||
OBJS += irq.o
|
||||
OBJS += ../../lib/rbtree.o
|
||||
OBJS += util/rbtree-interval.o
|
||||
|
||||
DEPS := $(patsubst %.o,%.d,$(OBJS))
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef KVM__INTERVAL_RBTREE_H
|
||||
#define KVM__INTERVAL_RBTREE_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define RB_INT_INIT(l, h) (struct rb_int_node){.low = l, .high = h}
|
||||
|
||||
struct rb_int_node {
|
||||
struct rb_node node;
|
||||
u64 low;
|
||||
u64 high;
|
||||
|
||||
/* max_high will store the highest high of it's 2 children. */
|
||||
u64 max_high;
|
||||
};
|
||||
|
||||
/* Return the rb_int_node interval in which 'point' is located. */
|
||||
struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point);
|
||||
|
||||
/* Return the rb_int_node in which start:len is located. */
|
||||
struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high);
|
||||
|
||||
int rb_int_insert(struct rb_root *root, struct rb_int_node *data);
|
||||
void rb_int_erase(struct rb_root *root, struct rb_int_node *node);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
#ifndef KVM__LINUX_KERNEL_H_
|
||||
#define KVM__LINUX_KERNEL_H_
|
||||
|
||||
@@ -23,4 +24,16 @@
|
||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||
#endif
|
||||
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
#define max(x, y) ({ \
|
||||
typeof(x) _max1 = (x); \
|
||||
typeof(y) _max2 = (y); \
|
||||
(void) (&_max1 == &_max2); \
|
||||
_max1 > _max2 ? _max1 : _max2; })
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#include <kvm/rbtree-interval.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define rb_int(n) rb_entry(n, struct rb_int_node, node)
|
||||
|
||||
struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point)
|
||||
{
|
||||
struct rb_node *node = root->rb_node;
|
||||
struct rb_node *lowest = NULL;
|
||||
|
||||
while (node) {
|
||||
struct rb_int_node *cur = rb_int(node);
|
||||
|
||||
if (node->rb_left && (rb_int(node->rb_left)->max_high > point)) {
|
||||
node = node->rb_left;
|
||||
} else if (cur->low <= point && cur->high > point) {
|
||||
lowest = node;
|
||||
break;
|
||||
} else if (point > cur->low) {
|
||||
node = node->rb_right;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lowest == NULL)
|
||||
return NULL;
|
||||
|
||||
return rb_int(lowest);
|
||||
}
|
||||
|
||||
struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high)
|
||||
{
|
||||
struct rb_int_node *range;
|
||||
|
||||
range = rb_int_search_single(root, low);
|
||||
if (range == NULL)
|
||||
return NULL;
|
||||
|
||||
/* We simply verify that 'high' is smaller than the end of the range where 'low' is located */
|
||||
if (range->high < high)
|
||||
return NULL;
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static void update_node_max_high(struct rb_node *node, void *arg)
|
||||
{
|
||||
struct rb_int_node *i_node = rb_int(node);
|
||||
|
||||
i_node->max_high = i_node->high;
|
||||
|
||||
if (node->rb_left)
|
||||
i_node->max_high = max(i_node->max_high, rb_int(node->rb_left)->high);
|
||||
if (node->rb_right)
|
||||
i_node->max_high = max(i_node->max_high, rb_int(node->rb_right)->high);
|
||||
}
|
||||
|
||||
int rb_int_insert(struct rb_root *root, struct rb_int_node *i_node)
|
||||
{
|
||||
struct rb_node **node = &(root->rb_node), *parent = NULL;
|
||||
|
||||
while (*node) {
|
||||
int result = i_node->low - rb_int(*node)->low;
|
||||
|
||||
parent = *node;
|
||||
if (result < 0)
|
||||
node = &((*node)->rb_left);
|
||||
else if (result > 0)
|
||||
node = &((*node)->rb_right);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
rb_link_node(&i_node->node, parent, node);
|
||||
rb_insert_color(&i_node->node, root);
|
||||
|
||||
rb_augment_insert(*node, update_node_max_high, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rb_int_erase(struct rb_root *root, struct rb_int_node *node)
|
||||
{
|
||||
struct rb_node *deepest;
|
||||
|
||||
deepest = rb_augment_erase_begin(&node->node);
|
||||
rb_erase(&node->node, root);
|
||||
rb_augment_erase_end(deepest, update_node_max_high, NULL);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user