位图:
在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