idr机制(32叉树)
来源:互联网 发布:托福 一个月 知乎 编辑:程序博客网 时间:2024/06/04 19:38
一.结构体
1.idr结构体
- struct idr {
- struct idr_layer __rcu *top; //idr_layer顶层,32叉树的根
- struct idr_layer *id_free; //指向idr_layer的空闲链表
- int layers; //idr_layer的层数量
- int id_free_cnt; //idr_layer空闲链表中剩余的idr_layer个数
- spinlock_t lock;
- };
2.idr_layer结构体
- struct idr_layer {
- unsigned long bitmap; //标记位图,标记使用情况
- struct idr_layer __rcu *ary[1<<IDR_BITS]; //子idr_layer数组ary[32]
- int count; //ary数组使用情况
- int layer; //层号
- struct rcu_head rcu_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=14
- struct 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_list
- spin_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=7
- int id;
- id = idr_get_empty_slot(idp, starting_id, pa); //-->idr_get_empty_slot
- if (id >= 0) {
- rcu_assign_pointer(pa[0]->ary[id & IDR_MASK],(struct idr_layer *)ptr
- //pa[0]->ary[0]=ptr 也就是idr_layer14->ary[0]=ptr
- pa[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; //按常规出牌吧,假设这个为0
- build_up:
- p = idp->top; //根top指向的idr_layer NULL
- layers = idp->layers; //获取layers层数量(0)
- if (unlikely(!p)) { //第一次运行idp->top=NULL,所以if条件为真,执行if分支的结果参考 图A
- if (!(p = get_from_free_list(idp))) //>>>1-->get_from_free_list 从根free中获取一个idr_layer14
- return -1;
- p->layer = 0; //指定idr_layer14的层号为0
- layers = 1; //layers层数量设为1
- }
- //layers<6 && id>=2^(layers*5) 看需不需要增加层数 见图B
- while ((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_layer14
- idp->layers = layers; //设置更新idr->layers层数量
- //----------------------------------------------分割线----------------------------------------------
- //以上部分主要处理layer相关,以下部分主要处理id相关
- v = sub_alloc(idp, &id, pa); //>>>2-->sub_alloc
- if (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_layer
- idp->id_free = p->ary[0]; //idr空闲链表指针指向第二个idr_layer
- idp->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; //根top
- l = idp->layers; //l=1
- pa[l--] = NULL; //p[1]=NULL;l=0
- while (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;
- else
- goto 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_layer14
- return 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)
- teq r1, #0
- beq 3b
- ands ip, r2, #7
- beq 1b @ If new byte, goto old routine
- ARM( ldrb r3, [r0, r2, lsr #3] )
- THUMB( lsr r3, r2, #3 )
- THUMB( ldrb r3, [r0, r3] )
- movs r3, r3, lsr ip @ shift off unused bits
- bne .L_found
- orr r2, r2, #7 @ if zero, then no bits here
- add r2, r2, #1 @ align bit pointer
- b 2b @ loop for next bit
- ENDPROC(_find_next_bit_le)
.L_found找到合适的跳转
- .L_found:
- #if __LINUX_ARM_ARCH__ >= 5
- rsb r0, r3, #0
- and r3, r3, r0
- clz r3, r3
- rsb r3, r3, #31
- add r0, r2, r3
- #else
- tst r3, #0x0f
- addeq r2, r2, #4
- movne r3, r3, lsl #4
- tst r3, #0x30
- addeq r2, r2, #2
- movne r3, r3, lsl #2
- tst r3, #0x40
- addeq r2, r2, #1
- mov r0, r2
- #endif
- cmp r1, r0 @ Clamp to maxbit
- movlo r0, r1
- mov pc, 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); //获取id
- if (id >= 0) {
- rcu_assign_pointer(pa[0]->ary[id & IDR_MASK],(struct idr_layer *)ptr);
- //pa[0]->ary[id]=ptr
- pa[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; //获取根top
- layers = idp->layers; //获取层数量 layers=1
- if (unlikely(!p)) { //FALSE
- if (!(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层的,所以之前的层的层号需要+1
- continue; //层数量也需要加1
- }
- if (!(new = get_from_free_list(idp))) { //空闲链表中获取新的idr_layer
- spin_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_layer
- new->count = 1; //新的idr_layer计数加1
- new->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); //设置根top
- idp->layers = layers; //更新层数量
- v = sub_alloc(idp, &id, pa); //获取id
- if (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; //获取根top
- l = idp->layers; //获取层数量l=1
- pa[l--] = NULL; //pa[1]=NULL,l=0
- while (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++; 层数+1
- oid = id;
- id = (id | ((1 << (5 * l)) - 1)) + 1; //id或上掩码再+1
- if (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;
- else
- goto restart;
- }
- if (m != n) { //期望id给用但有可用id
- sh = 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才为0
- break;
- if (!p->ary[m]) { //叶子m为空
- new = get_from_free_list(idp); //从空闲链表拿一个idr_layer
- if (!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); //获取根top
- if (!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,捆绑指针ptr
- int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); //起始数值获取id,捆绑指针ptr
- int 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); //移除id
- void idr_remove_all(struct idr *idp); //移除所有id
- void 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机制-转载
- android关于popupWindow不显示
- 编写模板函数求最大值
- 动态二维数组(C++)
- linux下各种解压方法
- Android中使用CountDownTimer封装CountDownUtil,制作一个简易定时器
- idr机制(32叉树)
- 每日vim系列0712
- (49)静态同步函数的锁是Class对象,例子:懒汉式--在多线程中存在问题--同步解决
- 日期和星期工具类
- ListView setAdapter has already been called 异常
- SG函数
- Android状态栏颜色修改,activity状态栏颜色,非布局写法
- SqlServerCLR聚合函数:分组连接字符串
- 轻松理解PV操作(转)