嵌入式操作系统内核原理和开发(等值block内存池设计)

梦想的初衷 提交于 2020-08-13 17:09:21


  【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】 
 
     内存池设计是嵌入式系统的一个重要环节,之前我们也讨论过相关的内容。但是,看了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才可以。当然如果没有等待的线程,那么直接把内存插入到链表前面中即可,就是这么简单。
 

 

 
 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!