嵌入式作業系統的等值block內存池設計

內存池設計是嵌入式系統的一個重要環節,之前我們也討論過相關的內容。但是,看了rawos的代碼之後,我覺得rawos的內存池設計更有特點。整個內存池的設計非常健壯,不但考慮了字節對齊的問題,而且還引入了等待調度機制,這是我所沒有想到的。所以,在此我很願意和大家分享這份優秀的代碼。閒話不多說,我們看看rawos的mempool數據結構是什麼樣的,


typedef struct MEM_POOL
{
RAW_COMMON_BLOCK_OBJECT common_block_obj;

/* Define the number of available memory blocks in the pool. */
RAW_U32 raw_block_pool_available;

/* Define the head pointer of the available block pool. */
RAW_U8 *raw_block_pool_available_list;

} MEM_POOL;

內存池的結構非常簡單,主要包括了通用阻塞結構、block數值,block起始指針。內存池下面可以包括若干個block,每個block的大小都是相等的,同時block之間是通過鏈表串聯在一起的,這個我們看了後面的代碼就明白了。mempool的處理函數不多,就三個,初始化、申請、釋放函數。


RAW_U16 raw_block_pool_create(MEM_POOL *pool_ptr, RAW_U8 *name_ptr, RAW_U32 block_size, RAW_VOID *pool_start, RAW_U32 pool_size)
{

//MEM_POOL *tail_ptr; /* Working block pool pointer */
RAW_U32 blocks; /* Number of blocks in pool */
RAW_U8 *block_ptr; /* Working block pointer */
RAW_U8 *next_block_ptr; /* Next block pointer */
RAW_U8 *end_of_pool; /* End of pool area */
RAW_U8 block_align_mask;

#if (RAW_BLOCK_FUNCTION_CHECK > 0)
/* Check for invalid pool size. */

if (pool_size < (block_size + block_size) ) {

return RAW_BLOCK_SIZE_ERROR;
}

if (pool_ptr == 0) {

return RAW_NULL_OBJECT;

}

if (pool_start == 0) {

return RAW_NULL_POINTER;
}

#endif

block_align_mask = sizeof(void *) - 1u;

if (((RAW_U32)pool_start & block_align_mask)){

return RAW_INVALID_ALIGN;

}

if ((pool_size & block_align_mask)) {

return RAW_INVALID_ALIGN;
}

if ((block_size & block_align_mask)) {

return RAW_INVALID_ALIGN;
}

/*Init the list*/
list_init(&pool_ptr->common_block_obj.block_list);

/* Setup the basic block pool fields. */
pool_ptr ->common_block_obj.name = name_ptr;
pool_ptr ->common_block_obj.block_way = 0;

/* Calculate the end of the pool's memory area. */
end_of_pool = (RAW_U8 *) pool_start + pool_size;

/* Walk through the pool area, setting up the available block list. */
blocks = 0;
block_ptr = (RAW_U8 *) pool_start;
next_block_ptr = block_ptr + block_size;

while (next_block_ptr <= end_of_pool) {

blocks++;

if (next_block_ptr == end_of_pool) {

break;

}

/* Setup the link to the next block. */
*((RAW_U8 * *) block_ptr) = next_block_ptr;

/* Advance to the next block. */
block_ptr = next_block_ptr;

/* Update the next block pointer. */
next_block_ptr = block_ptr + block_size;
}

/* Set the last block's forward pointer to NULL. */
*((RAW_U8 * *) block_ptr) = 0;

/* Save the remaining information in the pool control block. */
pool_ptr ->raw_block_pool_available = blocks;


pool_ptr ->raw_block_pool_available_list = (RAW_U8 *) pool_start;


return RAW_SUCCESS;
}

上面就是內存池的創建函數,入參共有五個參數,分別是mempool結構、名稱、block大小、pool起始地址、pool大小。函數基本內容如下所示,

(1)判斷內存池、指針參數合法性;

(2)檢驗指針是否n字節對齊,n取決於地址的大小;

(3)構建block鏈表,前後相連,最後一個block指向NULL指針;

(4)將pool首地址賦值給raw_block_pool_available_list,函數返回。


