임 베 디 드 운영 체제 커 널 원리 및 개발 (신 호 량)


【 성명: 판권 소유, 전재 환영, 상업 용도 로 사용 하지 마 십시오. 연락처: feixiaoxixing @ 163. com] 
 
    그동안 작업 때문에 운영 체제 라 는 것 은 계속 쓰 지 않 았 다.한편 으로 는 자신 이 이런 경험 이 없 는 것 이 고, 다른 한편 으로 는 운영 체제 가 비교적 복잡 하고 자질구레 하 며, 디 버 깅 하기 가 비교적 번거롭다.현재 실제 프로젝트 에서 사용 하 는 실시 간 운영 체제 가 매우 많 고 많은 국내 친구 들 도 운영 체 제 를 쓴 적 이 있 으 며 일부 프로젝트 는 아직도 유지 와 수정 중이 기 때문에 이것 은 매우 어 려 운 것 이다.내 가 아 는 것 과 익숙 한 것 만 세 가지 시스템 이 있다. 예 를 들 어
 
     (1)RT-THREAD
     (2)RAW-OS
     (3)ClearRTOS
 
    이 세 시스템 은 국내의 세 친구 가 개발 한 것 이다.그 중에서 rt - thread 시간 이 비교적 오래 되 고 모듈 도 비교적 완전 하 며 bsp, cpu, fs, lwip, gui 등 보조 적 인 코드 도 비교적 많 습 니 다. 관심 이 있 는 친 구 는 사이트 에서 코드 를 다운로드 하여 볼 수 있 습 니 다.raw - os 는 제 가 올해 에 야 발견 한 실시 간 시스템 입 니 다. 사이트 의 등록 시간 과 소프트웨어 버 전 번 호 를 보면 시스템 개발 시간 이 그리 길지 않 지만 전체 시스템 코드 의 구조 가 매우 뚜렷 하고 제 가 중점적으로 추천 하 는 코드 입 니 다.친구 들 이 직접 다운 로드 를 해서 코드 를 잘 살 펴 보면 많은 수확 이 있 을 것 입 니 다.마지막 코드 는 저자 이 운 이 라 는 책 을 쓸 때 os 의 기본 원 리 를 설명 하기 위해 개발 한 소프트웨어 로 스 레 드, 상호 배척, 메모리, 타이머, 구동 프레임 워 크 등 을 앞 뒤로 디자인 해 읽 을 만하 다.
 
    물론 이렇게 많은 우수한 코드 가 있 습 니 다. 저 는 지금 자신의 일 은 바퀴 를 다시 만 드 는 것 이 아니 라 이런 우수한 코드 들 이 어떻게 디자인 되 었 는 지 여러분 과 공유 하 는 것 이 라 고 생각 합 니 다.코드 자 체 를 이해 하 는 것 은 목적 이 아니 라 코드 뒤의 기본 적 인 사 고 를 이해 하 는 것 이 관건 이다.개인 적 으로 보면 rt - thread 와 raw - os 는 모두 공부 할 수 있 지만 raw - os 가 더 좋 습 니 다. 주로 작가 가 raw - os 를 vc 에 이식 하여 배 우 는 것 도 편리 하기 때 문 입 니 다. 만약 에 개인 이 사용 하 는 과정 에서 궁금 한 점 이 있 으 면 메 일 을 통 해 작가 와 신속하게 교류 할 수 있 습 니 다.그러나 raw - os 버 전 은 계속 update 에 있 기 때문에 일부 코드 는 앞 뒤 가 약간 다 릅 니 다. 그러나 이것 은 중점 이 아 닙 니 다. 잠시 모 르 는 내용 은 뒤의 이해 와 학습 을 통 해 점차적으로 파악 할 수 있 고 큰 장애 가 되 지 않 습 니 다.
 
    오늘 의 제목 처럼 신 호 량 의 설계 원 리 를 중점적으로 소개 합 니 다.우선 신 호 량 의 데이터 구조 가 어떤 지,
