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



  【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】 
 
     内存池设计是嵌入式系统的一个重要环节,之前我们也讨论过相关的内容。但是,看了rawos的代码之后,我觉得rawos的内存池设计更有特点。整个内存池的设计非常健壮,不但考虑了字节对齐的问题,而且还引入了等待调度机制,这是我所没有想到的。所以,在此我很愿意和大家分享这份优秀的代码。闲话不多说,我们看看rawos的mempool数据结构是什么样的,

  1. typedef struct MEM_POOL  
  2.   {  
  3.     RAW_COMMON_BLOCK_OBJECT       common_block_obj;  
  4.       
  5.     /* Define the number of available memory blocks in the pool.  */  
  6.     RAW_U32      raw_block_pool_available;  
  7.     
  8.     /* Define the head pointer of the available block pool.  */  
  9.     RAW_U8      *raw_block_pool_available_list;  
  10.     
  11.   } MEM_POOL;  
  12.     
    内存池的结构非常简单,主要包括了通用阻塞结构、block数值,block起始指针。内存池下面可以包括若干个block,每个block的大小都是相等的,同时block之间是通过链表串联在一起的,这个我们看了后面的代码就明白了。mempool的处理函数不多,就三个,初始化、申请、释放函数。
  1. 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)  
  2.   {  
  3.     
  4.     //MEM_POOL   *tail_ptr;                  /* Working block pool pointer  */  
  5.     RAW_U32       blocks;                     /* Number of blocks in pool    */  
  6.     RAW_U8        *block_ptr;                  /* Working block pointer       */  
  7.     RAW_U8        *next_block_ptr;             /* Next block pointer          */  
  8.     RAW_U8        *end_of_pool;                /* End of pool area            */  
  9.     RAW_U8          block_align_mask;  
  10.       
  11.     #if (RAW_BLOCK_FUNCTION_CHECK > 0)  
  12.        /* Check for invalid pool size.  */  
  13.       
  14.      if (pool_size < (block_size +  block_size) ) {  
  15.           
  16.         return RAW_BLOCK_SIZE_ERROR;  
  17.     }  
  18.     
  19.     if (pool_ptr == 0) {  
  20.           
  21.         return RAW_NULL_OBJECT;  
  22.     }  
  23.       
  24.     if (pool_start == 0) {  
  25.           
  26.         return RAW_NULL_POINTER;  
  27.     }  
  28.       
  29.     #endif  
  30.     
  31.      block_align_mask = sizeof(void *) - 1u;  
  32.     
  33.     if (((RAW_U32)pool_start & block_align_mask)){                               
  34.     
  35.         return RAW_INVALID_ALIGN;  
  36.     
  37.     }  
  38.        
  39.     if ((pool_size & block_align_mask)) {     
  40.           
  41.         return RAW_INVALID_ALIGN;  
  42.     }  
  43.     
  44.     if ((block_size & block_align_mask)) {     
  45.           
  46.         return RAW_INVALID_ALIGN;  
  47.     }  
  48.       
  49.     /*Init the list*/  
  50.     list_init(&pool_ptr->common_block_obj.block_list);  
  51.     
  52.     /* Setup the basic block pool fields.  */  
  53.     pool_ptr ->common_block_obj.name =  name_ptr;  
  54.     pool_ptr ->common_block_obj.block_way = 0;  
  55.       
  56.     /* Calculate the end of the pool's memory area.  */  
  57.     end_of_pool =  (RAW_U8  *) pool_start + pool_size;  
  58.     
  59.     /* Walk through the pool area, setting up the available block list.  */  
  60.     blocks =            0;  
  61.     block_ptr =         (RAW_U8  *) pool_start;  
  62.     next_block_ptr =    block_ptr + block_size;  
  63.       
  64.     while (next_block_ptr <= end_of_pool) {  
  65.     
  66.             blocks++;  
  67.               
  68.             if (next_block_ptr == end_of_pool) {  
  69.                   
  70.                 break;  
  71.     
  72.             }  
  73.     
  74.             /* Setup the link to the next block.  */  
  75.             *((RAW_U8  * *) block_ptr) =  next_block_ptr;  
  76.     
  77.             /* Advance to the next block.  */  
  78.             block_ptr =   next_block_ptr;  
  79.     
  80.             /* Update the next block pointer.  */  
  81.             next_block_ptr =  block_ptr + block_size;  
  82.     }  
  83.     
  84.     /* Set the last block's forward pointer to NULL.  */  
  85.     *((RAW_U8  * *) block_ptr) =  0;  
  86.     
  87.     /* Save the remaining information in the pool control block.  */  
  88.     pool_ptr ->raw_block_pool_available =  blocks;  
  89.     
  90.     
  91.     pool_ptr ->raw_block_pool_available_list =  (RAW_U8  *) pool_start;  
  92.     
  93.     
  94.     return RAW_SUCCESS;  
  95.   }  
  96.    
    上面就是内存池的创建函数,入参共有五个参数,分别是mempool结构、名称、block大小、pool起始地址、pool大小。函数基本内容如下所示,
     (1)判断内存池、指针参数合法性;
     (2)检验指针是否n字节对齐,n取决于地址的大小;
     (3)构建block链表,前后相连,最后一个block指向NULL指针;
     (4)将pool首地址赋值给raw_block_pool_available_list,函数返回。
  1. RAW_U16 raw_block_allocate(MEM_POOL *pool_ptr, RAW_VOID **block_ptr, RAW_U32 wait_option)  
  2.   {  
  3.       
  4.     RAW_U16             status;                               
  5.     
  6.     RAW_U8      *work_ptr;                        
  7.     
  8.     RAW_SR_ALLOC();  
  9.     
  10.     #if (RAW_BLOCK_FUNCTION_CHECK > 0)  
  11.        
  12.     if (pool_ptr == 0) {  
  13.         return RAW_NULL_OBJECT;  
  14.     }  
  15.       
  16.     if (block_ptr == 0) {  
  17.           
  18.         return RAW_NULL_POINTER;  
  19.     }  
  20.     
  21.     if (raw_int_nesting) {  
  22.     
  23.         if (wait_option != RAW_NO_WAIT) {  
  24.               
  25.             return RAW_NOT_CALLED_BY_ISR;  
  26.         }  
  27.           
  28.     }  
  29.       
  30.     #endif  
  31.     
  32.     RAW_CRITICAL_ENTER();  
  33.     
  34.     /* Determine if there is an available block.  */  
  35.     if (pool_ptr ->raw_block_pool_available) {  
  36.     
  37.         /* Yes, a block is available.  Decrement the available count.  */  
  38.         pool_ptr ->raw_block_pool_available--;  
  39.     
  40.         /* Pickup the current block pointer.  */  
  41.         work_ptr =  pool_ptr ->raw_block_pool_available_list;  
  42.     
  43.         /* Return the first available block to the caller.  */  
  44.         *((RAW_U8 **)block_ptr) =  work_ptr;  
  45.     
  46.         /* Modify the available list to point at the next block in the pool. */  
  47.         pool_ptr ->raw_block_pool_available_list = *((RAW_U8 **)work_ptr);  
  48.     
  49.         /* Set status to success.  */  
  50.         status =  RAW_SUCCESS;  
  51.     }  
  52.     
  53.     /*if no block memory is available then do it depend wait_option*/  
  54.     else {    
  55.           
  56.         if (wait_option == RAW_NO_WAIT) {   
  57.             *((RAW_U8 **)block_ptr)     = 0;  
  58.             RAW_CRITICAL_EXIT();  
  59.             return RAW_NO_PEND_WAIT;  
  60.         }    
  61.     
  62.         /*system is locked so task can not be blocked just return immediately*/  
  63.         if (raw_sched_lock) {    
  64.             *((RAW_U8 **)block_ptr)     = 0;  
  65.             RAW_CRITICAL_EXIT();      
  66.             return RAW_SCHED_DISABLE;      
  67.         }  
  68.       
  69.         raw_pend_object(&pool_ptr->common_block_obj, raw_task_active, wait_option);  
  70.     
  71.         RAW_CRITICAL_EXIT();  
  72.     
  73.         raw_sched();                                               
  74.     
  75.         RAW_CRITICAL_ENTER();  
  76.     
  77.         *((RAW_U8 **)block_ptr)     = 0;  
  78.         status = block_state_post_process(raw_task_active, block_ptr);  
  79.           
  80.         RAW_CRITICAL_EXIT();    
  81.     
  82.     }  
  83.     
  84.     
  85.     return status;  
  86.     
  87.   }  
  88.    
    和其他的内存池申请函数不一样,这里有一个wait_option选项。也就是说,如果当前没有合适的block,那么你可以选择等待处理。一旦别的线程释放内存,你就可以得到调度继续运行了。当然你也可以不等待,一旦寻找不到合适的block,立即返回为NULL。
  1. RAW_U16 raw_block_release(MEM_POOL *pool_ptr, RAW_VOID *block_ptr)  
  2.   {  
  3.     LIST *block_list_head;  
  4.       
  5.     RAW_U8        *work_ptr;           /* Working block pointer   */  
  6.     RAW_U8          need_schedule = 0;  
  7.       
  8.     RAW_SR_ALLOC();  
  9.     
  10.     #if (RAW_BLOCK_FUNCTION_CHECK > 0)  
  11.        
  12.     if (block_ptr == 0) {  
  13.         return RAW_NULL_OBJECT;  
  14.     }  
  15.       
  16.     if (pool_ptr == 0) {  
  17.           
  18.         return RAW_NULL_OBJECT;  
  19.     }  
  20.       
  21.     #endif  
  22.     
  23.     block_list_head = &pool_ptr->common_block_obj.block_list;  
  24.       
  25.     RAW_CRITICAL_ENTER();  
  26.       
  27.     work_ptr =  ((RAW_U8 *) block_ptr);  
  28.       
  29.     if (is_list_empty(block_list_head)) {          
  30.     
  31.         /* Put the block back in the available list.  */  
  32.         *((RAW_U8  **) work_ptr) =  pool_ptr ->raw_block_pool_available_list;  
  33.     
  34.         /* Adjust the head pointer.  */  
  35.         pool_ptr ->raw_block_pool_available_list =  work_ptr;          
  36.     
  37.         /* Increment the count of available blocks.  */  
  38.         pool_ptr ->raw_block_pool_available++;  
  39.     }  
  40.     
  41.     else {  
  42.           
  43.         need_schedule = 1;  
  44.         wake_send_msg(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list),  block_ptr);     
  45.     
  46.     }  
  47.      
  48.     RAW_CRITICAL_EXIT();  
  49.     
  50.     if (need_schedule) {  
  51.         raw_sched();  
  52.     }  
  53.       
  54.     /* Return completion status.  */  
  55.     return RAW_SUCCESS;  
  56.   }  
  57.    
    和其他的内存free函数不一样,这里的free函数多了一个wake_send_msg的功能。这也就是说,当然如果存在阻塞等待资源的线程,那么把资源送给该线程,同时把该线程唤醒,还要把need_schedule设置为1才可以。当然如果没有等待的线程,那么直接把内存插入到链表前面中即可,就是这么简单。
 


Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