본문으로 건너뛰기
Practical RTOS Internals · 25/53

Priority Inversion 문제 — Mars Pathfinder 사례·Bounded vs Unbounded

· Hawk · 4분 읽기

#한 줄 요약

“고우선 task가 저우선 task 때문에 막힌다” — 이것이 Priority Inversion입니다.

Priority Inversion은 RTOS 설계에서 가장 악명 높은 함정 중 하나입니다. 우선순위 기반 스케줄링의 전제 자체를 흔드는 현상이라 정확히 이해해 두는 것이 좋습니다.

#Bounded vs Unbounded

#Bounded (정상)

  1. T_high가 mutex를 기다림 (T_low가 보유, critical 짧음).
  2. T_low가 critical 종료 (수 µs) 후 mutex release.
  3. T_high가 즉시 진행.

대기 시간은 T_low의 critical 길이로 정해집니다. 짧으면 문제가 없습니다.

#Unbounded (위험)

  1. T_high가 mutex 대기, T_low가 보유 중.
  2. T_med가 ready 상태가 되어 T_low를 preempt.
  3. T_med가 계속 진행, T_low는 멈춤.
  4. T_highT_med 종료까지 무한 대기.

T_med가 길어지면 T_high도 무한히 대기합니다. 이렇게 되면 시스템이 실패합니다.

#Mars Pathfinder 1997

NASA Pathfinder는 화성 도착 후 지속적으로 reset하는 문제를 겪었습니다.

Task 구성

  • 데이터 수집 task (T_low)
  • 통신 task (T_med, long-running)
  • bus 관리 task (T_high)

시나리오 — T_low가 bus mutex 획득 → T_medT_low를 preempt → T_high가 mutex 대기하다 watchdog timeout으로 reset.

JPL은 Priority Inheritance를 활성화(VxWorks 설정)해 문제를 해결했습니다. 화성 현지의 탐사선을 지구에서 원격으로 디버그한 사례로 유명합니다.

#해결책 1 — Priority Inheritance Protocol (PIP)

  • T_low가 mutex 보유, T_high가 대기 시 → T_low의 priority를 T_high level로 boost.
  • T_low가 release하면 → priority를 원래대로 복원.

이렇게 되면 T_medT_low를 preempt하지 못합니다. boost된 priority가 더 높기 때문입니다.

configUSE_MUTEX_PI = 1 // FreeRTOS default

#해결책 2 — Priority Ceiling Protocol (PCP)

각 mutex에 priority ceiling을 정적으로 부여하는 방식입니다.

  • mutex X의 ceiling을 T_high priority로 설정합니다.
  • T_low가 take하는 즉시 priority가 ceiling level로 boost됩니다.
  • 결과적으로 T_med시작조차 못 합니다.

PCP는 take 즉시 boost합니다. 반면 PI는 wait가 발생해야 boost가 일어납니다.

장점은 deadlock 방지입니다. 단점은 priority를 사전에 결정해야 한다는 점입니다.

#Immediate PCP vs Original PCP

ImmediateOriginal
Boost 시점Take 즉시Conflict 시
구현단순복잡
채택VxWorks·Zephyr옛 academic

#PIP vs PCP

PIPPCP
단순성
Priority 사전 분석
Deadlock 방지
채택FreeRTOS·ZephyrVxWorks

FreeRTOS의 기본 정책은 PIP입니다.

#PI의 한계 — Chained Inheritance

  • T_high가 mutex A 대기, T_med가 보유.
  • T_med가 mutex B 대기, T_low가 보유.
  • T_med의 priority가 boost되고, 그 결과 T_low도 boost됩니다.

체인이 길수록 boost 전파 비용이 커집니다. RTOS 구현체는 보통 깊이 제한을 둡니다.

#Linux PREEMPT_RT

Mainline mutex에는 PI가 없습니다. PREEMPT_RT의 rtmutex가 PI를 지원하며, 이것이 RT 보장의 핵심입니다.

#실전 — 회피 우선

  1. Critical section은 짧게 유지합니다(수 µs).
  2. Lock을 보유한 채로 long blocking 호출을 피합니다.
  3. Lock 획득 순서를 일관되게 유지합니다.
  4. 공유 자원을 최소화합니다.

#자주 하는 실수

⚠️ Semaphore로 critical 자원을 보호하면 PI가 적용되지 않습니다.

⚠️ configUSE_MUTEX_PI = 0으로 두면 Pathfinder 사례가 재현됩니다.

⚠️ PI를 믿고 critical section을 길게 두는 것은 위험합니다. bounded일 뿐 zero는 아닙니다.

⚠️ 여러 mutex를 lock order 없이 쓰면 chain inheritance와 deadlock이 함께 발생합니다.

#정리

  • Priority Inversion은 고우선 task가 저우선 task에 막히는 현상입니다.
  • Bounded(critical 길이로 한정)와 Unbounded(T_med preempt) 두 형태가 있습니다.
  • Mars Pathfinder 1997 사건은 PI 활성화로 해결됐습니다.
  • PIP(FreeRTOS)와 PCP(VxWorks)가 양대 해결책입니다.
  • Semaphore는 PI를 지원하지 않으므로, critical 자원에는 mutex를 씁니다.