typedef struct RAW_SEMAPHORE
{ 
	RAW_COMMON_BLOCK_OBJECT       common_block_obj;
	RAW_U32                       count;
	
} RAW_SEMAPHORE;

    이 코드 들 은 모두 raw - os 에서 발췌 한 것 으로 이 버 전 은 0.94 버 전 으로 최신 0.96c 버 전과 차이 가 있다.먼저 신 호 량 의 기본 구 조 를 분석 해 보 세 요. 사실은 매우 간단 합 니 다. 두 개의 변수 만 있 는데 그 중에서 commblock_obj 는 유 니 버 설 형식 으로 현재 구조의 이름, 유형, 차단 대기 열 을 기록 하 였 으 며, count 는 계수 로 방출 된 자원 이 있 는 지 여 부 를 판단 합 니 다.
 
    신 호 량 의 조작 에 대해 말하자면 신 호 량 의 생 성, 획득, 방출, 삭제 작업 일 뿐이다. 물론 여기 서 작 가 는 비교적 상세 하 게 고려 하고 신 호 량 이 방출 될 때 나 누 었 다. WAKE_ONE_SEM 과 WAKEALL_SEM 두 가지 타 입.신 호 량 이 왔 을 때 대기 스 레 드 를 깨 우 느 냐, 아니면 모든 대기 스 레 드 를 깨 우 느 냐 하 는 뜻 이다.다음은 이 몇 가지 함 수 를 순서대로 소개 하 겠 습 니 다. 먼저 함 수 를 만 드 는 것 입 니 다.
RAW_U16 raw_semaphore_create(RAW_SEMAPHORE *semaphore_ptr, RAW_U8 *name_ptr, RAW_U32 initial_count)
{
	#if (RAW_SEMA_FUNCTION_CHECK > 0)
	
	if (semaphore_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}

	if (initial_count == 0xffffffff) {

		return RAW_SEMOPHORE_OVERFLOW;

	}
	
	#endif

	/*Init the list*/
	list_init(&semaphore_ptr->common_block_obj.block_list);
	
	/*Init resource*/
	semaphore_ptr->count     = initial_count;                                 
	
	semaphore_ptr->common_block_obj.name = name_ptr;  
	
	semaphore_ptr->common_block_obj.block_way = 0;
	
	return RAW_SUCCESS;

}

    초기 화 함 수 를 보면 서 우 리 는 신 호 량 의 초기 화 도 매우 간단 하 다 는 것 을 알 게 되 었 다. 기본 적 인 작업 은 주로 다음 과 같다.
    (1) 매개 변수의 합 법성 을 판단 한다.
    (2) 차단 대기 열, 이름 등 초기 화;
    (3) 신 호 량 의 수 를 초기 화 합 니 다.
 
    이 말 을 마치 고 우 리 는 신 호 량 의 획득 이 어떻게 완성 되 는 지 보 았 습 니 다. 코드 의 길이 가 약간 길 수 있 지만 너무 긴장 하지 않 아 도 됩 니 다.
