在編寫應用層代碼中使用位圖,發現內核中已經有現成的實現便使用之。對位圖的使用主要是幾個git
關鍵API。github
第一:bitmap_zero函數用於初始化位圖函數
源碼以下:spa
/* *@dst: 位圖的起始地址 *@nbits: 位圖的個數 */
static inline void bitmap_zero(unsigned long *dst, int nbits) { int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); memset(dst, 0, len); }
第二:bitmap_set函數用於設置特定的位code
1 /* 2 * @map: 位圖的內存空間的首地址 3 * @start:須要設置的起始位 4 * @nr : 須要設置的位的數目 5 */ 6 void bitmap_set(unsigned long *map, int start, int nr) 7 { 8 unsigned long *p = map + BIT_WORD(start); //以unsigned long 爲單位的狀況,設置起始位置 9 const int size = start + nr; //須要設置的末位,不包括此位 10 /* 11 * @bits_to_set 在一個須要設置的unsigned long中,可能須要設置的位 12 * [0_____start_________BITS_PER_LONG) 13 * [0____________________bits_to_set) 14 */ 15 int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); 16 unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); 17 18 while (nr - bits_to_set >= 0) { 19 *p |= mask_to_set; 20 nr -= bits_to_set; 21 bits_to_set = BITS_PER_LONG; //通過上一步的操做後,須要設置的位都是BITS_PER_LONG的倍數 22 mask_to_set = ~0UL; 23 p++; 24 } 25 if (nr) { //nr 必須大於1,此函數纔有效果 26 mask_to_set &= BITMAP_LAST_WORD_MASK(size); 27 *p |= mask_to_set; //產生最終的效果 28 } 29 }
與bit_set函數相對應的是bit_clear函數用於清除位,其實現原理和bit_set函數相似。blog
第三:find_first_zero_bit函數用於找到第一個清空位內存
/* * Find the first cleared bit in a memory region. * @addr: 位圖的起始位置 * @size: 位圖的大小 */ unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) { const unsigned long *p = addr; unsigned long result = 0; unsigned long tmp; while (size & ~(BITS_PER_LONG-1)) { //位圖的大小超過一個 BIT_PER_LONG的狀況下 if (~(tmp = *(p++))) goto found; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) //此狀況成立的時候,也是沒有找到。且size應該是 BIT_PER_LONG的整數倍。 return result; tmp = (*p) | (~0UL << size); if (tmp == ~0UL) /* Are any bits zero? */ return result + size; /* Nope. */ //若是沒有找到就會返回 size found: return result + ffz(tmp); }
於此函數對應的是函數find_first_bit尋找第一個設置位。資源
第四:find_next_zero_bit 和 find_next_bit 函數能夠在第一次找到後,再次尋找清空位或設置位。get
具體使用狀況能夠參考:源碼
備註:
位圖除了應用於內存管理,還能夠應用到對共享資源的管理,LDD3的P128就有提到。