2009年6月12日 星期五

OS心得系列Memory Control Blocks--PART 1

為了便於記憶體的管理,在 uC/OS-II 中使用記憶體控制塊 (Memory Control Blocks, MCB) 的資料結構來跟蹤每一個記憶體分割區,系統中的每個記憶體分割區都有它自己的 MCB。程式清單 L7.1 是 memory control blocks (MCB) 的定義。

程式清單 L7.1 Memory Control Block (MCB) data structure
typedef struct {
void *OSMemAddr;
void *OSMemFreeList;
INT32U OSMemBlkSize;
INT32U OSMemNBlks;
INT32U OSMemNFree;
} OS_MEM;

.OSMemAddr 是指向記憶體分割區起始位址的指標。它在建立記憶體分割區 [見 OSMemCreate()] 時被初始化,在此之後就不能更改了。

.OSMemFreeList 是指向下一個未使用的記憶體控制塊或者下一個未使用的的記憶體塊的指標,具體含義要根據該記憶體分割區是否已經建立來決定。

.OSMemBlkSize 是記憶體分割區中記憶體塊的大小,是使用者建立該記憶體分割區時指定的。

.OSMemNBlks 是記憶體分割區中總的記憶體塊數量,也是使用者建立該記憶體分割區時指定的。

.OSMemNFree 是記憶體分割區中當前可以得未使用的記憶體塊數量。

如果要在 uC/OS-II 中使用記憶體管理,需要在 OS_CFG.H 檔案中將常數定義 OS_MEM_EN 設為 1。這樣 uC/OS-II 在啟動時就會對 memory manager 進行初始化 [由 OSInit() 呼叫 OSMemInit() 來實現]。該初始化主要建立一個如圖 F7.3 所示的 MCB link list,其中的常數定義 OS_MAX_MEM_PART (見檔案 OS_CFG.H) 定義了最大的記憶體分割區數,該常數值至少要為 2。



Creating a partition, OSMemCreate()

在使用一個記憶體分割區之前,必須先建立該記憶體分割區。這個操作可以透過呼叫 OSMemCreate() 函式來完成。程式清單 L7.2 說明了如何建立一個含有 100 個記憶體塊、每個記憶體塊 32 位元組的記憶體分割區。

程式清單 L7.2 Creating a memory partition


OS_MEM *CommTxBuf;
INT8U CommTxPart[100][32];

void main (void)
{
INT8U err;


OSInit();
.
.
CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err);
.
.
OSStart();
}

程式清單 L7.3 是 OSMemCreate() 函式的程式碼。該函式共有 4 個參數:記憶體分割區的起始位址、分區內的記憶體塊總塊數、每個記憶體塊的位元組數和一個指向錯誤資訊程式的指標。如果 OSMemCreate() 操作失敗,它將返回一個 NULL 指標。否則,它將返回一個指向記憶體控制塊的指標。對記憶體管理的其他操作,像 OSMemGet() ,OSMemPut(),OSMemQuery() 函式等,都需要透過該指標進行。

每個記憶體分割區必須含有至少兩個記憶體塊 [L7.3(1)],每個記憶體塊至少為一個指標的大小,因為同一分區中的所有未使用的記憶體塊是由指標串聯起來的 [L7.3(2)]。接著,OSMemCreate() 從系統中的未使用的 MCB list 中取得一個 MCB [L7.3(3)],該 MCB 包含相對應記憶體分割區的程式執行期的資訊。 OSMemCreate() 必須在有未使用的 MCB 可用的情況下才能建立一個記憶體分割區 [L7.3(4)]。在上述條件均得到滿足時,所要建立的記憶體分割區內的所有記憶體塊被鏈結成一個單向 link list [L7.3(5)]。然後,在相對應的 MCB 中填寫相對應的資訊 [L7.3(6)]。完成上述各動作後,OSMemCreate() 返回指向該記憶體塊的指標。使該指標在以後對記憶體塊的操作中使用[L7.3(6)] 。


程式清單 L7.3 OSMemCreate()
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
{
OS_MEM *pmem;
INT8U *pblk;
void **plink;
INT32U i;


if (nblks < 2) { (1)
*err = OS_MEM_INVALID_BLKS;
return ((OS_MEM *) 0);
}

if (blksize < sizeof(void *)) { (2)
*err = OS_MEM_INVALID_SIZE;
return ((OS_MEM *) 0);
}

OS_ENTER_CRITICAL();

pmem = OSMemFreeList; (3)

if (OSMemFreeList != (OS_MEM *) 0) {
OSMemFreeList = (OS_MEM *) OSMemFreeList->OSMemFreeList;
}

OS_EXIT_CRITICAL();

if (pmem == (OS_MEM *) 0) { (4)
*err = OS_MEM_INVALID_PART;
return ((OS_MEM *) 0);
}

plink = (void **) addr; (5)
pblk = (INT8U *) addr + blksize;

for (i = 0; i < (nblks - 1); i++) {
*plink = (void *) pblk;
plink = (void **) pblk;
pblk = pblk + blksize;
}

*plink = (void *) 0;

OS_ENTER_CRITICAL();

pmem->OSMemAddr = addr; (6)
pmem->OSMemFreeList = addr;
pmem->OSMemNFree = nblks;
pmem->OSMemNBlks = nblks;
pmem->OSMemBlkSize = blksize;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;
return (pmem); (7)
}


圖 F7.4 是 OSMemCreate() 函式執行完成後,MCB 及對應的記憶體分割區和分割區內的記憶體塊之間的關係。在程式執行期間,經過多次的記憶體分配和釋放後,同一分區內的各記憶體塊之間的鏈結順序會發生很大的變化。

沒有留言:

張貼留言