RAW_U16 raw_semaphore_get(RAW_SEMAPHORE *semaphore_ptr,  RAW_U32 wait_option)
{

	RAW_U16 error_status;

	RAW_SR_ALLOC();

	#if (RAW_SEMA_FUNCTION_CHECK > 0)

	if (semaphore_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
	
	if (raw_int_nesting) {

		return RAW_NOT_CALLED_BY_ISR;
	}

	#endif
	
	
	RAW_CRITICAL_ENTER();
	if (semaphore_ptr->count) {                      
		semaphore_ptr->count--;                                       

		RAW_CRITICAL_EXIT();
		
		return RAW_SUCCESS;
	}
	
	/*Cann't get semphore, and return immediately if wait_option is  RAW_NO_WAIT*/
	if (wait_option == RAW_NO_WAIT) { 

		RAW_CRITICAL_EXIT();
		return RAW_NO_PEND_WAIT;
	}      
	
	if (raw_sched_lock) {   
		RAW_CRITICAL_EXIT();	
		return RAW_SCHED_DISABLE;
	}

	raw_pend_object(&semaphore_ptr->common_block_obj, raw_task_active, wait_option);
	RAW_CRITICAL_EXIT();

	raw_sched(); 
	
	error_status = block_state_post_process(raw_task_active, 0);
	return error_status;

}

    신 호 량 의 획득 상황 이 비교적 복잡 한데 이것 은 길이 에 도 나타난다.하지만 괜 찮 습 니 다. 우 리 는 함수 가 무엇 을 했 는 지 한 걸음 한 걸음 보 았 습 니 다.
    (1) 매개 변수의 합 법성 을 판단 한다.
    (2) 현재 함수 가 중 단 된 프로 세 스에 있 는 지 판단 하고 되 돌아 오 기 를 선택 하면;
    (3) 현재 count 가 0 인지 여 부 를 판단 하고 0 이 아니라면 1 을 줄 여 되 돌려 줍 니 다.
    (4) 현재 count 가 0 이 고 스 레 드 가 기다 리 기 싫 으 면 되 돌아 오 기 를 선택 합 니 다.
    (5) 현재 스케줄 링 이 금지 되 어 있 으 면 되 돌아 오 기 를 선택 합 니 다.
     (6) 현재 스 레 드 는 자신 을 걸 고 ready 대기 열 에서 삭제 하 며 자신의 pend 를 신 호 량 의 차단 대기 열 로 이동 합 니 다.
     (7) 막 힌 스 레 드 는 다시 실행 기 회 를 얻 었 습 니 다. 우 리 는 task 데이터 구조 에서 결 과 를 얻 었 습 니 다. 이때 도 반드시 자원 을 얻 었 기 때 문 만 은 아 닙 니 다.
 
    위의 get 함 수 는 비교적 복잡 해 보이 지만 모든 동기 함 수 는 기본적으로 이렇게 디자인 되 었 고 많이 보면 오히려 8 개의 문장 느낌 이 든다.처음 본 친구 들 은 익숙 하지 않 았 나 봐 요.괜찮아, 매일 두 번 더 보면 시간 이 지나 면 괜찮아.자, 이어서 우 리 는 신 호 량 의 방출 함수 가 어떻게 처리 되 는 지 계속 보 러 갑 니 다. 여러분 은 마음의 준 비 를 하 세 요.
static RAW_U16 internal_semaphore_put(RAW_SEMAPHORE *semaphore_ptr, RAW_U8 opt_wake_all)
{
	LIST *block_list_head;
	
	RAW_SR_ALLOC();

	#if (RAW_SEMA_FUNCTION_CHECK > 0)
	
	if (semaphore_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
	
	#endif

	block_list_head = &semaphore_ptr->common_block_obj.block_list;
	
	RAW_CRITICAL_ENTER();
	/*if no block task on this list just return*/
	if (is_list_empty(block_list_head)) {        
	    
		if (semaphore_ptr->count == 0xffffffff) {

			RAW_CRITICAL_EXIT();
			return RAW_SEMOPHORE_OVERFLOW;

		}
		/*increase resource*/
	    semaphore_ptr->count++;                                      
	    
	    RAW_CRITICAL_EXIT();
	    return RAW_SUCCESS;
	}

	/*wake all the task blocked on this semphore*/
	if (opt_wake_all) {

		while (!is_list_empty(block_list_head)) {
			raw_wake_object(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));
		}

	}

	else {
		
		/*Wake up the highest priority task block on the semaphore*/
		raw_wake_object(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));
	}
	
	RAW_CRITICAL_EXIT();

	raw_sched();    

	return RAW_SUCCESS;
}

    보기 에는 신 호 량 의 방출 함수 도 비교적 긴 것 같 지만 인내심 만 있 으 면 모두 알 수 있 습 니 다. 우 리 는 구체 적 으로 분석 해 보 겠 습 니 다.
    (1) 매개 변수의 합 법성 을 판단 한다.
    (2) 현재 대기 열 이 있 는 지 여 부 를 판단 합 니 다. 없 으 면 count 가 증가 하고 함수 가 돌아 갑 니 다. 물론 count 가 0xffffff ff 에 도달 하면 돌아 가 야 하지만 확률 이 매우 낮 습 니 다.
    (3) 현재 대기 열 이 존재 합 니 다. opt 에 따라wake_all 의 요 구 는 하나의 스 레 드 를 깨 우 는 것 입 니까? 아니면 모든 스 레 드 를 깨 우 는 것 입 니까?
    (4) 시스템 스케줄 링 함 수 를 호출 하여 높 은 우선 순위 작업 이 제때에 실 행 될 기 회 를 얻 도록 한다.
    (5) 현재 스 레 드 가 다시 실 행 될 기 회 를 얻 고 함수 가 되 돌 아 옵 니 다.
 
    위의 설명 이 있 었 는데, 우 리 는 os 의 코드 도 사실 그렇게 무 섭 지 않다 는 것 을 발견 했다.그 러 니 신 호 량 이 어떻게 삭제 되 는 지 단숨에 보 세 요.