RAW_U16 raw_block_allocate(MEM_POOL *pool_ptr, RAW_VOID **block_ptr, RAW_U32 wait_option)

{

RAW_U16 status;

RAW_U8 *work_ptr;

RAW_SR_ALLOC();

#if (RAW_BLOCK_FUNCTION_CHECK > 0)

if (pool_ptr == 0) {
return RAW_NULL_OBJECT;
}

if (block_ptr == 0) {

return RAW_NULL_POINTER;
}

if (raw_int_nesting) {

if (wait_option != RAW_NO_WAIT) {

return RAW_NOT_CALLED_BY_ISR;
}

}

#endif

RAW_CRITICAL_ENTER();

/* Determine if there is an available block. */
if (pool_ptr ->raw_block_pool_available) {

/* Yes, a block is available. Decrement the available count. */
pool_ptr ->raw_block_pool_available--;

/* Pickup the current block pointer. */
work_ptr = pool_ptr ->raw_block_pool_available_list;

/* Return the first available block to the caller. */
*((RAW_U8 **)block_ptr) = work_ptr;

/* Modify the available list to point at the next block in the pool. */
pool_ptr ->raw_block_pool_available_list = *((RAW_U8 **)work_ptr);

/* Set status to success. */
status = RAW_SUCCESS;
}


/*if no block memory is available then do it depend wait_option*/
else {

if (wait_option == RAW_NO_WAIT) {
*((RAW_U8 **)block_ptr) = 0;
RAW_CRITICAL_EXIT();
return RAW_NO_PEND_WAIT;
}

/*system is locked so task can not be blocked just return immediately*/
if (raw_sched_lock) {
*((RAW_U8 **)block_ptr) = 0;
RAW_CRITICAL_EXIT();
return RAW_SCHED_DISABLE;
}

raw_pend_object(&pool_ptr->common_block_obj, raw_task_active, wait_option);

RAW_CRITICAL_EXIT();

raw_sched();

RAW_CRITICAL_ENTER();

*((RAW_U8 **)block_ptr) = 0;
status = block_state_post_process(raw_task_active, block_ptr);

RAW_CRITICAL_EXIT();

}


return status;

}

和其他的內存池申請函數不一樣,這裡有一個wait_option選項。也就是說,如果當前沒有合適的block,那麼你可以選擇等待處理。一旦別的線程釋放內存,你就可以得到調度繼續運行了。當然你也可以不等待,一旦尋找不到合適的block,立即返回為NULL。


RAW_U16 raw_block_release(MEM_POOL *pool_ptr, RAW_VOID *block_ptr)
{
LIST *block_list_head;

RAW_U8 *work_ptr; /* Working block pointer */
RAW_U8 need_schedule = 0;

RAW_SR_ALLOC();

#if (RAW_BLOCK_FUNCTION_CHECK > 0)

if (block_ptr == 0) {
return RAW_NULL_OBJECT;
}

if (pool_ptr == 0) {

return RAW_NULL_OBJECT;
}

#endif

block_list_head = &pool_ptr->common_block_obj.block_list;

RAW_CRITICAL_ENTER();

work_ptr = ((RAW_U8 *) block_ptr);

if (is_list_empty(block_list_head)) {

/* Put the block back in the available list. */
*((RAW_U8 **) work_ptr) = pool_ptr ->raw_block_pool_available_list;

/* Adjust the head pointer. */
pool_ptr ->raw_block_pool_available_list = work_ptr;

/* Increment the count of available blocks. */
pool_ptr ->raw_block_pool_available++;
}

else {

need_schedule = 1;
wake_send_msg(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list), block_ptr);

}

RAW_CRITICAL_EXIT();

if (need_schedule) {
raw_sched();
}

/* Return completion status. */
return RAW_SUCCESS;
}

和其他的內存free函數不一樣,這裡的free函數多了一個wake_send_msg的功能。這也就是說,當然如果存在阻塞等待資源的線程,那麼把資源送給該線程,同時把該線程喚醒,還要把need_schedule設置為1才可以。當然如果沒有等待的線程,那麼直接把內存插入到鏈表前面中即可,就是這麼簡單。


分享到:


相關文章: