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]
}