RAW_U16 raw_semaphore_delete(RAW_SEMAPHORE *semaphore_ptr)
{
	LIST *block_list_head;
	
	RAW_SR_ALLOC();

	#if (RAW_SEMA_FUNCTION_CHECK > 0)
	
	if (semaphore_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
	
	#endif

	block_list_head = &semaphore_ptr->common_block_obj.block_list;
	
	RAW_CRITICAL_ENTER();

	/*All task blocked on this queue is waken up*/
	while (!is_list_empty(block_list_head)) {
		delete_pend_obj(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));	
	}                             

	RAW_CRITICAL_EXIT();
	raw_sched(); 
	return RAW_SUCCESS;
}

    신 호 량 삭제 작업 은 사실 매우 적 고 간단 하 다. 마찬가지 로 우리 도 정리 해 보 자.
    (1) 매개 변수의 합 법성 을 판단 한다.
    (2) 차단 대기 열 에 있 는 모든 스 레 드 를 깨 웁 니 다.
    (3) 시스템 스케줄 링 함 수 를 호출 합 니 다. 우선 순위 가 높 은 작업 이 막 막 막 힌 대기 열 에서 방출 될 가능성 이 높 기 때 문 입 니 다.
    (4) 현재 스 레 드 가 다시 실행 되 고 함수 가 되 돌아 갑 니 다.
 
    위의 몇 가지 함수 에 대한 설명 을 통 해 우 리 는 os 상호 배척 부분 에 관 한 코드 도 사실 복잡 하지 않다 는 것 을 발견 했다.시스템 자체 와 중단 에 대해 조금 만 알 면 코드 는 모두 알 아 볼 수 있다.물론 위의 코드 는 우리 가 비교적 거 칠 게 말 하기 때문에 약간의 세부 사항 은 보충 해 야 한다.
 
    (1) 전역 변수 작업 의 함 수 는 닫 힌 상태 에서 작업 해 야 합 니 다.
    (2) 실시 간 시스템 의 선점 은 매 순간 진행 되 는 것 이다. 예 를 들 어 반환 중단 시, 신 호 량 방출 시, 호출 지연 함수, 호출 스케줄 함수 등 이 있 기 때문에 여러분 의 마음 속 에 선점 개념 이 있어 야 한다.
    (3) 상호 배척 함수 에서 링크 의 구 조 를 대량으로 사 용 했 기 때문에 모두 링크 의 관련 알고리즘 을 잘 파악 하 는 것 을 권장 합 니 다.
    (4) os 에 관 한 코드 는 반드시 많이 보고 생각 하 며 연습 을 많이 해 야 발전 과 향상 이 있 을 수 있 습 니 다. 종이 에 있 는 것 은 결국은 얕 고 이 일 을 직접 해 야 한 다 는 것 을 알 아야 합 니 다.
  

좋은 웹페이지 즐겨찾기