OSEK 태스크(Task)와 ISR(Interrupt Service Routine)은 VDX의 두 가지 실행 단위다. Task는 OS가 제어하는 주기·이벤트 기반 실행 단위, ISR은 하드웨어 인터럽트로 트리거되는 핸들러. 둘 다 OIL(OSEK Implementation Language)로 정적 선언한다.

Processing Levels

OSEK은 실행 문맥을 우선순위 계층으로 분리한다.

Level설명
ISR Category 1최상위, OS가 관여하지 않음
ISR Category 2OS가 관리하는 인터럽트 핸들러
TaskOS 스케줄러가 관리하는 실행 단위
OS Background(아이들)

Task

선언 (C + OIL)

TASK(TaskL1) {        // Task ID
    ...               // Task Body
    TerminateTask();  // End of Task (반드시 호출)
}
TASK TaskL1 {
    PRIORITY = 1;        // 우선순위 (큰 값이 높음)
    STACK = SHARED;      // 공유 스택 사용
    SCHEDULE = FULL;     // FULL: preemptable, NON: non-preemptable
    AUTOSTART = FALSE;   // 자동 시작 여부
    ACTIVATION = 1;      // 최대 큐잉 활성화 횟수
};
OIL 속성의미
PRIORITY숫자 값이 클수록 우선순위 높음
STACKSHARED 또는 별도 할당
SCHEDULEFULL = 선점 가능, NON = 비선점 (→ 실시간 스케줄링 선점 정책 참고)
AUTOSTARTTRUE면 시스템 시작 시 자동 활성화
ACTIVATION큐에 쌓일 수 있는 최대 활성화 횟수

Task 상태 머신

OSEK Task는 running / ready / waiting / suspended 4-상태를 가진다. Basic Task는 waiting 상태를 사용하지 않는다.

State의미
runningCPU가 Task에 할당되어 명령 수행. 한 번에 하나의 Task만 이 상태에 있을 수 있음
ready실행 가능하지만 CPU 미할당. 스케줄러가 이 집합에서 다음 실행 Task 선택
waiting(Extended Task 전용) 특정 event가 발생할 때까지 동작 정지
suspended휴식 상태. activate되어야 Ready로 진입

상태 전이:

전이계기
activateActivateTask 등 system service로 Task가 Ready로 진입
start스케줄러가 Ready 집합에서 Task를 선택해 Running으로
preempt스케줄러가 다른 Task 실행을 결정해 Running → Ready
terminateTask 본문이 TerminateTask로 종료 (또는 에러로 강제 종료)
wait(Extended) WaitEvent 호출로 Running → Waiting. Context 저장 필요
release(Extended) Waiting Task에 기다리던 event가 발생해 Ready로 복귀

Basic Task vs Extended Task

항목Basic TaskExtended Task
Waiting 상태불허허용
전형적 코드{ ... ; TerminateTask(); }{ ... ; WaitEvent(event); ... ; TerminateTask(); }
Event 사용✓ (WaitEvent로 이벤트 대기)
ConformanceBCC1 / BCC2 / ECC (모두 지원)ECC1 / ECC2에서만 지원

Task API

API용도
ActivateTask(TaskID)Task를 Ready 상태로 (Suspended → Ready)
TerminateTask()현재 Running Task를 Suspended로
ChainTask(TaskID)다른 Task를 activate하면서 자신은 terminate (원자적)
Schedule()명시적으로 스케줄링 수행 (Non-preemptive Task가 자발 양보)
GetTaskID(TaskRefType)현재 Running Task의 ID 조회
GetTaskState(TaskID, TaskRefType state)Task ID의 현재 state(Running/Ready/Waiting/Suspended) 조회

모든 API는 StatusType을 반환한다. E_OK가 정상, E_OS_LIMITACTIVATION 한도 초과 등 — 전체 코드는 OSEK Error Handling 참고.

Context Switching

Context = MCU가 현재 실행 중인 Task 상태 — PC, SP, 범용 레지스터 등 Task 재개에 필요한 값의 집합. 선점이 일어나면 OS는 다음을 수행한다.

  • Context Save — Running Task의 레지스터 상태를 메모리에 저장
  • Context Load — 다음 실행 Task의 저장된 Context를 MCU 레지스터에 복원

스위치 시점은 Task 유형에 따라 다르다.

  • Basic Task — preempt 시 Save, 다시 running 진입 시 Load
  • Extended Task — 위에 더해 wait 시에도 Save, release 이후 running 진입 시 Load

→ 개념의 일반론은 컨텍스트 스위치 참고.

Event — Extended Task 동기화

용도 — Extended Task 간 실행 순서를 맞추는 메커니즘. 예: Task A가 Task B의 연산 결과를 필요로 할 때, 결과 준비 event까지 wait.

Event 규칙

  • Event wait은 Extended Task에서만 가능 (Waiting 상태를 지원해야 하므로)
  • Event set은 Basic Task·ISR2에서도 가능
  • Task가 waiting 상태로 들어가기 전에 이미 set된 event를 기다리면 바로 running 유지 (waiting으로 가지 않음)
  • ClearEventevent를 소유한 Task만 호출 가능 (event의 대기 주체)

