임 베 디 드 운영 체제 커 널 원리 와 개발 (등가 block 메모리 풀 디자인)

【 성명: 판권 소유, 전재 환영, 상업 용도 로 사용 하지 마 십시오. 연락처: feixiaoxixing @ 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) 블록 체인 테이블 을 구축 하고 앞 뒤 가 연결 되 며 마지막 블록 은 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 기능.물론 자원 을 기다 리 는 스 레 드 가 존재 한다 면 자원 을 이 스 레 드 에 보 내 는 동시에 이 스 레 드 를 깨 우 고 needschedule 을 1 로 설정 해 야 합 니 다.물론 기다 리 는 스 레 드 가 없다 면 링크 앞 에 메모 리 를 직접 삽입 하면 됩 니 다. 이렇게 간단 합 니 다.
 

좋은 웹페이지 즐겨찾기