Radix tree/IDR/IDA

来源:互联网 发布:2016软件人均产值 编辑:程序博客网 时间:2024/05/20 08:42

Radix tree

原理

利用radix tree可以根据一个长整形快速查找其对应的对象指针。radix树与trie树有点相似,trie树一般用于字符串到对象的映射,radix树一般用于长整数到对象的映射。

这里写图片描述
来看一个四叉radix树,树高为4,每一个根节点最多有四个叶节点,总共最多有256个节点。而且这里每个叶节点使用两个字母(00/01/10/11)表示,一层层下来,由于总共有4层,每个长整型一定是0x00000010类似的8个字母组成的数据。

当我们插入一个新节点的时候,我们根据数据的比特位,在树中向下查找,若没有相应的节点,则生成相应的节点,直到数据比特位访问完,则建立叶节点映射相应的对象。

当我们删除一个节点的时候,沿着路径查找到叶节点后,直接删除叶节点,中间的非叶节点不删除。


结构体及API介绍

linux内核中相关的文件include/linux/radix-tree.h和lib/radix-tree.c,使用时包含头文件#include<linux/radix-tree.h>

radix树的root节点的结构体

struct radix_tree_root {        unsigned int            height;//从叶节点向上计算出的树高度        gfp_t                   gfp_mask;//内存申请的标识        struct radix_tree_node  __rcu *rnode;//子节点指针};

radix树叶子节点的结构体

struct radix_tree_node {        unsigned int    height;/* Height from the bottom */        unsigned int    count;//子节点个数        union {                struct radix_tree_node *parent;//父节点指针                struct rcu_head rcu_head;//用于节点释放的RCU链表        };        void __rcu      *slots[RADIX_TREE_MAP_SIZE];//指向存储数据指针        unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];};

初始化

#define RADIX_TREE_INIT(mask)   {                                       \        .height = 0,                                                    \        .gfp_mask = (mask),                                             \        .rnode = NULL,                                                  \}#define RADIX_TREE(name, mask) \        struct radix_tree_root name = RADIX_TREE_INIT(mask)

或者使用
先定义struct radix_tree_root my_radix_tree;变量之后,再使用下面的宏对这个变量初始化。

#define INIT_RADIX_TREE(root, mask)                                     \do {                                                                    \        (root)->height = 0;                                             \        (root)->gfp_mask = (mask);                                      \        (root)->rnode = NULL;                                           \} while (0)

节点的插入与删除与查找

int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);void *radix_tree_delete(struct radix_tree_root *, unsigned long);void *radix_tree_lookup(struct radix_tree_root *, unsigned long);

例子


IDR

IDR机制是内核中将一个整数ID号和指针关联在一起的机制。
比如,当适配器要访问总线上的I2C设备时,首先要知道他们的ID号,同时要在内核中建立一个用于描述该设备的设备结构体,驱动程序将ID号和设备结构体关联起来,如果使用数组进行索引,一旦ID号很大,则用数组索引会占据大量的存储空间,如果使用链表,在总线上设备特别多的情况下,链表的查询效率不高。此时,IDR机制应运而生,内部采用红黑树,可以很方便的将整数和指针关联起来,并且有很高的搜索效率。

下面是linux/idr.h头文件中的一些定义,具体的函数调用接口可能随着新的内核已经发生了改变,要根据对应的include/idr.h头文件中的定义来。
相关结构体

struct idr {        struct idr_layer __rcu  *hint;  /* the last layer allocated from */        struct idr_layer __rcu  *top;        struct idr_layer        *id_free;        int                     layers; /* only valid w/o concurrent changes */        int                     id_free_cnt;        int                     cur;    /* current pos for cyclic allocation */        spinlock_t              lock;};struct idr_layer {        int                     prefix; /* the ID prefix of this idr_layer */        DECLARE_BITMAP(bitmap, IDR_SIZE); /* A zero bit means "space here" */        struct idr_layer __rcu  *ary[1<<IDR_BITS];        int                     count;  /* When zero, we can release it */        int                     layer;  /* distance from leaf */        struct rcu_head         rcu_head;};

定义并初始化

//定义#define DEFINE_IDR(name)        struct idr name = IDR_INIT(name)//静态初始化#define IDR_INIT(name)                                                  \{                                                                       \        .lock                   = __SPIN_LOCK_UNLOCKED(name.lock),      \}//动态初始化void idr_init(struct idr *idp);

分配存放ID号的内存
int idr_pre_get(struct idr *idp, gfp_t gfp_mask)

将ID号和指针关联
int idr_get_new(struct idr *idp, void *ptr, int *id)
参数ptr是需要关联的指针,参数id是由内核自动分配的ID号

通过ID号查找对应的指针
void *idr_find(struct idr *idr, int id)

删除ID号
void idr_remove(struct idr *idp, int id);


IDA

ida只是用来分配id,并不将某数据结构和id关联起来。
sd设备的设备名,如sda,驱动在生成设备文件的时候会向系统申请一个ida,也就是唯一id,然后把id映射成设备文件名sdxxx,

#define DEFINE_IDA(name)        struct ida name = IDA_INIT(name)#define IDA_INIT(name)          { .idr = IDR_INIT((name).idr), .free_bitmap = NULL, }void ida_init(struct ida *ida);int ida_pre_get(struct ida *ida, gfp_t gfp_mask);int ida_get_new(struct ida *ida, int *p_id);void ida_remove(struct ida *ida, int id);void ida_destroy(struct ida *ida);

参考文章

  1. IDR机制
0 0
原创粉丝点击