#관련 항목

Practical RTOS Internals · 26 of 53

  1. 1Practical RTOS Internals — 실시간 커널 내부 분석 시리즈 소개
  2. 2RTOS가 필요한 이유 — 일반 OS와의 결정적 차이
  3. 3Task와 Thread 개념 — TCB·상태 머신·생명 주기 분석
  4. 4실시간 스케줄링 알고리즘 비교 — RR·Priority·EDF·RMS
  5. 5Preemption과 Cooperation — 강제 전환 vs 자발 양보
  6. 6인터럽트와 RTOS — ISR Context·Deferred Processing·FromISR API
  7. 7동기화 기초 분석 — Critical Section·Mutual Exclusion·Race Condition
  8. 8Semaphore 개념 분해 — Counting·Binary·P/V 연산
  9. 9Mutex 개념 분해 — Ownership·Recursive·Priority Inheritance
  10. 10큐와 메시지 패싱 — Producer-Consumer·Ring Buffer·전달 의미
  11. 11실시간성 분석 — Latency·Jitter·Deadline·WCET·RMA
  12. 12Ready List 자료구조 분석 — Linked List·Bitmap·O(1) Scheduler
  13. 13Blocked List 자료구조 — Timeout 정렬·Delta List·Two-List Scheme
  14. 14Scheduler 알고리즘 구현 추적 — Next-Task Selection 로직
  15. 15Context Switch 원리 분석 — 레지스터 저장·복원·Stack Frame
  16. 16ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적
  17. 17ARM Cortex-A Context Switch — Mode 전환·SVC·Banked Registers
  18. 18RISC-V Context Switch 분석 — ECALL·mret·CSR
  19. 19RTOS Tick과 타이머 — SysTick·Generic Timer·configTICK_RATE_HZ
  20. 20Tickless 모드 구현 — Idle Tick Suppression·Sleep·Wake 보정
  21. 21Scheduler Latency 측정 기법 — GPIO Toggle·DWT·ftrace·cyclictest
  22. 22RTOS Tracing과 Observability — Tracealyzer·SystemView·ITM/ETM
  23. 23Critical Section 구현 비교 — IRQ Disable·BASEPRI·Spinlock
  24. 24Semaphore 내부 구현 추적 — Counter·Wait List·ISR-Safe Variant
  25. 25Mutex 내부 구현 추적 — Owner·Recursion Count·ISR 금지
  26. 26Priority Inversion 문제 — Mars Pathfinder 사례·Bounded vs Unbounded
  27. 27Priority Inheritance 구현 — Inherit·Disinherit·Chain
  28. 28Priority Ceiling Protocol — Immediate vs Original 비교
  29. 29Queue 내부 구현 추적 — Ring Buffer·2 Wait Lists·Atomic Send/Receive
  30. 30Event Group 분석 — Bit Flag·AND/OR Wait·Sync Barrier
  31. 31ISR-Safe API 설계 — FromISR 패턴·Higher Priority Wake·Deferred Work
  32. 32Deadlock 분석 — 4 조건·Wait-for Graph·Lock Ordering·Timeout
  33. 33Stream Buffer와 Message Buffer — FreeRTOS 10의 Lock-Free SPSC
  34. 34실시간 메모리 요구사항 — Determinism·Fragmentation·WCET
  35. 35FreeRTOS Heap_1~5 분석 — 5종 Allocator의 구조와 트레이드오프
  36. 36TLSF Allocator 분석 — Two-Level Segregated Fit O(1)
  37. 37Static Allocation — 컴파일 타임으로 동적 위험 제거하기
  38. 38Memory Pool — Fixed-Size Block Allocator의 단순함과 강력함
  39. 39Stack Overflow 탐지 — Canary·MPU·Watermark 3중 방어
  40. 40SMP RTOS 설계 — Ready List·Affinity·IPI·Load Balancing
  41. 41SMP Spinlock 구현 — LDREX/STREX·Ticket Lock·MCS·WFE/SEV
  42. 42Software Timer 분석 — Daemon Task·자료구조·ISR-Safe API
  43. 43RTOS System Call — SVC·ECALL·User/Kernel 분리·FreeRTOS-MPU
  44. 44TrustZone과 TF-M — Secure/Non-Secure·NSC Veneer·PSA
  45. 45AMP와 OpenAMP — Heterogeneous SoC·RPMsg·remoteproc
  46. 46C++ in RTOS — RAII·std::thread·ETL·Coroutine
  47. 47FreeRTOS 소스 분석 — tasks.c·queue.c·port.c 추적
  48. 48Zephyr 커널 분석 — k_thread·k_sem·Driver Model
  49. 49RT-Thread 분석 — Object 모델·Components·Smart·Studio
  50. 50RTOS 포팅 가이드 — 새 아키텍처에 옮기는 절차
  51. 51RTOS 선택 가이드 — Footprint·License·Certification·Ecosystem
  52. 52Apache NuttX 분석 — POSIX·PX4·NASA Ingenuity
  53. 53PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL