find_next_bit函数解析

位图:
在Linux下,从数据结构上看,位图本质上是一个数组,数组的每个元素都是long型的(即32bit或64bit)。
在32bit系统中位图如下:
低地址:  31......0
        63......32
高地址:4095......4064

上图中的数字就是各个bit位的标号,即索引。
对于位图的操作,也就是对位图中bit位的操作。
从作用上说,位图通常与其它数据相关联,用位图中的bit位对该数据进行统计或管理。

在kernel4.14中从start开始找第一个0/1的index函数变得更简洁了。如果看不懂可以先看旧代码,就代码逻辑更清晰。

代码位置lib/find_bit.c
find_next_bit和find_next_zero_bit最终都调用了函数_find_next_bit,通过控制参数invert来实现找0或1.

find_next_bit和find_next_zero_bit代码如下,主要是就是参数invert的不同,没什么好说的。
 57 #ifndef find_next_bit
 58 /*
 59  * Find the next set bit in a memory region.
 60  */
 61 unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
 62                 unsigned long offset)
 63 {
 64     return _find_next_bit(addr, size, offset, 0UL);
 65 }
 66 EXPORT_SYMBOL(find_next_bit);
 67 #endif
 68 
 69 #ifndef find_next_zero_bit
 70 unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
 71                  unsigned long offset)
 72 {
 73     return _find_next_bit(addr, size, offset, ~0UL);
 74 }
 75 EXPORT_SYMBOL(find_next_zero_bit);
 76 #endif

重点是分析_find_next_bit,参数addr是保存位图的数组,nbits是最大有效的index(注可能不是32/64对齐的),start是开始的index,invert值确定要查找第一个0还是1。

 24 #if !defined(find_next_bit) || !defined(find_next_zero_bit)
 25 
 26 /*
 27  * This is a common helper function for find_next_bit and
 28  * find_next_zero_bit.  The difference is the "invert" argument, which
 29  * is XORed with each fetched word before searching it for one bits.
 30  */
 31 static unsigned long _find_next_bit(const unsigned long *addr,
 32         unsigned long nbits, unsigned long start, unsigned long invert)
 33 {
 34     unsigned long tmp;
 35 
 36     if (unlikely(start >= nbits))  //如果开始值就大于或等于最大有效的index,就直接返回最大index值
 37         return nbits;
 38 //通过start对long取整,找到从数组中的哪个元素开始找。
    //通过异或操作将要查找的0或1都转换成1,例:如查找第一个0,tmp中的值异或上一个全1的invert,tmp的bit值将会翻转,此时查1就是查0.
 39     tmp = addr[start / BITS_PER_LONG] ^ invert;
 40 
 41     /* Handle 1st word. */
 42     tmp &= BITMAP_FIRST_WORD_MASK(start);  //通过对start取余找到在本元素中的index,并将低于此index的bit都清0
 43     start = round_down(start, BITS_PER_LONG);  //通过round_down操作将start值对long取整,在具体元素中的哪个bit由__ffs来确定
 44 
 45     while (!tmp) {  //如果tmp值不全为0,则说明tmp中有bit为1,当然这个bit可能是超过最大值nbits的无效值。为0则说明此元素没有bit为1
 46         start += BITS_PER_LONG;  //将start值增加一个long
 47         if (start >= nbits)  //如果超过最大值nbits直接返回最大值,说明整个位图都没有要找的值
 48             return nbits;
 49 
 50         tmp = addr[start / BITS_PER_LONG] ^ invert;  //将下一个元素赋值给tmp,同时查找0/1统一为查1.
 51     }
 52 
 53     return min(start + __ffs(tmp), nbits);  //通过取bit为1的index和最大值nbits取小来去除掉大于nbits的无效值
 54 }
 55 #endif
 
 
 #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))  //(start) & (BITS_PER_LONG - 1)对long取余,同归对全1的左移完成将低于index的bit清0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值