find_next_zero_bit:
int find_next_zero_bit
(const unsigned long *addr, int size, int offset)
查詢*addr中,從第offset位開始,第一個不為0的位的位元(最低位從0開始)
,注: offset最小值為0,最大值為sizeof(unsigned long)*8 - 1
//why * 8??
sample:
例如尋找位元影像bitmap(共32位)的第5位開始第一個不為0的位的位元(查詢結果為5)
--
5
4 3 2 1 0
|---|---|---|---|---|---|
| 0
| 1 | 1 | 1 | 1 | 1 |
|---|---|---|---|---|---|
bitmap = 31 = 011111
---------------------------------------------------------------
#include //Needed by all modules
#include //Needed for KERN_ALERT
int init_module(void)
{
int devnum;
unsigned long bitmap = 31;
devnum = find_next_zero_bit(&bitmap, 32, 5);
printk("<1> devnum = %d/n", devnum);
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "Goodbye./n");
}
#define DECLARE_BITMAP(name,bits) /
unsigned long name[BITS_TO_LONGS(bits)]
http://blog.chinaunix.net/u1/38994/showart_2002937.html
函數原型解析:
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
long size,
unsigned long offset)
{
const unsigned
long *p = addr + BITOP_WORD(offset); // offset位於p指向的long地址32位空間
unsigned long result = offset & ~(BITS_PER_LONG-1); //
offset是第result個4位元組
unsigned long tmp;
if (offset >=
size)
return size;
size -=
result; // 調整32位整倍數上
offset
%= BITS_PER_LONG; // offset位於32位的第幾位
if (offset) { //
offset不在一個long資料的第0位上,在1-31位中[luther.gliethttp]
tmp = *(p++);
tmp |= ~0UL >> (BITS_PER_LONG - offset); //
將0-offset資料填充上1.
if (size <
BITS_PER_LONG) // 不足32bits
goto
found_first;
if (~tmp)
// 取非非0說明含有0值
goto found_middle;
size -=
BITS_PER_LONG; //
如果上面~tmp等於0,那麼說明該*p資料為32位全1.[luther.gliethttp]
result +=
BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1))
{ // 好了,執行到這裡,我們的offset已經處在4位元組的第0位上,下面進行
if
(~(tmp = *(p++))) //
4位元組快速查詢.如果~tmp非0,說明該32位元據中含有0資料,找到.[luther.gliethttp]
goto found_middle;
result +=
BITS_PER_LONG; // 到下一個4位元組空間
size -=
BITS_PER_LONG; // 減少4位元組資料
}
if
(!size) //
size等於0,說明首先size等於4位元組整倍數,其次所有資料已經查完,
return
result; //
所有資料全部為1,沒有發現0位,result等於size.[luther.gliethttp]
tmp =
*p; //
size不是32位整倍數,還剩幾個bit沒有檢查,繼續執行下面檢查工作.[luther.gliethtp]
found_first:
tmp |= ~0UL << size; //
現在0-size為有效資料,size-31為未使用空間,所以先將size-31置成全1.
if (tmp == ~0UL)
/* Are any bits zero? */ // 如果tmp全1,那麼說明就沒找找1個
return
result + size; /* Nope. */ //
result+size就等於函數傳入的參數size大小.[luther.gliethttp]
found_middle:
return result + ffz(tmp); //
我們在32位元據的0-31中發現必定存在0位值,計算他是第幾位.[luther.gliethttp]
}
#define
ffz(x) __ffs(~(x)) //
__ffs找到第一次出現1值的位移值,從bit0開始到bit31依次找[luther.gliethttp]
/**
* __ffs
- find first bit in word.
* @word: The word to search
*
*
Undefined if no bit exists, so code should check against 0 first.
*/
static
inline unsigned long __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) { //
低16位沒有1值,那麼num加16,同時高16位移動到低16位
num +=
16; //
這樣低16位永遠都是去掉根本不存在的那種必然情況後的資料.
word >>= 16;
}
if ((word & 0xff) == 0) { // 低8位是否有
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; //
這樣num就是出現1的位移值了.[luther.gliethttp]
}