2009年6月12日 星期五

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

Obtaining a memory block, OSMemGet()

應用程式可以呼叫 OSMemGet() 函式從已經建立的記憶體分割區中申請一個記憶體塊。該函式的唯一參數是指向特定記憶體分割區的指標,該指標是在建立記憶體分割區時,由 OSMemCreate() 函式所返回。顯然的,應用程式必須知道記憶體塊的大小,並且在使用時不能超過該容量。例如,如果一個記憶體分割區內的記憶體塊為 32 位元組,那麼,應用程式最多只能使用該記憶體塊中的 32 位元組。當應用程式不再使用這個記憶體塊後,必須及時把它釋放,重新放回相對應的記憶體分割區中 [見 OSMemPut()]。

程式清單 L7.4 是 OSMemGet() 函式的程式碼。參數中的指標pmem 指向使用者希望從其中分配記憶體塊的記憶體分割區[L7.4(1)] 。OSMemGet() 首先檢查記憶體分割區中是否有未使用的的記憶體塊[L7.4(2)] 。如果有,從未使用的記憶體塊鏈表中刪除第一個記憶體塊[L7.4(3)] ,並對未使用的記憶體塊鏈表作相應的修改 [L7.4(4)] 。這包括將鏈表頭指標後移一個元素和未使用的記憶體塊數減1[L7.4(5)] 。最後,返回指向被分配記憶體塊的指標[L7.4(6)] 。

程式清單 L7.4 OSMemGet()


void *OSMemGet (OS_MEM *pmem, INT8U *err) (1)
{
void *pblk;


OS_ENTER_CRITICAL();

if (pmem->OSMemNFree > 0) { (2)
pblk = pmem->OSMemFreeList; (3)
pmem->OSMemFreeList = *(void **) pblk; (4)
pmem->OSMemNFree--; (5)

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;
return (pblk); (6)

} else {
OS_EXIT_CRITICAL();

*err = OS_MEM_NO_FREE_BLKS;
return ((void *) 0);
}
}


值得注意的是,使用者可以在 ISR 中呼叫 OSMemGet(),因為在暫時沒有記憶體塊可用的情況下,OSMemGet() 不會等待,而是馬上返回 NULL 指標。

Returning a memory block, OSMemPut()

當使用者應用程式不再使用一個記憶體塊時,必須及時地把它釋放並放回到原本的記憶體分割區中。這個操作由 OSMemPut() 函式完成。必須注意的是,OSMemPut() 並不知道一個記憶體塊是屬於哪個記憶體分割區的。例如,使用者的 task 從一個包含 32 位元組記憶體塊的分區中分配了一個記憶體塊,用完後,把它返還給了一個包含 120 位元組記憶體塊的記憶體分割區。當使用者應用程式下一次申請 120 位元組分區中的一個記憶體塊時,它會只得到 32 位元組的可用空間,其他 88 位元組屬於其他的 task,這就有可能使系統崩潰。

程式清單 L7.5 是 OSMemPut() 函式的程式碼。它的第一個參數 pmem 是指向 MCB 的指標,也即記憶體塊屬於的記憶體分割區 [L7.5(1)]。OSMemPut() 首先檢查記憶體分割區是否已滿 [L7.5(2)]。如果已滿,說明系統在分配和釋放記憶體時出現了錯誤。如果未滿,要釋放的記憶體塊被插入到該分區的未使用的 MCB link list 中 [L7.5(3)]。最後,將分區中未使用的記憶體塊總數加 1 [L7.5(4)]。

程式清單 L7.5 OSMemPut()


INT8U OSMemPut (OS_MEM *pmem, void *pblk) (1)
{
OS_ENTER_CRITICAL();

if (pmem->OSMemNFree >= pmem->OSMemNBlks) { (2)
OS_EXIT_CRITICAL();
return (OS_MEM_FULL);
}

*(void **) pblk = pmem->OSMemFreeList; (3)
pmem->OSMemFreeList = pblk;
pmem->OSMemNFree++; (4)

OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}


Obtaining status about memory partition, OSMemQuery()

在 uC/OS-II 中,可以使用 OSMemQuery() 函式來查詢一個特定記憶體分割區的有關消息。透過該函式可以知道特定記憶體分割區中記憶體塊的大小、可用記憶體塊數和正在使用的記憶體塊數等資訊。所有這些資訊都放在一個叫 OS_MEM_DATA 的資料結構中,如程式清單 L7.6。

程式清單 L7.6 Data structure used to obtain status from a partition


typedef struct {
void *OSAddr; /* 指向記憶體分割區第一個位址的指標 */
void *OSFreeList; /* 指向未使用的 MCB link list 第一個位址的指標 */
INT32U OSBlkSize; /* 每個記憶體塊所含的位元組數 */
INT32U OSNBlks; /* 記憶體分割區總的記憶體塊數 */
INT32U OSNFree; /* 未使用的記憶體塊總數 */
INT32U OSNUsed; /* 正在使用的記憶體塊總數 */
} OS_MEM_DATA;


程式清單 L7.7 是 OSMemQuery() 函式的程式碼,它將指定記憶體分割區的資訊複製到 OS_MEM_DATA 定義的相對應變數中。在此之前,程式首先禁止了外部中斷,防止複製過程中某些變數值被修改 [L7.7(1)]。由於正在使用的記憶體塊數是由 OS_MEM_DATA 中的局部變數計算得到的,所以,可以放在 critical section 的外面。

程式清單 L7.7 OSMemQuery()


INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata)
{
OS_ENTER_CRITICAL();

pdata->OSAddr = pmem->OSMemAddr; (1)
pdata->OSFreeList = pmem->OSMemFreeList;
pdata->OSBlkSize = pmem->OSMemBlkSize;
pdata->OSNBlks = pmem->OSMemNBlks;
pdata->OSNFree = pmem->OSMemNFree;

OS_EXIT_CRITICAL();

pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2)
return (OS_NO_ERR);
}

沒有留言:

張貼留言