在我們實際編程中,有時候需要做這麼一件事情..就是一個ID對應一個地址..就好像你的身份證對應你的人一樣,只要知道號.就能快速的找到與之對應的地址.有人說,用個數組不就行了..但是數組是定長的,不方便.那用鏈表行不行,鏈表行是行了.但是鏈表的查找很慢,尤其是數據一旦多了.又萬一要找的數據是最後一個,那咋辦..豈不是得遍歷每一個....有沒有什麼好的辦法能直接快速定位到要找的地址呢....
我們設想下.在32位操作系統中,典型的數據類型爲 int 也就是4字節.如果將這個4字節中的每一個位表示一個數據.那麼就可以用一個unsigned int來表示32個地址了.然後根據這個4字節內的值,就可以快速的找到對應的地址了...方便多了.但是這麼一來.只能存32個值...那如果將這個32個地址和對應的4字節的bitmap組成結構體.用bitmap描述一個32的數組....接着用bitmap原本描述地址的,用來存儲這個結構體本身..這樣構建起2層的樹形結構.豈不是可以描述1024個地址了..而頂層僅僅使用了一個4字節的bitmap來描述...又擴大了使用的地址範圍了...而繼續剛剛的,,1024 遠遠沒有達到4字節的最大值..那豈不是浪費..所以繼續增加樹的層數.3層樹那就是32768,4層樹就是1048576....6層就是1073741824 7層就超過4字節所能表達的最大值了...具體怎麼實現呢...下面就來分析下kernel中idr機制..就是上面描述的那樣...
首先我先聲明.我這裏分析的代碼是從linux2.6.36中提取出來的.並在vs2010中編譯測試過..由於kernel中有一些有的沒有函數.我去掉了...不影響整體..相信看懂這個代碼,再去看kernel會一目瞭然...
struct __idr_layer {
unsigned long bitmap; /* A zero bit means "space here" */
struct __idr_layer *ary[1<<IDR_BITS]; /* id對應的地址就存放在此處..id值爲bitmap中對應的位 */
int count; /* When zero, we can release it */
int layer; /* distance from leaf */
};
struct __idr {
struct __idr_layer* top; /* 執行頂層layer */
struct __idr_layer* id_free; /* 空閒layer存放處 */
int layers; /* only valid without concurrent changes 當前top的層數,用於遍歷到底層,存取葉節點 */
int id_free_cnt; /* 空閒區layer個數 */
#if defined(LINUX_LOCK)
pthread_mutex_t mutex_lock;
#endif
};
上面的就是idr所涉及的結構體..上面已經有了很多註釋了...其中LINUX_LOCK部分,是我自己修改的.因爲我的這段代碼提取出來主要用在應用程序中...所以定義了平臺相關的多線程同步機制..
/* 根據ID查找對應的地址 */
void* find(int id);
/* 操作之前的準備,用於申請layer,存入空閒區 */
int pre_get();
/* 將ptr對應id,id爲自動計算 */
int get_new(void *ptr, int *id);
/* 將ptr對應id,id爲starting_id開始的號 */
int get_new_above(void *ptr, int starting_id, int *id);
/* 遍歷每一個節點,並調用fn函數 */
int each(int (*fn)(int id, void *p, void *data), void *data);
/* 獲得nextidp的下一個地址,nextidp返回下一個id值 */
void* get_next(int *nextidp);
/* 替換指定ID值中的存儲地址 */
void* replace(void *ptr, int id);
/* 解除指定id值對應的地址 */
void remove(int id);
/* 清空top樹中所有的內容 */
void remove_all();
/* 清空整個idr,包涵free_layer區域 */
void destroy();
/* 初始化idr構建lock機制 */
void init();
上面就是idr的所有操作了..下面我們先看一下idr的基本使用方法.我們按照使用方法進行分析..
#include "idr.h"
int main(int argc, char* argv[])
{
idr _id;
int i = 10;
while(i--){
int ret = -10;
int id = i;
do{
if(_id.pre_get())
ret = _id.get_new((void*)i,&id);
}while(ret == -idr::EAGAIN);
}
i = 10;
void* val;
while(i--){
val = _id.find(i);
}
_id.destroy();
return 0;
}
參看代碼以及上面對函數的基本解釋.可以看懂這部分在幹什麼了..下面開始從構造函數idr::idr開始分析...
idr::idr(void)
{
init();
}
idr::~idr(void)
{
destroy();
}
void idr::destroy()
{
remove_all();
while (m_idp.id_free_cnt) {
struct __idr_layer *p = get_from_free_list(&m_idp); //清空free中的節點
delete p;
}
lock_destroy();
}
void idr::init()
{
memset(&m_idp, 0, sizeof(struct __idr));
lock_init();
}
構造函數僅僅就是將idr結構體清空,如果使用鎖機制,就初始化鎖...接着分析pre_get()函數.該函數是分配layer到空閒區域...已被在進行分配id->prt過程中隨時可以得到layer.
int idr::pre_get()
{
/* 循環申請layer,存入free_區域 */
while (m_idp.id_free_cnt < IDR_FREE_MAX) {
struct __idr_layer *nnew;
nnew = (struct __idr_layer*) new __idr_layer;
if (nnew == NULL)
return (0);
memset(nnew, 0, sizeof(struct __idr_layer));
move_to_free_list(&m_idp, nnew);
}
return 1;
}
void idr::__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++;
}
void idr::move_to_free_list(struct __idr *idp, struct __idr_layer *p)
{
// unsigned long flags;
/*
* Depends on the return element being zeroed.
*/
lock_lock();
__move_to_free_list(idp, p);
lock_unlock();
}
看的時候可以有些鬱悶,好我給大家看個圖..最終會變成這樣的佈局...
其中id_free_cnt等於14(這是一個宏.回頭看了代碼就知道了.是個固定值..)而layer形成了一個鏈表.每次idr需要取layer的時候,都直接取最後一個.然後id_free = id_free->ary[0];也就是之前一個.好.這個應該很好理解..
接着是get_new這個函數...這裏是整個idr的核心部分
int idr::get_new(void *ptr, int *id)
{
int rv;
/* 調用idr_get_new_above_int綁定id到ptr,id從0開始.自動計算 */
rv = idr_get_new_above_int(&m_idp, ptr, 0);
/*
* This is a cheap hack until the IDR code can be fixed to
* return proper error values.
*/
if (rv < 0)
return _idr_rc_to_errno(rv);
/* 返回新的id號 */
*id = rv;
return 0;
}
int idr::idr_get_new_above_int(struct __idr *idp, void *ptr, int starting_id)
{
struct __idr_layer *pa[MAX_LEVEL];
int id;
/*
根據starting_id獲取空閒id,會自動分配layer,以及樹的增長
pa中存放依次存放葉子節點到top的layer層次指針
*/
id = idr_get_empty_slot(&m_idp, starting_id, pa);
if (id >= 0) {
/*
* Successfully found an empty slot. Install the user
* pointer and mark the slot full.
*/
/* id關聯ptr */
pa[0]->ary[id & IDR_MASK] = (struct __idr_layer *)ptr;
pa[0]->count++;
/* 標誌該節點已被使用bitmap中置位 */
idr_mark_full(pa, id);
}
return id;
}
int idr::idr_get_empty_slot(struct __idr *idp, int starting_id,struct __idr_layer **pa)
{
struct __idr_layer *p, *nnew;
int layers, v, id;
id = starting_id;
build_up:
p = idp->top;
layers = idp->layers;
/* 如果第一次使用,則top爲NULL獲取top的layer. */
if (!p) {
if (!(p = get_from_free_list(idp)))
return -1;
p->layer = 0;
layers = 1;
}
/*
* Add a new layer to the top of the tree if the requested
* id is larger than the currently allocated space.
*/
while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
/* 樹增長 */
layers++;
if (!p->count) {
/* special case: if the tree is currently empty,
* then we grow the tree by moving the top node
* upwards.
*/
p->layer++;
continue;
}
/* 獲取新的layer,作爲top.將原本的top作爲該新的top的子節點 */
if (!(nnew = get_from_free_list(idp))) {
/*
* The allocation failed. If we built part of
* the structure tear it down.
*/
lock_lock();
for (nnew = p; p && p != idp->top; nnew = p) {
p = p->ary[0];
nnew->ary[0] = NULL;
nnew->bitmap = nnew->count = 0;
__move_to_free_list(idp, nnew);
}
lock_unlock();
return -1;
}
/* 設置新的top */
nnew->ary[0] = p;
nnew->count = 1;
nnew->layer = layers-1;
/* 若之前的top爲滿,則標誌該節點對應的這一位爲1 */
if (p->bitmap == IDR_FULL)
__set_bit(0, &nnew->bitmap);
p = nnew;
}
idp->top = p;
idp->layers = layers;
/* 獲取id.從idr樹中,會自動增加缺少的top的子節點 */
v = sub_alloc(idp, &id, pa);
if (v == IDR_NEED_TO_GROW)
goto build_up;
return(v);
}
void idr::idr_mark_full(struct __idr_layer **pa, int id)
{
struct __idr_layer *p = pa[0];
int l = 0;
/* 根據id設置bitmap */
__set_bit(id & IDR_MASK, &p->bitmap);
/*
* If this layer is full mark the bit in the layer above to
* show that this part of the radix tree is full. This may+ [0x6] 0x00000000 {bitmap=??? ary=0x00000004 count=??? ...} idr_layer *
* complete the layer above and require walking up the radix
* tree.
*/
/* 若整個layer節點爲滿,則標誌該layer的父節點對應的位爲1 */
while (p->bitmap == IDR_FULL) {
if (!(p = pa[++l]))
break;
id = id >> IDR_BITS;
__set_bit((id & IDR_MASK), &p->bitmap);
}
}
int idr::sub_alloc(struct __idr *idp, int *starting_id, struct __idr_layer **pa)
{
int n, m, sh;
struct __idr_layer *p, *nnew;
int l, id, oid;
unsigned long bm;
id = *starting_id;
restart:
p = idp->top;
l = idp->layers;
/* 設置最後一個爲NULL用於判斷到達頂層 */
pa[l--] = NULL;
while (1) {
/*
* We run around this while until we reach the leaf node...
*/
/* 計算n,爲該layer中的哪個位置(0~31) */
n = (id >> (IDR_BITS*l)) & IDR_MASK;
bm = ~p->bitmap;
/* 根據bm和n計算獲得下一個空閒位置 */
m = find_next_bit(&bm, IDR_SIZE, n);
/* 如果空閒位置==IDR_SIZE(32),表示已經滿了,則需要增長樹 */
if (m == IDR_SIZE) {
/* no space available go back to previous layer. */
l++;
oid = id;
/* 重新計算id,該id爲被增長之後的新值 */
id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
/* if already at the top layer, we need to grow */
if (id >= 1 << (idp->layers * IDR_BITS)) {
*starting_id = id;
/* 返回上一層,增長樹 */
return IDR_NEED_TO_GROW;
}
p = pa[l];
// BUG_ON(!p);
/* If we need to go up one layer, continue the
* loop; otherwise, restart from the top.
*/
sh = IDR_BITS * (l + 1);
if (oid >> sh == id >> sh)
continue;
else
goto restart;
}
/* 調整id號 */
if (m != n) {
sh = IDR_BITS*l;
id = ((id >> sh) ^ n ^ m) << sh;
}
if ((id >= MAX_ID_BIT) || (id < 0))
return IDR_NOMORE_SPACE;
/* 最終所有的操作,都會循環到l==0這邊.因爲所有的ptr地址,都保存在第0層的頁節點上 */
if (l == 0)
break;
/*
* Create the layer below if it is missing.
*/
/* 新增缺少的layer節點,並根據id獲取對應的節點 */
if (!p->ary[m]) {
nnew = get_from_free_list(idp);
if (!nnew)
return -1;
nnew->layer = l-1;
p->ary[m] = nnew;
p->count++;
}
/* 指向下層新的layer節點,保存p地址,到pa中 */
pa[l--] = p;
p = p->ary[m];
}
pa[l] = p;
return id;
}
我大部分都已經註釋了...下面看下在單層情況下是什麼佈局
在idr.layers == 1 的情況就是上面這圖所示,所有的ptr都落在ary對應的地址區域...而對應得到的id值就是0到31.也就是5位..用4字節的低5位表示0到31 這32個地址對應的區域..下面再看下2層的情況
從前副圖中,我們總結下..在1層中,id最大值爲1 << 5(32只需要5個二進制位) * 1 = 在2層中1 << 5(32只需要5個二進制位) * 2 在2層的情況中,僅僅覆蓋了4字節中的32^3次方 32768 個id號..所以這顆樹可以繼續增長..直到4字節的最大值
好..看下第三層的圖示吧...這也是最後一張圖了..剩下的沒有畫..太大了...繼續想象吧...
我們從3層中想象下,如何通過id來找到指定的ptr.首先假設id值爲12345;對應的二進制爲0b 1 00110 10011 我們說過每5位表示一個layer的底層32位值.把麼首先從頂層0b1找到idr->top.ary[1]->ary[0b00110]->ary[10011]得到的,就是該id對應的ptr了...
void* idr::find(int id)
{
int n;
struct __idr_layer *p;
/* p指向頂層 */
p = m_idp.top;
if (!p)
return NULL;
/* 計算當前整顆樹能放置多少頁節點 */
n = (p->layer+1) * IDR_BITS;
/* Mask off upper bits we don't use for the search. */
id &= MAX_ID_MASK;
if (id >= (1 << n))
return NULL;
/* 從id中每IDR_BITS對應一個地址,從top開始,依次取出layer找到底層的layer獲取ptr地址 */
while (n > 0 && p) {
n -= IDR_BITS;
p = p->ary[(id >> n) & IDR_MASK];
}
return((void *)p);
}
爲了驗證我說的是不是對的,直接看下代碼.來看看find函數是怎麼找到id對應的ptr的....上面已經有註釋了,就不多說了....
到這裏大部分已經講完了..剩下的部分.自己慢慢分析了....最後我貼出我整理的代碼..希望能幫助大家...謝謝
idr.h
#ifndef __IDR_H__
#define __IDR_H__
/* 定義系統平臺 */
#define SYSTEM_LINUX 1
#define SYSTEM_WINDOWS 2
/* 選擇系統平臺 */
#define SYSTEM_TYPE SYSTEM_WINDOWS
#define BITS_PER_LONG 32
#define USE_LOCK
/* 使用多線程鎖機制 */
#if defined(USE_LOCK)
# if SYSTEM_TYPE == SYSTEM_LINUX
# define LINUX_LOCK
# endif /* SYSTEM_TYPE == SYSTEM_LINUX */
#endif /* defined(USE_LOCK) */
/* 包含系統平臺頭文件 */
#if defined(LINUX_LOCK)
#include <pthread.h>
#endif /* defined(LINUX_LOCK) */
#if BITS_PER_LONG == 32
# define IDR_BITS 5
# define IDR_FULL 0xfffffffful
/* We can only use two of the bits in the top level because there is
only one possible bit in the top level (5 bits * 7 levels = 35
bits, but you only use 31 bits in the id). */
# define TOP_LEVEL_FULL (IDR_FULL >> 30)
#elif BITS_PER_LONG == 64
# define IDR_BITS 6
# define IDR_FULL 0xfffffffffffffffful
/* We can only use two of the bits in the top level because there is
only one possible bit in the top level (6 bits * 6 levels = 36
bits, but you only use 31 bits in the id). */
# define TOP_LEVEL_FULL (IDR_FULL >> 62)
#else
# error "BITS_PER_LONG is not 32 or 64"
#endif /* BITS_PER_LONG == 32 */
#define IDR_SIZE (1 << IDR_BITS)
#define IDR_MASK ((1 << IDR_BITS)-1)
#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
#define MAX_ID_MASK (MAX_ID_BIT - 1)
/* Leave the possibility of an incomplete final layer */
#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
/* Number of id_layer structs to leave in free list */
/* 最大空閒區域layer個數 */
#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
#define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC)
#define IDR_NEED_TO_GROW -2
#define IDR_NOMORE_SPACE -3
class idr
{
struct __idr_layer {
unsigned long bitmap; /* A zero bit means "space here" */
struct __idr_layer *ary[1<<IDR_BITS]; /* id對應的地址就存放在此處..id值爲bitmap中對應的位 */
int count; /* When zero, we can release it */
int layer; /* distance from leaf */
};
struct __idr {
struct __idr_layer* top; /* 執行頂層layer */
struct __idr_layer* id_free; /* 空閒layer存放處 */
int layers; /* only valid without concurrent changes 當前top的層數,用於遍歷到底層,存取葉節點 */
int id_free_cnt; /* 空閒區layer個數 */
#if defined(LINUX_LOCK)
pthread_mutex_t mutex_lock;
#endif
};
/* 定義互斥鎖操作函數 */
#if defined(LINUX_LOCK)
#define lock_init() pthread_mutex_init(&m_idp.mutex_lock,NULL);
#define lock_destroy() pthread_mutex_destroy(&m_idp.mutex_lock);
#define lock_lock() pthread_mutex_lock(&m_idp.mutex_lock);
#define lock_unlock() pthread_mutex_unlock(&m_idp.mutex_lock);
#else
#define lock_init()
#define lock_destroy()
#define lock_lock()
#define lock_unlock()
#endif
public:
enum {EAGAIN = 1,ENOSPC = 2,EINVAL = 3,ENOENT = 4};
public:
idr(void);
~idr(void);
public:
/* 根據ID查找對應的地址 */
void* find(int id);
/* 操作之前的準備,用於申請layer,存入空閒區 */
int pre_get();
/* 將ptr對應id,id爲自動計算 */
int get_new(void *ptr, int *id);
/* 將ptr對應id,id爲starting_id開始的號 */
int get_new_above(void *ptr, int starting_id, int *id);
/* 遍歷每一個節點,並調用fn函數 */
int each(int (*fn)(int id, void *p, void *data), void *data);
/* 獲得nextidp的下一個地址,nextidp返回下一個id值 */
void* get_next(int *nextidp);
/* 替換指定ID值中的存儲地址 */
void* replace(void *ptr, int id);
/* 解除指定id值對應的地址 */
void remove(int id);
/* 清空top樹中所有的內容 */
void remove_all();
/* 清空整個idr,包涵free_layer區域 */
void destroy();
/* 初始化idr構建lock機制 */
void init();
private:
/* 從free_layer中取出一個layer */
struct __idr_layer* get_from_free_list(struct __idr *idp);
/* 將layer->p 存放到指定的idr的空閒區中,此處僅僅是加鎖而已 */
void move_to_free_list(struct __idr *idp, struct __idr_layer *p);
/* 將layer->p 存放到指定的idr的空閒區中,若使用鎖機制,保證該函數被執行在加鎖中 */
void __move_to_free_list(struct __idr *idp, struct __idr_layer *p);
/* */
int idr_get_new_above_int(struct __idr *idp, void *ptr, int starting_id);
/* 從指定的id號開始,去獲取空閒的id對應的位置,返回空閒的id號 */
int idr_get_empty_slot(struct __idr *idp, int starting_id,struct __idr_layer **pa);
/* 設置id號對應的位被置位,並且如果是多層樹結構,則該層滿之後,將上層置位 */
void idr_mark_full(struct __idr_layer **pa, int id);
/* 置位 */
void __set_bit(int nr, volatile unsigned long *addr);
/* 清除位 */
void __clear_bit(int nr, volatile unsigned long *addr);
/* 測試位 */
int test_bit(unsigned int nr, const unsigned long *addr);
/* 子葉分配,以及計算id值,並返回id值..pa爲數組.從0->依次存放該節點的父節點指針 */
int sub_alloc(struct __idr *idp, int *starting_id, struct __idr_layer **pa);
/* 找到下一個可用的位,並返回該位的編號 */
unsigned long find_next_bit( const unsigned long *addr, unsigned long size,
unsigned long offset);
unsigned long __ffs(unsigned long word);
int fls(int x);
inline void* ERR_PTR(long error)
{
return (void *) error;
}
void free_layer(struct __idr_layer *p);
void sub_remove(struct __idr *idp, int shift, int id);
void idr_remove_warning(int id);
private:
struct __idr m_idp;
};
#endif /* __IDR_H__ */
idr.cpp
#include "idr.h"
#include <cstring>
idr::idr(void)
{
init();
}
idr::~idr(void)
{
destroy();
}
void* idr::find(int id)
{
int n;
struct __idr_layer *p;
/* p指向頂層 */
p = m_idp.top;
if (!p)
return NULL;
/* 計算當前整顆樹能放置多少頁節點 */
n = (p->layer+1) * IDR_BITS;
/* Mask off upper bits we don't use for the search. */
id &= MAX_ID_MASK;
if (id >= (1 << n))
return NULL;
/* 從id中每IDR_BITS對應一個地址,從top開始,依次取出layer找到底層的layer獲取ptr地址 */
while (n > 0 && p) {
n -= IDR_BITS;
p = p->ary[(id >> n) & IDR_MASK];
}
return((void *)p);
}
int idr::pre_get()
{
/* 循環申請layer,存入free_區域 */
while (m_idp.id_free_cnt < IDR_FREE_MAX) {
struct __idr_layer *nnew;
nnew = (struct __idr_layer*) new __idr_layer;
if (nnew == NULL)
return (0);
memset(nnew, 0, sizeof(struct __idr_layer));
move_to_free_list(&m_idp, nnew);
}
return 1;
}
int idr::get_new(void *ptr, int *id)
{
int rv;
/* 調用idr_get_new_above_int綁定id到ptr,id從0開始.自動計算 */
rv = idr_get_new_above_int(&m_idp, ptr, 0);
/*
* This is a cheap hack until the IDR code can be fixed to
* return proper error values.
*/
if (rv < 0)
return _idr_rc_to_errno(rv);
/* 返回新的id號 */
*id = rv;
return 0;
}
int idr::get_new_above(void *ptr, int starting_id, int *id)
{
int rv;
/* 調用idr_get_new_above_int綁定id到ptr,id從starting_id開始.自動計算 */
rv = idr_get_new_above_int(&m_idp, ptr, starting_id);
/*
* This is a cheap hack until the IDR code can be fixed to
* return proper error values.
*/
if (rv < 0)
return _idr_rc_to_errno(rv);
/* 返回新的id號 */
*id = rv;
return 0;
}
int idr::each(int (*fn)(int id, void *p, void *data), void *data)
{
int n, id, max, error = 0;
struct __idr_layer *p;
struct __idr_layer *pa[MAX_LEVEL];
struct __idr_layer **paa = &pa[0];
n = m_idp.layers * IDR_BITS;
/* p指向top */
p = m_idp.top;
/* 計算頁節點的最大數量 */
max = 1 << n;
id = 0;
while (id < max) {
while (n > 0 && p) {
n -= IDR_BITS;
*paa++ = p;
p = p->ary[(id >> n) & IDR_MASK];
}
/* callback函數調用 */
if (p) {
error = fn(id, (void *)p, data);
if (error)
break;
}
id += 1 << n;
while (n < fls(id)) {
n += IDR_BITS;
p = *--paa;
}
}
return error;
}
void* idr::get_next(int *nextidp)
{
struct __idr_layer *p, *pa[MAX_LEVEL];
struct __idr_layer **paa = &pa[0];
int id = *nextidp;
int n, max;
/* find first ent */
n = m_idp.layers * IDR_BITS;
max = 1 << n;
p = m_idp.top;
if (!p)
return NULL;
while (id < max) {
while (n > 0 && p) {
n -= IDR_BITS;
*paa++ = p;
p = p->ary[(id >> n) & IDR_MASK];
}
if (p) {
*nextidp = id;
return p;
}
id += 1 << n;
while (n < fls(id)) {
n += IDR_BITS;
p = *--paa;
}
}
return NULL;
}
void* idr::replace(void *ptr, int id)
{
int n;
struct __idr_layer *p, *old_p;
p = m_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);
/* 找到id對應的layer節點 */
n -= IDR_BITS;
while ((n > 0) && p) {
p = p->ary[(id >> n) & IDR_MASK];
n -= IDR_BITS;
}
n = id & IDR_MASK;
if (p == NULL || !test_bit(n, &p->bitmap))
return ERR_PTR(-ENOENT);
/* 替換id對應的ptr爲新的ptr */
old_p = p->ary[n];
p->ary[n] = (__idr_layer*)ptr;
/* 返回舊的ptr地址 */
return old_p;
}
void idr::remove(int id)
{
struct __idr_layer *p;
struct __idr_layer *to_free;
/* Mask off upper bits we don't use for the search. */
id &= MAX_ID_MASK;
sub_remove(&m_idp, (m_idp.layers - 1) * IDR_BITS, id);
if (m_idp.top && m_idp.top->count == 1 && (m_idp.layers > 1) &&
m_idp.top->ary[0]) {
/*
* Single child at leftmost slot: we can shrink the tree.
* This level is not needed anymore since when layers are
* inserted, they are inserted at the top of the existing
* tree.
*/
to_free = m_idp.top;
p = m_idp.top->ary[0];
m_idp.top = p;
--m_idp.layers;
to_free->bitmap = to_free->count = 0;
free_layer(to_free);
}
while (m_idp.id_free_cnt >= IDR_FREE_MAX) {
p = get_from_free_list(&m_idp);
/*
* Note: we don't call the rcu callback here, since the only
* layers that fall into the freelist are those that have been
* preallocated.
*/
delete p;
}
return;
}
void idr::remove_all()
{
int n, id, max;
int bt_mask;
struct __idr_layer *p;
struct __idr_layer *pa[MAX_LEVEL];
struct __idr_layer **paa = &pa[0];
n = m_idp.layers * IDR_BITS;
p = m_idp.top;
m_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;
}
}
m_idp.layers = 0;
}
void idr::destroy()
{
remove_all();
while (m_idp.id_free_cnt) {
struct __idr_layer *p = get_from_free_list(&m_idp);
delete p;
}
lock_destroy();
}
void idr::init()
{
memset(&m_idp, 0, sizeof(struct __idr));
lock_init();
}
/***************************private function****************************/
idr::__idr_layer* idr::get_from_free_list(struct __idr *idp)
{
struct __idr_layer *p;
lock_lock();
if ((p = m_idp.id_free)) {
/* 從空閒區摘取一個layer */
m_idp.id_free = p->ary[0];
m_idp.id_free_cnt--;
p->ary[0] = NULL;
}
lock_unlock();
return(p);
}
void idr::__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++;
}
void idr::move_to_free_list(struct __idr *idp, struct __idr_layer *p)
{
// unsigned long flags;
/*
* Depends on the return element being zeroed.
*/
lock_lock();
__move_to_free_list(idp, p);
lock_unlock();
}
int idr::idr_get_new_above_int(struct __idr *idp, void *ptr, int starting_id)
{
struct __idr_layer *pa[MAX_LEVEL];
int id;
/*
根據starting_id獲取空閒id,會自動分配layer,以及樹的增長
pa中存放依次存放葉子節點到top的layer層次指針
*/
id = idr_get_empty_slot(&m_idp, starting_id, pa);
if (id >= 0) {
/*
* Successfully found an empty slot. Install the user
* pointer and mark the slot full.
*/
/* id關聯ptr */
pa[0]->ary[id & IDR_MASK] = (struct __idr_layer *)ptr;
pa[0]->count++;
/* 標誌該節點已被使用bitmap中置位 */
idr_mark_full(pa, id);
}
return id;
}
int idr::idr_get_empty_slot(struct __idr *idp, int starting_id,struct __idr_layer **pa)
{
struct __idr_layer *p, *nnew;
int layers, v, id;
id = starting_id;
build_up:
p = idp->top;
layers = idp->layers;
/* 如果第一次使用,則top爲NULL獲取top的layer. */
if (!p) {
if (!(p = get_from_free_list(idp)))
return -1;
p->layer = 0;
layers = 1;
}
/*
* Add a new layer to the top of the tree if the requested
* id is larger than the currently allocated space.
*/
while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
/* 樹增長 */
layers++;
if (!p->count) {
/* special case: if the tree is currently empty,
* then we grow the tree by moving the top node
* upwards.
*/
p->layer++;
continue;
}
/* 獲取新的layer,作爲top.將原本的top作爲該新的top的子節點 */
if (!(nnew = get_from_free_list(idp))) {
/*
* The allocation failed. If we built part of
* the structure tear it down.
*/
lock_lock();
for (nnew = p; p && p != idp->top; nnew = p) {
p = p->ary[0];
nnew->ary[0] = NULL;
nnew->bitmap = nnew->count = 0;
__move_to_free_list(idp, nnew);
}
lock_unlock();
return -1;
}
/* 設置新的top */
nnew->ary[0] = p;
nnew->count = 1;
nnew->layer = layers-1;
/* 若之前的top爲滿,則標誌該節點對應的這一位爲1 */
if (p->bitmap == IDR_FULL)
__set_bit(0, &nnew->bitmap);
p = nnew;
}
idp->top = p;
idp->layers = layers;
/* 獲取id.從idr樹中,會自動增加缺少的top的子節點 */
v = sub_alloc(idp, &id, pa);
if (v == IDR_NEED_TO_GROW)
goto build_up;
return(v);
}
void idr::idr_mark_full(struct __idr_layer **pa, int id)
{
struct __idr_layer *p = pa[0];
int l = 0;
/* 根據id設置bitmap */
__set_bit(id & IDR_MASK, &p->bitmap);
/*
* If this layer is full mark the bit in the layer above to
* show that this part of the radix tree is full. This may+ [0x6] 0x00000000 {bitmap=??? ary=0x00000004 count=??? ...} idr_layer *
* complete the layer above and require walking up the radix
* tree.
*/
/* 若整個layer節點爲滿,則標誌該layer的父節點對應的位爲1 */
while (p->bitmap == IDR_FULL) {
if (!(p = pa[++l]))
break;
id = id >> IDR_BITS;
__set_bit((id & IDR_MASK), &p->bitmap);
}
}
int idr::sub_alloc(struct __idr *idp, int *starting_id, struct __idr_layer **pa)
{
int n, m, sh;
struct __idr_layer *p, *nnew;
int l, id, oid;
unsigned long bm;
id = *starting_id;
restart:
p = idp->top;
l = idp->layers;
/* 設置最後一個爲NULL用於判斷到達頂層 */
pa[l--] = NULL;
while (1) {
/*
* We run around this while until we reach the leaf node...
*/
/* 計算n,爲該layer中的哪個位置(0~31) */
n = (id >> (IDR_BITS*l)) & IDR_MASK;
bm = ~p->bitmap;
/* 根據bm和n計算獲得下一個空閒位置 */
m = find_next_bit(&bm, IDR_SIZE, n);
/* 如果空閒位置==IDR_SIZE(32),表示已經滿了,則需要增長樹 */
if (m == IDR_SIZE) {
/* no space available go back to previous layer. */
l++;
oid = id;
/* 重新計算id,該id爲被增長之後的新值 */
id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
/* if already at the top layer, we need to grow */
if (id >= 1 << (idp->layers * IDR_BITS)) {
*starting_id = id;
/* 返回上一層,增長樹 */
return IDR_NEED_TO_GROW;
}
p = pa[l];
// BUG_ON(!p);
/* If we need to go up one layer, continue the
* loop; otherwise, restart from the top.
*/
sh = IDR_BITS * (l + 1);
if (oid >> sh == id >> sh)
continue;
else
goto restart;
}
/* 調整id號 */
if (m != n) {
sh = IDR_BITS*l;
id = ((id >> sh) ^ n ^ m) << sh;
}
if ((id >= MAX_ID_BIT) || (id < 0))
return IDR_NOMORE_SPACE;
/* 最終所有的操作,都會循環到l==0這邊.因爲所有的ptr地址,都保存在第0層的頁節點上 */
if (l == 0)
break;
/*
* Create the layer below if it is missing.
*/
/* 新增缺少的layer節點,並根據id獲取對應的節點 */
if (!p->ary[m]) {
nnew = get_from_free_list(idp);
if (!nnew)
return -1;
nnew->layer = l-1;
p->ary[m] = nnew;
p->count++;
}
/* 指向下層新的layer節點,保存p地址,到pa中 */
pa[l--] = p;
p = p->ary[m];
}
pa[l] = p;
return id;
}
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
void idr::__set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
int idr::test_bit(unsigned int nr, const unsigned long *addr)
{
return ((1UL << (nr % BITS_PER_LONG)) &
(((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
}
void idr::__clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p &= ~mask;
}
unsigned long idr::find_next_bit( const unsigned long *addr, unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BIT_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < BITS_PER_LONG)
goto found_first;
if (tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
if ((tmp = *(p++)))
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp &= (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
}
unsigned long idr::__ffs(unsigned long word)
{
int num = 0;
#if BITS_PER_LONG == 64
if ((word & 0xffffffff) == 0) {
num += 32;
word >>= 32;
}
#endif
if ((word & 0xffff) == 0) {
num += 16;
word >>= 16;
}
if ((word & 0xff) == 0) {
num += 8;
word >>= 8;
}
if ((word & 0xf) == 0) {
num += 4;
word >>= 4;
}
if ((word & 0x3) == 0) {
num += 2;
word >>= 2;
}
if ((word & 0x1) == 0)
num += 1;
return num;
}
int idr::fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
void idr::sub_remove(struct __idr *idp, int shift, int id)
{
struct __idr_layer *p = idp->top;
struct __idr_layer **pa[MAX_LEVEL];
struct __idr_layer ***paa = &pa[0];
struct __idr_layer *to_free;
int n;
*paa = NULL;
*++paa = &idp->top;
while ((shift > 0) && p) {
n = (id >> shift) & IDR_MASK;
__clear_bit(n, &p->bitmap);
*++paa = &p->ary[n];
p = p->ary[n];
shift -= IDR_BITS;
}
n = id & IDR_MASK;
if (p != NULL && test_bit(n, &p->bitmap)){
__clear_bit(n, &p->bitmap);
p->ary[n] = NULL;
to_free = NULL;
while(*paa && ! --((**paa)->count)){
if (to_free)
free_layer(to_free);
to_free = **paa;
**paa-- = NULL;
}
if (!*paa)
idp->layers = 0;
if (to_free)
free_layer(to_free);
} else
idr_remove_warning(id);
}
void idr::free_layer(struct __idr_layer *p)
{
}
void idr::idr_remove_warning(int id)
{
// printf("idr_remove called for id=%d which is not allocated.\n", id);
}