2008년 4월 22일 화요일

uC/OS-II 커널구조(1) - 크리티컬 섹션

uc/OS-II의 핵심 서비스 함수
OS_ENTER_CRITICAL()
OS_EXIT_CRITICAL()
OSInit()
OSStart()
OSIntEnter()
OSIntExit()
OSSchedLock() -> OS_SCHED_LOCK_EN
OSSchedUnlock() -> OS_SCHED_LOCK_EN
OSVersion()

-----------------------------------------------------------------------------------------
1. OS_ENTER_CRITICAL() / OS_EXIT_CRITICAL()
서로 다른 태스크와 ISR이 크리티컬 섹션에 동시에 진입하는 것을 방지하기 위해 인터럽트를 비활성화/활성화 시키기 위한 함수.
프로세서는 일반적으로 인터럽트를 활성화/비활성화 하는 명령어를 제공한다. 이는 각 컴파일러의 특성에 따라 메커니즘이 다르기 때문에 uC/OS-II 에서는 OS_ENTER_CRITICAL() / OS_EXIT_CRITICAL() 매크로를 사용한다. 이 매크로는 프로세서에 의존적이기 때문에 서로 다른 고유의 OS_CPU.H 파일로 분리되어 있다.
이 매크로들을 이용하여 크리티컬 섹션의 영역을 쌍으로 감싼다.

{
..
OS_ENTER_CRITICAL();
// uC/OS-II 크리티컬 섹션
OS_EXIT_CRITICAL();
..
}

응용 프로그램에서도 이 매크로들을 사용하여 크리티컬 섹션을 보호할 수 있다. 단, 인터럽트를 비활성화시킨 상태에서 OSTimeDly() 같은 함수를 호출하면 시스템이 멈출수 있으므로 주의해야 한다. (태스크가 일정 시간동안 정지상태에로 들어가면서 이 함수를 호출하는데 인터럽트가 비활성화 상태면 타임 틱 인터럽트가 발생할 수 없으므로 문제가 발생한다)
일반적으로 uC/OS-II 서비스를 호출할 때, 인터럽트는 활성화 상태여야 한다.

OS_ENTER_CRITICAL() / OS_EXIT_CRITICAL()은 서로 다른 세가지 방법으로 구현한다. 포트를 만들 때 프로세서와 컴파일러의 기능에 따라 적절한 방법을 선택해야 한다. 실제 사용시는 응용에 사용하고자 하는 포트에 따라 OS_CPU.H에 정의한 OS_CRITICAL_METHOD 상수에 적절한 값을 지정해야 한다.

1) OS_CRITICAL_METHOD == 1
OS_ENTER_CRITICAL() 매크로에 인터럽트를 비활성화는 프로세서 명령을 정의하고,
OS_EXIT_CRITICAL() 매크로에 인터럽트를 활성화하는 프로세서 명령을 정의.
이것의 문제점은 인터럽트 비활성화 상태에서 uC/OS-II 함수를 호출하면, 함수 복귀 시 인터럽트는 활성화 상태가 되지만, uC/OS-II 함수 호출 전에 의도적으로 인터럽트를 비활성화 했다면, 함수 복귀 후에도 인터럽트가 비활성화 되어 있어야 하지만 이런 방법으로는 불가능하다. 특정 프로세서/컴파일러는 이 방법말고는 예외가 없는 경우도 있다.
2) OS_CRITICAL_METHOD == 2
인터럽트 활성화/비활성화 상태를 스택에 저장한 뒤 인터럽트를 비활성화하는 것이다. OS_EXIT_CRITICAL()은 단순히 인터럽트 상태를 스택에서 읽어와 복구하는 방식으로 구현하면 된다. 이 방식을 사용하면, 인터럽트가 비활성화 상태이든 활성화 상태이든 함수 호출 뒤에 이전 상태를 그대로 유지할 수 있다. 단, 인터럽트를 비활성화한 상태에서 uC/OS-II 함수를 호출하면 인터럽트 지연시간이 늘어나서 전체 시스템의 응답성이 떨어지므로 특별한 주의가 필요하다.

#define OS_ENTER_CRITICAL() \
asm("PUSH PSW") \ -> 프로세서 상태워드를 스택에 저장.
asm(" DI") -> 인터럽트 비활성화

#define OS_EXIT_CRITICAL() \
asm("POP PSW") -> 스택에 저장했던 프로세서의 인터럽트 복구

3) OS_CRITICAL_METHOD == 3
어떤 컴파일러는 프로세서 상태 워드의 값을 읽어서 C함수 안에서 선언한 지역변수에 저장하는 기능이 있다. PSW복구를 위해 이 변수를 사용할 수 있다.

void Some_uCOS_II_Service(arguments)
{
OS_CPU_SR cpu_sr;

...
cpu_sr = get_processor_psw();
disable_interrupt();

// 크리티컬 섹션
...
set_processor_psw(cpu_sr);
...
}

출처> uC/OS-II 실시간 커널...

댓글 없음: