idr机制(32叉树)
来源:互联网 发布:算法新解pdf 编辑:程序博客网 时间:2024/05/16 06:32
一.结构体
1.idr结构体
struct idr {struct idr_layer __rcu *top;//idr_layer顶层,32叉树的根struct idr_layer *id_free;//指向idr_layer的空闲链表intlayers;//idr_layer的层数量intid_free_cnt;//idr_layer空闲链表中剩余的idr_layer个数spinlock_tlock;};
2.idr_layer结构体
struct idr_layer {unsigned longbitmap;//标记位图,标记使用情况struct idr_layer __rcu*ary[1<<IDR_BITS];//子idr_layer数组ary[32]intcount;//ary数组使用情况intlayer;//层号struct rcu_headrcu_head;};
在32位系统中IDR_BITS的取值为5
#if BITS_PER_LONG == 32# define IDR_BITS 5# define IDR_FULL 0xfffffffful# define TOP_LEVEL_FULL (IDR_FULL >> 30)#elif BITS_PER_LONG == 64# define IDR_BITS 6# define IDR_FULL 0xfffffffffffffffful# define TOP_LEVEL_FULL (IDR_FULL >> 62)#else# error "BITS_PER_LONG is not 32 or 64"#endif
二.idr的初始化
#define IDR_INIT(name)\{\.top= NULL,\.id_free= NULL,\.layers = 0,\.id_free_cnt= 0,\.lock= __SPIN_LOCK_UNLOCKED(name.lock),\}#define DEFINE_IDR(name)struct idr name = IDR_INIT(name)
定义一个idr结构体并赋值
三.分配id
1.idr_pre_get
int idr_pre_get(struct idr *idp, gfp_t gfp_mask){while (idp->id_free_cnt < IDR_FREE_MAX) {//IDR_FREE_MAX=14struct idr_layer *new;//定义新的idr_layer结构体指针new = kmem_cache_zalloc(idr_layer_cache, gfp_mask);//分配*new内存空间if (new == NULL)return (0);move_to_free_list(idp, new);//-->move_to_free_list}return 1;}EXPORT_SYMBOL(idr_pre_get);
move_to_free_list
static void move_to_free_list(struct idr *idp, struct idr_layer *p){unsigned long flags;spin_lock_irqsave(&idp->lock, flags);__move_to_free_list(idp, p);//-->__move_to_free_listspin_unlock_irqrestore(&idp->lock, flags);}
__move_to_free_list
static void __move_to_free_list(struct idr *idp, struct idr_layer *p){p->ary[0] = idp->id_free;idp->id_free = p;idp->id_free_cnt++;}
第一次循环结果
接着循环
再接着
一直这样下去直到循环结束(14次)
2.idr_get_new和idr_get_new_above
idr_get_new
int idr_get_new(struct idr *idp, void *ptr, int *id){int rv;rv = idr_get_new_above_int(idp, ptr, 0);if (rv < 0)return _idr_rc_to_errno(rv);*id = rv;return 0;}EXPORT_SYMBOL(idr_get_new);
idr_get_new_above
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id){int rv;rv = idr_get_new_above_int(idp, ptr, starting_id);if (rv < 0)return _idr_rc_to_errno(rv);*id = rv;return 0;}EXPORT_SYMBOL(idr_get_new_above);
两个函数都会调用idr_get_new_above_int函数,差别在于starting_id不同
下面分情况讨论,先以id为0走个过场
idr的top简称为根top,free简称为根free均为idr_layer指针类型,分别指向使用中和空闲idr_layer链表头
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id){struct idr_layer *pa[MAX_LEVEL];//MAX_LEVEL=7int id;id = idr_get_empty_slot(idp, starting_id, pa);//-->idr_get_empty_slotif (id >= 0) {rcu_assign_pointer(pa[0]->ary[id & IDR_MASK],(struct idr_layer *)ptr//pa[0]->ary[0]=ptr 也就是idr_layer14->ary[0]=ptrpa[0]->count++;//idr_layer14->count++idr_mark_full(pa, id);//设置其位图-->走完0过场的效果见图c}return id;}
idr_get_empty_slot
static int idr_get_empty_slot(struct idr *idp, int starting_id,struct idr_layer **pa){struct idr_layer *p, *new;int layers, v, id;unsigned long flags;id = starting_id;//按常规出牌吧,假设这个为0build_up:p = idp->top;//根top指向的idr_layer NULLlayers = idp->layers;//获取layers层数量(0)if (unlikely(!p)) {//第一次运行idp->top=NULL,所以if条件为真,执行if分支的结果参考 图Aif (!(p = get_from_free_list(idp)))//>>>1-->get_from_free_list 从根free中获取一个idr_layer14return -1;p->layer = 0;//指定idr_layer14的层号为0layers = 1;//layers层数量设为1}//layers<6 && id>=2^(layers*5) 看需不需要增加层数 见图Bwhile ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {layers++;if (!p->count) {p->layer++;continue;}if (!(new = get_from_free_list(idp))) {spin_lock_irqsave(&idp->lock, flags);for (new = p; p && p != idp->top; new = p) {p = p->ary[0];new->ary[0] = NULL;new->bitmap = new->count = 0;__move_to_free_list(idp, new);}spin_unlock_irqrestore(&idp->lock, flags);return -1;}new->ary[0] = p;new->count = 1;new->layer = layers-1;if (p->bitmap == IDR_FULL)__set_bit(0, &new->bitmap);p = new;}rcu_assign_pointer(idp->top, p);//根top指向idr_layer14idp->layers = layers;//设置更新idr->layers层数量//----------------------------------------------分割线----------------------------------------------//以上部分主要处理layer相关,以下部分主要处理id相关v = sub_alloc(idp, &id, pa);//>>>2-->sub_allocif (v == IDR_NEED_TO_GROW)//IDR_NEED_TO_GROW=-2需要扩大goto build_up;return(v);}
图A:
图B
>>>get_from_free_list 从idr空闲idr_layer链表中获取第一个idr_layer
static struct idr_layer *get_from_free_list(struct idr *idp){struct idr_layer *p;//定义一个idr_layer指针unsigned long flags;spin_lock_irqsave(&idp->lock, flags);if ((p = idp->id_free)) {//根free获取一个空闲idr_layeridp->id_free = p->ary[0];//idr空闲链表指针指向第二个idr_layeridp->id_free_cnt--;//idr的空闲idr_layer个数减1(14-1)p->ary[0] = NULL;//断开第一个idr_layer和第二个idr_layer的联系}spin_unlock_irqrestore(&idp->lock, flags);return(p);}
这里先穿插一下32进制的计算,上面图B中2^0,2^5,2^10,2^15,2^20,2^25可以(32=2^5)理解成32^0,32^1,32^2,32^3,32^3,32^4,32^5
那么用32进制表达一个十进制数id可以套用一下公式
a的值属于[0,31]
an的值如何获得id/(32^n)即可,等同于id/(2^5^n)等同于id/((1<<5)^n)
an-1的值如何获得id>>(5*(n-1))即可
>>>sub_alloc
static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa){int n, m, sh;struct idr_layer *p, *new;int l, id, oid;unsigned long bm;id = *starting_id; restart:p = idp->top;//根topl = idp->layers;//l=1pa[l--] = NULL;//p[1]=NULL;l=0while (1) {n = (id >> (IDR_BITS*l)) & IDR_MASK;//计算对应的n值,属于[0,31]bm = ~p->bitmap;//取反位图m = find_next_bit(&bm, IDR_SIZE, n);//>>>1 find_next_bit 位图中偏移量为n处查找'1'if (m == IDR_SIZE) {//位图满了l++;oid = id;id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;if (id >= 1 << (idp->layers * IDR_BITS)) {*starting_id = id;return IDR_NEED_TO_GROW;}p = pa[l];BUG_ON(!p);sh = IDR_BITS * (l + 1);if (oid >> sh == id >> sh)continue;elsegoto restart;}if (m != n) {//期望的n值被占用,但可找到可用的m值sh = IDR_BITS*l;id = ((id >> sh) ^ n ^ m) << sh;//>>>2 重新计算id值}if ((id >= MAX_ID_BIT) || (id < 0))return IDR_NOMORE_SPACE;if (l == 0)//l==0跳出while循环break;if (!p->ary[m]) {new = get_from_free_list(idp);if (!new)return -1;new->layer = l-1;rcu_assign_pointer(p->ary[m], new);p->count++;}pa[l--] = p;p = p->ary[m];}pa[l] = p;//pa[0]=p 也就是idr_layer14return id;}
>>>find_next_bit
#define find_next_bit(p,sz,off)_find_next_bit_le(p,sz,off)//>>_find_next_bit_le
该宏的意思是在p指向的(大小为sz的)位图表中的第off个位置开始找寻可用(为"1")的格子,找到返回该位
_find_next_bit_le是汇编代码实现的定义在/arch/arm/lib/findbit.S
ENTRY(_find_next_bit_le)teqr1, #0beq3bandsip, r2, #7beq1b@ If new byte, goto old routine ARM(ldrbr3, [r0, r2, lsr #3]) THUMB(lsrr3, r2, #3) THUMB(ldrbr3, [r0, r3])movsr3, r3, lsr ip@ shift off unused bitsbne.L_foundorrr2, r2, #7@ if zero, then no bits hereaddr2, r2, #1@ align bit pointerb2b@ loop for next bitENDPROC(_find_next_bit_le)
.L_found找到合适的跳转
.L_found:#if __LINUX_ARM_ARCH__ >= 5rsbr0, r3, #0andr3, r3, r0clzr3, r3rsbr3, r3, #31addr0, r2, r3#elsetstr3, #0x0faddeqr2, r2, #4movner3, r3, lsl #4tstr3, #0x30addeqr2, r2, #2movner3, r3, lsl #2tstr3, #0x40addeqr2, r2, #1movr0, r2#endifcmpr1, r0@ Clamp to maxbitmovlor0, r1movpc, lr
>>>id值的计算的补充说明
首先前面n的取值n = (id >> (IDR_BITS*l)) & IDR_MASK;
IDR_MASK的定义#define IDR_MASK ((1 << IDR_BITS)-1)也就是说IDR_MASK=31等于2进制的1,1111b
所以&IDR_MASK只是框定n值落在0~31之间,掩码作用
那么不出意外的话n = (id >> (IDR_BITS*l))
接着
sh = IDR_BITS*l;
id = ((id >> sh) ^ n ^ m) << sh;
带入表达式中
id=((id >> IDR_BITS*l) ^ (id >> (IDR_BITS*l)) ^ m) << IDR_BITS*l;
异或的操作是相同为1,不同为0,结合起来化简得
id = ((1 ^ m) << sh=m<<sh
图C
^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_
已经借用id0走了过场,下面分析下其他情况
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id){struct idr_layer *pa[MAX_LEVEL];//定义父idr_layer数组int id;id = idr_get_empty_slot(idp, starting_id, pa);//获取idif (id >= 0) {rcu_assign_pointer(pa[0]->ary[id & IDR_MASK],(struct idr_layer *)ptr);//pa[0]->ary[id]=ptrpa[0]->count++;//idr_layer->count++idr_mark_full(pa, id);//标记id位图}return id;}static int idr_get_empty_slot(struct idr *idp, int starting_id,struct idr_layer **pa){struct idr_layer *p, *new;int layers, v, id;unsigned long flags;id = starting_id;build_up:p = idp->top;//获取根toplayers = idp->layers;//获取层数量 layers=1if (unlikely(!p)) {//FALSEif (!(p = get_from_free_list(idp)))return -1;p->layer = 0;layers = 1;}while ((layers < 6) && (id >= (1 << (layers*5)))) {//参考图B,如果id值超过或等于对应层所能容纳的最大数,则进入循环layers++;//增加层数量if (!p->count) {//0~31没使用,直接使用32就属于这种情况p->layer++;//由于32需要添加1层的,所以之前的层的层号需要+1continue; //层数量也需要加1}if (!(new = get_from_free_list(idp))) {//空闲链表中获取新的idr_layerspin_lock_irqsave(&idp->lock, flags);//分配失败,--空闲idr_layer链表缺货for (new = p; p && p != idp->top; new = p) {//p指针还原p = p->ary[0];new->ary[0] = NULL;new->bitmap = new->count = 0;__move_to_free_list(idp, new);//分配更多空闲链表}spin_unlock_irqrestore(&idp->lock, flags);return -1;}new->ary[0] = p;//新的idr_layer->ary[0]指向旧的idr_layernew->count = 1;//新的idr_layer计数加1new->layer = layers-1;//设置新的idr_layer的层号if (p->bitmap == IDR_FULL)//若旧的(叶子)idr_layer的id全用过了__set_bit(0, &new->bitmap);//那么标记下新(父)idr_layer位图的第0位p = new;//根top指向新的idr_layer}rcu_assign_pointer(idp->top, p);//设置根topidp->layers = layers;//更新层数量v = sub_alloc(idp, &id, pa);//获取idif (v == IDR_NEED_TO_GROW)//该层id号全用完了,必须扩大idr_layer层数量goto build_up;return(v);}static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa){int n, m, sh;struct idr_layer *p, *new;int l, id, oid;unsigned long bm;id = *starting_id; restart:p = idp->top;//获取根topl = idp->layers;//获取层数量l=1pa[l--] = NULL;//pa[1]=NULL,l=0while (1) {n = (id >> (5*l)) & IDR_MASK;//n做处理 属于[0,31]bm = ~p->bitmap;//位图取反m = find_next_bit(&bm, IDR_SIZE, n);//查找n开始能用的位if (m == IDR_SIZE) {//id表满了l++;层数+1oid = id;id = (id | ((1 << (5 * l)) - 1)) + 1;//id或上掩码再+1if (id >= 1 << (idp->layers * 5)) {//需要添加层*starting_id = id;return IDR_NEED_TO_GROW;}p = pa[l];BUG_ON(!p);sh = 5 * (l + 1);if (oid >> sh == id >> sh)continue;elsegoto restart;}if (m != n) {//期望id给用但有可用idsh = 5*l;id = ((id >> sh) ^ n ^ m) << sh;//id设置为可用id}if ((id >= MAX_ID_BIT) || (id < 0))return IDR_NOMORE_SPACE;if (l == 0)//一层层循环计算直到到达叶子处l才为0break;if (!p->ary[m]) {//叶子m为空new = get_from_free_list(idp);//从空闲链表拿一个idr_layerif (!new)return -1;new->layer = l-1;//设置新链表层数rcu_assign_pointer(p->ary[m], new);//叶子m指向新链表p->count++;//使用计数加1}pa[l--] = p;//pa[大]=节点p = p->ary[m];//p=节点->叶子m}pa[l] = p;//pa[小]=叶子return id;}
来个效果图id=4吧
id=32情况(idr_layer13的位图1标记错了)
1024情况
四.查找id
1.idr_find
void *idr_find(struct idr *idp, int id){int n;struct idr_layer *p;p = rcu_dereference_raw(idp->top);//获取根topif (!p)return NULL;n = (p->layer+1) * IDR_BITS;//计算最外层的n值id &= MAX_ID_MASK;if (id >= (1 << n))return NULL;BUG_ON(n == 0);while (n > 0 && p) {//循环一层层查找n -= IDR_BITS;BUG_ON(n != p->layer*IDR_BITS);p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);//一次获取an ... a0 }return((void *)p);}EXPORT_SYMBOL(idr_find);
前面讲过32进制的id值算法
当构建完idr机制之后
id=top->ary[an]->ary[a(n-1)]->....->ary[a0]来获得
借助图片分析下(idr_layer13的位图标记有错)
五idr操作
1. idr_remove idr_remove_all 移除
void idr_remove(struct idr *idp, int id){struct idr_layer *p;struct idr_layer *to_free;id &= MAX_ID_MASK;sub_remove(idp, (idp->layers - 1) * IDR_BITS, id);if (idp->top && idp->top->count == 1 && (idp->layers > 1) && idp->top->ary[0]) {to_free = idp->top;p = idp->top->ary[0];rcu_assign_pointer(idp->top, p);--idp->layers;to_free->bitmap = to_free->count = 0;free_layer(to_free);}while (idp->id_free_cnt >= IDR_FREE_MAX) {p = get_from_free_list(idp);kmem_cache_free(idr_layer_cache, p);}return;}EXPORT_SYMBOL(idr_remove);
移除全部
void idr_remove_all(struct idr *idp){int n, id, max;int bt_mask;struct idr_layer *p;struct idr_layer *pa[MAX_LEVEL];struct idr_layer **paa = &pa[0];n = idp->layers * IDR_BITS;p = idp->top;rcu_assign_pointer(idp->top, NULL);max = 1 << n;id = 0;while (id < max) {while (n > IDR_BITS && p) {n -= IDR_BITS;*paa++ = p;p = p->ary[(id >> n) & IDR_MASK];}bt_mask = id;id += 1 << n;/* Get the highest bit that the above add changed from 0->1. */while (n < fls(id ^ bt_mask)) {if (p)free_layer(p);n += IDR_BITS;p = *--paa;}}idp->layers = 0;}EXPORT_SYMBOL(idr_remove_all);
2.idr_replace 替换
void *idr_replace(struct idr *idp, void *ptr, int id){int n;struct idr_layer *p, *old_p;p = idp->top;if (!p)return ERR_PTR(-EINVAL);n = (p->layer+1) * IDR_BITS;id &= MAX_ID_MASK;if (id >= (1 << n))return ERR_PTR(-EINVAL);n -= IDR_BITS;while ((n > 0) && p) {p = p->ary[(id >> n) & IDR_MASK];n -= IDR_BITS;}n = id & IDR_MASK;if (unlikely(p == NULL || !test_bit(n, &p->bitmap)))return ERR_PTR(-ENOENT);old_p = p->ary[n];rcu_assign_pointer(p->ary[n], ptr);return old_p;}EXPORT_SYMBOL(idr_replace);
六.idr空闲链表的销毁
idr_destroy
void idr_destroy(struct idr *idp){while (idp->id_free_cnt) {struct idr_layer *p = get_from_free_list(idp);kmem_cache_free(idr_layer_cache, p);}}EXPORT_SYMBOL(idr_destroy);
七.用法
1.api函数
void *idr_find(struct idr *idp, int id);//查找id对应的指针int idr_pre_get(struct idr *idp, gfp_t gfp_mask);//分配idr_layer空闲链表int idr_get_new(struct idr *idp, void *ptr, int *id);//获取id,捆绑指针ptrint idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);//起始数值获取id,捆绑指针ptrint idr_for_each(struct idr *idp,int (*fn)(int id, void *p, void *data), void *data);void *idr_get_next(struct idr *idp, int *nextid);void *idr_replace(struct idr *idp, void *ptr, int id);//替换id捆绑的指针void idr_remove(struct idr *idp, int id);//移除idvoid idr_remove_all(struct idr *idp);//移除所有idvoid idr_destroy(struct idr *idp);//销毁idr_layer空闲链表void idr_init(struct idr *idp);//初始化idr
2.大致用法
1.idr_init声明设置idr
2.idr_pre_get分配空闲idr_layer链表
3.id_get_new/idr_get_new_above分配id并将id与指针ptr捆绑
4.利用idr_find根据id获取指针ptr
5.idr_remove/idr_remove_all移除分配的id
6.idr_destroy销毁空闲idr_layer链表
7.idr_replace替换id
- idr机制(32叉树)
- idr机制(32叉树)
- idr机制(32叉树)
- idr机制
- idr机制
- idr机制
- IDR机制
- idr机制
- IDR机制
- IDR机制
- IDR机制
- IDR机制
- linux idr机制
- linux idr机制
- linux的idr机制
- linux kernel idr机制
- linux idr机制
- idr机制-转载
- RC 资源文件
- 点击头部字母,滚动条跳转到相应的位置 jquery
- 【2013.1.24】我有一个梦想:有一天世界上全部电器都可以用一个充电器来充电——Adapter
- WIFI Calibration
- NesC学习经验总结:第三篇 如何调试NesC程序
- idr机制(32叉树)
- 理解WebKit和Chromium: 消息循环(Message Loop)
- NesC学习经验总结:第四篇 commands和events的用法与provide和use的关系
- CentOS Linux 远程终端ssh乱码问题
- MIni2440 各种资源整理
- TCP/IP RFCS
- How to Use Hive-based Registry IN WINCE.NET
- 杭电OJ题 1577 WisKey的眼神 解题报告
- 文件I/O操作----带与不带缓冲的I/O