linux kernel idr機制

在我們實際編程中,有時候需要做這麼一件事情..就是一個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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章