读rbtree
读rbtree
定义在rbtree.c文件
rb_insert_color:插入一个节点
rb_prev:返回当前节点之前的节点e
rb_next:返回当前节点之后的节点
rb_erase:删除一个节点
内存管理,io调度算法等等使用了红黑树!
红黑树实质是自平衡二叉树。
两个完全公平调度策略,一个是CFS进程调度器中使用,另一个是CFQ有关块设备的调度策略。
CFS进程调度策略是基于红黑树实现。
virtual runtime(vruntime) 记录着进程已经运行的时间,但是并不是直接记录,而是要根据进程的权重将运行时间放大或者缩小一个比例。
在完全公平调度算法中基于红黑树来实现,CFS数据结构,调度实体sched_entity,它代表一个调度单位,在组调度关闭的时候可以把它等同为进程。每一个task_struct中都有一个sched_entity,进程的vruntime和权重都保存在这个结构中。那么所有的sched_entity依靠红黑树来组织在一起。
所有的sched_entity以vruntime为key插入到红黑树中,同时缓存树的最左侧节点,也就是vrumtime最小的节点,这样可以迅速选中vruntime最小的进程。
只有等待CPU的就绪态进程在这棵树上,睡眠进程和正在运行的进程都不在树上。
struct rb_node {
unsigned long __rb_parent_color; //父节点的颜色
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__( ( aligned(sizeof(long) ) ) );
在linux的rbtree实现中没有key域,这是linux数据结构的一个特色,就是结构不包括数据,而是由数据和基本结构被包括在同一个struct中。(list_head中没有data域,需要用链表的struct中要包含list_head域一样)由结构体获取数据信息是通过CONTAINER_OF这个宏来实现的,利用了一些编译器的特性,参考Linux的链表源码。
rb_node结构体,被一个”__attribute__((aligned(sizeof(long))))”所包装(非常重要,技巧),
”__attribute__((aligned(sizeof(long))))“的意思是把结构体的地址按“sizeof(long)”对齐,
对于32位机,sizeof(long)为4 (即结构体内的数据类型的地址为4的倍数)。对于64位机,sizeof(long)为8(结构体内的数据类型的地址为8的倍数).
关键的点:
- 对于rb_tree中的每一个节点,都需要标记一个颜色(只有两种选择red/black),技巧就在于使用了字节对齐,任何rb_node结构体的地址的低两位肯定都是0,用它们来表示颜色。
- unsingned long rb_parent_color 变量有两个作用:存储父节点的地址,用后两位来标识此节点的颜色。
#define rb_parent(r) ( (struct rb_node *) ( (r)->__rb_parent_color & ~3 ) )
/*3的二进制后几位是011,取反,后两位是00,在和r节点存储的父节点进行与运算得到地址,也就是说把后两位置零。
#define rb_entry(ptr, type, member) container_of(ptr, type, memeber)
container_of(ptr,type,memeber)三个参数分别代表指针、类型、成员。
通过一个结构体变量中一个成员的地址找到这个结构体变量的首地址。算结构体地址。
jcmaxx33@gmail.com
jcmaxx33Team@github