最近在看 linux 的源代码,里面的代码十分的精炼,无论是处于什么目的来学习(算法,驱动,文件系统....)都会有十分大的收获。
在阅读 struct rb_node 代码的过程中存在着许多的疑问,所以在这里对 struct rb_node 这一结构体中的相应实现手法加以分析与注释。
1. struct rb_node 结构体代码分析
struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
可以从中学习的就是内核开发人员在实现 rb_node 的时候采用的是地址对其的方式,也就是说,
通过 __attribute__((aligned(sizeof(long)))) 这一条语句来实现存储结构体变量 struct rb_node
的时候是将其地址进行对其的。 在 linux 系统中所沿用的对其策略是,如果存放的是 2字节的
数据类型的话,那么必须保证其地址是 2 的倍数,也就是说 valueof(address) % 2 == 0 ;
而我们同样可以从二进制角度来分析地址,那便是 address 的后 1 位必须是 0 才可保证该
address 的数值可以被 2 整除。 那么我们知道 short 在32 位机器上面占用 2 个字节的大小
那么通过上面的方式便可推知: short 变量的存放地址,如果使用地址对齐那它的地址的最后 1 位
必须是 0 才可以。
以同样的方式推断,在 32 位机器上面,如果存放的变量类型占用是 4 个字节,那么存放该变量的
地址的最后 2 位必须是0 才可以保证该 address %4 == 0 。同样如果存放变量需要 8 个字节大小的
空间,那么该变量所对应的地址address 的最后3位必须是 0 才可以。
如果你曾经看过算法导论中的红黑树的树中节点的结构描述,在看到linux 内核中的rbtree 中的
rb_node 中的用来表示指向父节点的 rb_parent_color 这个字段可能会觉得有些奇怪,这是
因为 rb_parent_color 这一属性字段中存放的信息,不仅仅有当前 rb_node 所在树中的父节点
的地址信息,还用使用其父节点地址数值中的最后 2 位来存放当前结点 rb_node 的颜色这一属性。
在算法导论中的rb_node 的伪代码原型描述如下:
struct rb_node
{
struct rb_node *p ;
struct rb_node *left ,*right ;
type color ;
type key ;
};
从中可以看到的是,其指向父节点的是以结构体指针来表示的,而在内核代码实现中它是以一个
unsigned long 的类型来表示的,其实仔细想一下,二者在本质上是一个东西。指针即为存放