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

Priority Ceiling Protocol — Immediate vs Original 비교

· Hawk · 4분 읽기

#한 줄 요약

“Mutex에 ceiling을 정적으로 부여하고 take 즉시 boost한다” — PI의 take-then-conflict 방식과 달리, 사전에 적극적으로 막는 접근입니다.

이번 글에서는 Priority Ceiling Protocol(PCP)을 살펴봅니다. PI보다 덜 알려졌지만 deadlock 보장 측면에서 강력합니다.

#PCP 동작

각 mutex M에 priority ceiling C(M)을 부여합니다. C(M)이 mutex를 lock할 task 중 최고 priority입니다.

예시 — mutex X: C(X) = 5 (T_high의 priority)

  1. T_low (priority 1)가 X를 take하는 즉시 → T_low의 priority가 5로 boost.
  2. T_med (priority 3)가 ready 되어도 시작 못 함 (T_low의 5 > 3).
  3. T_low가 X를 release하면 priority가 1로 복원.

PCP는 take 즉시 boost합니다. PI는 conflict가 발생한 후에 boost합니다.

#Immediate PCP vs Original PCP

ImmediateOriginal
Boost 시점Take 즉시Take + conflict 시
구현단순복잡 (system ceiling 계산)
Preemption자기 ceiling 위 task만동일 + 다른 mutex ceiling
사용VxWorks·일부 RTOS학술

#Deadlock 방지 증명

  1. T1M1 보유 (ceiling 5) → T1 priority = 5.
  2. T1M2 (ceiling 5)를 시도.
  3. 만약 T2M2를 보유 중이면 → T2 priority ≥ 5 (M2의 ceiling).
  4. T2의 priority가 5 이상이면 T1시작도 못 함 — 모순.
  5. 따라서 T2M2를 보유할 수 없고, M2는 free 상태이므로 T1이 acquire 가능.

결론은 PCP를 쓰면 deadlock이 불가능하다는 것입니다.

이것이 PCP의 가장 큰 매력입니다. Lock order에 무관하게 deadlock이 막힙니다.

#구현 — RTOS API

// VxWorks
semMCreate(SEM_PRIORITY_CEILING, ceiling_priority);
// Zephyr (config 옵션)
CONFIG_PRIORITY_CEILING=y
struct k_mutex mtx;
k_mutex_init(&mtx);
mtx.ceiling = HIGH_PRIO;

FreeRTOS는 PCP를 지원하지 않습니다. PI만 제공합니다.

#System Ceiling — Original PCP

SystemCeiling(t) = max(C(M) for M in locked mutexes at time t)

T_new가 lock을 시도할 때

  • T_new->priority > SystemCeiling이면 proceed.
  • 그 외에는 block.

구현이 복잡합니다. 그래서 Immediate 방식이 훨씬 흔합니다.

#PI vs PCP 비교

PIPImmediate PCP
Boost 발생Conflict 시Take 즉시
Priority 사전 결정불필요필수
Deadlock 방지
Blocking 길이bounded (by critical)bounded (이론 동일)
Unnecessary boost자주 발생자주 발생
구현 복잡도
호환성동적 시스템정적 분석 가능

#단점 — Unnecessary Boost

T_high가 mutex를 사용하지 않는 시점에도 T_lowT_high level로 boost되어, T_med·T_low항상 starved되고 시스템 throughput이 감소합니다.

PCP는 worst case 안전하지만 best case 낭비가 심합니다.

#적용 사례

RTOSDefault옵션
FreeRTOSPIPCP 없음
ZephyrPICONFIG_PRIORITY_CEILING_PROTOCOL
VxWorksPI or PCP양쪽
QNXPIPCP
RTAIPI

대부분의 시스템은 PI를 기본으로 씁니다. PCP는 deadlock 회피가 critical인 환경에서 선택됩니다.

#Immediate PCP 구현 예

typedef struct {
int locked;
int ceiling;
TaskHandle_t owner;
int owner_orig_prio;
} mutex_pcp_t;
int mutex_pcp_take(mutex_pcp_t *m) {
taskENTER_CRITICAL();
if (m->locked) {
/* 누가 보유 중 — 대기 (priority ≥ ceiling이므로 wait가 없어야 정상) */
taskEXIT_CRITICAL();
return ERROR;
}
m->locked = 1;
m->owner = current_task();
m->owner_orig_prio = current_task()->prio;
/* Boost */
current_task()->prio = m->ceiling;
taskEXIT_CRITICAL();
return 0;
}
int mutex_pcp_give(mutex_pcp_t *m) {
taskENTER_CRITICAL();
if (m->owner != current_task()) {
taskEXIT_CRITICAL();
return ERROR;
}
/* Restore */
current_task()->prio = m->owner_orig_prio;
m->locked = 0;
m->owner = NULL;
taskEXIT_CRITICAL();
return 0;
}

#자주 하는 실수

⚠️ Ceiling 계산 실수

max(이 mutex를 쓰는 task priority)로 정확히 잡아야 합니다. 빠지면 PI가 적용되지 않아 inversion이 발생합니다.

⚠️ FreeRTOS에서 PCP를 시도

지원하지 않습니다. PI만 가능합니다.

⚠️ 동적 시스템에 PCP 적용

새 task가 더 높은 priority로 mutex를 사용하면 ceiling을 재계산해야 합니다. 동적 환경에서는 어렵습니다.

#정리

  • PCP는 mutex에 정적 ceiling을 두고 take 즉시 boost합니다.
  • Immediate vs Original 중 Immediate가 훨씬 흔합니다.
  • Deadlock 방지가 자동이며 lock order에 무관합니다.
  • Priority 사전 결정이 필요해서 동적 시스템에서는 적용이 어렵습니다.
  • 채택 사례는 VxWorks·Zephyr입니다. FreeRTOS는 PI만 지원합니다.

다음 편은 Queue 내부 구현입니다.

#관련 항목

Practical RTOS Internals · 28 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