15. C語言實現位圖 bitmap

1. 位圖是什麼?

位圖是一種資源管理的方式,按位bit與資源一對一的對應關係。

位圖中的每一位將於內存中的每一頁一一對應。
一個位有 2 種狀態,即 0 和 1 ,用位圖中的每一個位來表示實際物理內存的 4KB(一頁) 。

如果某位爲 0 ,表示該位對應的頁未分配。
反之,某位爲 1 ,表示該位對應的頁已分配。

2. 實現位圖

實現位圖,用到兩個文件,bitmap.c 和 bitmap.h。
bitmap.h 是關於位圖的定義和一些函數聲明。
bitmap.c 是操作位圖的一些函數。

bitmap.h

#ifndef __LIB_KERNEL_BITMAP_H
#define __LIB_KERNEL_BITMAP_H
#include "../std_int.h"
#include "../string.h"

#define BITMAP_MASK 1

struct bitmap {
   uint32_t btmp_bytes_len;
/* 在遍歷位圖時,整體上以字節爲單位,細節上是以位爲單位,所以此處位圖的指針必須是單字節 */
   uint8_t* bits;
};

void bitmap_init(struct bitmap* btmp);
bool bitmap_scan_test(struct bitmap* btmp, uint32_t bit_idx);
int bitmap_scan(struct bitmap* btmp, uint32_t cnt);
void bitmap_set(struct bitmap* btmp, uint32_t bit_idx, int8_t value);
#endif

bitmap.h 中定義一個結構體 struct bitmap, 它包含兩個元素,位圖的大小和位圖的地址。
通過這個結構體就能找到位圖。

bitmap.c

#include "bitmap.h"
#include "../std_int.h"
#include "../string.h"
#include "print.h"
#include "../../kernel/my_interrupt.h"
#include "../../kernel/debug.h"

/* 將位圖btmp初始化 */
void bitmap_init(struct bitmap* btmp) {
   memset(btmp->bits, 0, btmp->btmp_bytes_len);   
}

/* 判斷bit_idx位是否爲1,若爲1則返回true,否則返回false */
bool bitmap_scan_test(struct bitmap* btmp, uint32_t bit_idx) {
   uint32_t byte_idx = bit_idx / 8;    // 向下取整用於索引數組下標
   uint32_t bit_odd  = bit_idx % 8;    // 取餘用於索引數組內的位
   return (btmp->bits[byte_idx] & (BITMAP_MASK << bit_odd));
}

/* 在位圖中申請連續cnt個位,成功則返回其起始位下標,失敗返回-1 */
int bitmap_scan(struct bitmap* btmp, uint32_t cnt) {
   uint32_t idx_byte = 0;	 // 用於記錄空閒位所在的字節
/* 先逐字節比較,蠻力法 */
   while (( 0xff == btmp->bits[idx_byte]) && (idx_byte < btmp->btmp_bytes_len)) {
/* 1表示該位已分配,所以若爲0xff,則表示該字節內已無空閒位,向下一字節繼續找 */
      idx_byte++;
   }

   ASSERT(idx_byte < btmp->btmp_bytes_len);
   if (idx_byte == btmp->btmp_bytes_len) {  // 若該內存池找不到可用空間		
      return -1;
   }

 /* 若在位圖數組範圍內的某字節內找到了空閒位,
  * 在該字節內逐位比對,返回空閒位的索引。*/
   int idx_bit = 0;
 /* 和btmp->bits[idx_byte]這個字節逐位對比 */
   while ((uint8_t)(BITMAP_MASK << idx_bit) & btmp->bits[idx_byte]) { 
	 idx_bit++;
   }
	 
   int bit_idx_start = idx_byte * 8 + idx_bit;    // 空閒位在位圖內的下標
   if (cnt == 1) {
      return bit_idx_start;
   }

   uint32_t bit_left = (btmp->btmp_bytes_len * 8 - bit_idx_start);   // 記錄還有多少位可以判斷
   uint32_t next_bit = bit_idx_start + 1;
   uint32_t count = 1;	      // 用於記錄找到的空閒位的個數

   bit_idx_start = -1;	      // 先將其置爲-1,若找不到連續的位就直接返回
   while (bit_left-- > 0) {
      if (!(bitmap_scan_test(btmp, next_bit))) {	 // 若next_bit爲0
	 count++;
      } else {
	 count = 0;
      }
      if (count == cnt) {	    // 若找到連續的cnt個空位
	 bit_idx_start = next_bit - cnt + 1;
	 break;
      }
      next_bit++;          
   }
   return bit_idx_start;
}

/* 將位圖btmp的bit_idx位設置爲value */
void bitmap_set(struct bitmap* btmp, uint32_t bit_idx, int8_t value) {
   ASSERT((value == 0) || (value == 1));
   uint32_t byte_idx = bit_idx / 8;    // 向下取整用於索引數組下標
   uint32_t bit_odd  = bit_idx % 8;    // 取餘用於索引數組內的位

/* 一般都會用個0x1這樣的數對字節中的位操作,
 * 將1任意移動後再取反,或者先取反再移位,可用來對位置0操作。*/
   if (value) {		      // 如果value爲1
      btmp->bits[byte_idx] |= (BITMAP_MASK << bit_odd);
   } else {		      // 若爲0
      btmp->bits[byte_idx] &= ~(BITMAP_MASK << bit_odd);
   }
}

註釋中已經寫的很詳細了,就是一些對位圖的操作函數。

:本文實現的位圖,供以後內存管理時調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章