API

API동작
SetEvent(TaskID, EventMask)지정 Task의 event set. Task가 해당 event를 waiting 중이면 Ready로
ClearEvent(EventMask)호출 Task 자신의 event flag clear
GetEvent(TaskID, EventMaskRef)Task의 모든 event 상태 bitmap 반환
WaitEvent(EventMask)현재 Extended Task를 Waiting으로. 대기 event가 이미 set이면 즉시 복귀

3-Step 사용 예

Task A priority > Task B priority. Task A가 Event_A를 기다리고 Task B가 이를 발생시키는 시나리오.

Step 1) Task A: WaitEvent(Event_A)
        → Task A Running → Waiting,  Ready Queue 다음 Task B가 Running
 
Step 2) Task B: SetEvent(TaskA, Event_A)
        → Task A에 event flag set, Task A Waiting → Ready
        → (Full preemptive) 스케줄링 발생, Task A가 Task B를 선점
 
Step 3) Task A 내에서: ClearEvent(Event_A)
        → Event flag 삭제. 다음 WaitEvent가 다시 block 가능해짐
        ※ Clear 하지 않으면 다음 WaitEvent는 즉시 return (이미 set 상태)

OIL 선언

Event 자체는 이름과 mask만 설정하고, 실제 매핑은 Task의 OIL에서 수행한다. Task 하나에 여러 event가 있을 수 있으므로 mask로 구분.

EVENT Event_A {
    MASK = AUTO;   // 또는 비트 위치 지정
};
 
TASK TaskA {
    EVENT = Event_A;  // 이 Task가 사용하는 event 매핑
    /* ... */
};

ISR (Interrupt Service Routine)

인터럽트로 트리거되는 함수. OSEK은 두 가지 카테고리를 구분한다.

항목ISR Category 1ISR Category 2
시스템 콜불허 (어떤 OS 서비스도 사용 불가)허용 (예: ActivateTask, CounterTick)
OS 인식무시OS가 인식
OIL 기술불필요필요
오버헤드낮음 / 빠름높음 / 느림
이식성마이크로프로세서 간 이식성 없음상대적으로 이식 가능
TerminateTask 호출불필요 (ISR은 복귀로 종료)

ISR2 선언 (C + OIL)

ISR(myISR) {
    // ISR code
    // no need to call TerminateTask()
}
ISR MyISR {
    CATEGORY = 2;
    PRIORITY = 1;        // 인터럽트 우선순위
    STACKSIZE = 32768;
    SOURCE = SIGUSR1;    // 인터럽트 소스
};

우선순위 계층

OSEK은 실행 컨텍스트 사이에 고정 우선순위 계층을 강제한다.

Interrupt level  >  Logical level for scheduler  >  Task level

Interrupt(Cat1·Cat2)은 Full/Non Preemptive 여부와 무관하게 항상 Task를 선점하며, 이 때 Context Switching이 발생한다. ISR 중에는 rescheduling이 일어나지 않고, Cat2 ISR 종료 후에만 Task에 대한 rescheduling이 수행된다. ISR 내부에서 activate된 Task는 모든 interrupt routine이 끝난 후에야 스케줄될 수 있다.

Nested Cat1·Cat2 — Unbounded Delay 문제

Category가 다른 인터럽트가 중첩될 때 시나리오별 동작이 다르다.

문제 시나리오 — Cat1 ISR 도중 Cat2 ISR 발생 → Cat2가 ActivateTask로 Task 깨움 → Cat1 ISR이 나중에 종료되지만 Cat1은 OS를 call하지 않으므로, activate된 Task에 대한 rescheduling이 무한 지연(unbounded delay) 될 수 있다.

해결책 — 모든 Cat1 ISR의 priority를 Cat2 ISR보다 같거나 높게 구성한다. 그러면 Cat1 ISR 도중 Cat2 ISR이 끼어들 수 없고, Cat2 ISR이 먼저 처리되어 정상적으로 OS 스케줄링이 이루어진다.

Interrupt 제어 API

중첩 허용 여부와 대상 범위가 3쌍으로 나뉜다.

대상Nesting
DisableAllInterrupts / EnableAllInterrupts모든 interrupt불허
SuspendAllInterrupts / ResumeAllInterrupts모든 interrupt허용
SuspendOSInterrupts / ResumeOSInterruptsCategory 2 only허용

Nesting 허용이 중요한 이유 — 중첩 허용 쌍은 Suspend를 N회 호출하면 Resume을 동일 N회 불러야 interrupt가 재활성화된다 (depth counter). 중첩되는 critical section이 있어도 안전하게 쌓을 수 있다.

Task·ISR 간 자원 공유

Task끼리, 또는 Task와 ISR2 사이에 공유 데이터가 있으면 경쟁 상태가 발생할 수 있다. → OSEK 리소스가 임계 영역(critical section) 수단 제공.

같이 보기