← Documents Documentation/core-api/real-time/theory.rst GitHub 원문 ↗

Linux 6.18.37 · Core API

Theory of operation

PREEMPT_RT가 sleeping spin lock, rtmutex priority inheritance와 threaded interrupt를 사용해 kernel latency를 줄이는 원리를 설명합니다.

Source pathDocumentation/core-api/real-time/theory.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

theory.rst:1-116

`PREEMPT_RT`의 핵심은 scheduler가 제어할 수 없는 실행 구간을 줄이는 것입니다. 일반 spin lock을 `rtmutex` 기반 sleeping lock으로 바꾸고 interrupt handler 대부분을 scheduled thread로 이동합니다.

Priority inheritance는 높은 priority task가 낮은 priority lock owner를 기다릴 때 owner를 일시적으로 승격하여 priority inversion을 줄이고 lock 해제를 앞당깁니다.

Threaded interrupt는 짧은 primary handler와 process-context threaded handler로 나뉘며, 후자는 기본 `SCHED_FIFO` priority 50으로 실행됩니다. 이 구조가 높은 priority task의 실질적인 wakeup latency를 낮춥니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 =====================
4 Theory of operation
5 =====================
6
7 :Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
8
9 Preface
10 =======
11
12 PREEMPT_RT transforms the Linux kernel into a real-time kernel. It achieves
13 this by replacing locking primitives, such as spinlock_t, with a preemptible
14 and priority-inheritance aware implementation known as rtmutex, and by enforcing
15 the use of threaded interrupts. As a result, the kernel becomes fully
16 preemptible, with the exception of a few critical code paths, including entry
17 code, the scheduler, and low-level interrupt handling routines.
18
19 This transformation places the majority of kernel execution contexts under the
20 control of the scheduler and significantly increasing the number of preemption
21 points. Consequently, it reduces the latency between a high-priority task
22 becoming runnable and its actual execution on the CPU.
23
24 Scheduling
25 ==========
26
27 The core principles of Linux scheduling and the associated user-space API are
28 documented in the man page sched(7)
29 `sched(7) <https://man7.org/linux/man-pages/man7/sched.7.html>`_.
30 By default, the Linux kernel uses the SCHED_OTHER scheduling policy. Under
31 this policy, a task is preempted when the scheduler determines that it has
32 consumed a fair share of CPU time relative to other runnable tasks. However,
33 the policy does not guarantee immediate preemption when a new SCHED_OTHER task
34 becomes runnable. The currently running task may continue executing.
35
36 This behavior differs from that of real-time scheduling policies such as
37 SCHED_FIFO. When a task with a real-time policy becomes runnable, the
38 scheduler immediately selects it for execution if it has a higher priority than
39 the currently running task. The task continues to run until it voluntarily
40 yields the CPU, typically by blocking on an event.
41
42 Sleeping spin locks
43 ===================
44
45 The various lock types and their behavior under real-time configurations are
46 described in detail in Documentation/locking/locktypes.rst.
47 In a non-PREEMPT_RT configuration, a spinlock_t is acquired by first disabling
48 preemption and then actively spinning until the lock becomes available. Once
49 the lock is released, preemption is enabled. From a real-time perspective,
50 this approach is undesirable because disabling preemption prevents the
51 scheduler from switching to a higher-priority task, potentially increasing
52 latency.
53
54 To address this, PREEMPT_RT replaces spinning locks with sleeping spin locks
55 that do not disable preemption. On PREEMPT_RT, spinlock_t is implemented using
56 rtmutex. Instead of spinning, a task attempting to acquire a contended lock
57 disables CPU migration, donates its priority to the lock owner (priority
58 inheritance), and voluntarily schedules out while waiting for the lock to
59 become available.
60
61 Disabling CPU migration provides the same effect as disabling preemption, while
62 still allowing preemption and ensuring that the task continues to run on the
63 same CPU while holding a sleeping lock.
64
65 Priority inheritance
66 ====================
67
68 Lock types such as spinlock_t and mutex_t in a PREEMPT_RT enabled kernel are
69 implemented on top of rtmutex, which provides support for priority inheritance
70 (PI). When a task blocks on such a lock, the PI mechanism temporarily
71 propagates the blocked task’s scheduling parameters to the lock owner.
72
73 For example, if a SCHED_FIFO task A blocks on a lock currently held by a
74 SCHED_OTHER task B, task A’s scheduling policy and priority are temporarily
75 inherited by task B. After this inheritance, task A is put to sleep while
76 waiting for the lock, and task B effectively becomes the highest-priority task
77 in the system. This allows B to continue executing, make progress, and
78 eventually release the lock.
79
80 Once B releases the lock, it reverts to its original scheduling parameters, and
81 task A can resume execution.
82
83 Threaded interrupts
84 ===================
85
86 Interrupt handlers are another source of code that executes with preemption
87 disabled and outside the control of the scheduler. To bring interrupt handling
88 under scheduler control, PREEMPT_RT enforces threaded interrupt handlers.
89
90 With forced threading, interrupt handling is split into two stages. The first
91 stage, the primary handler, is executed in IRQ context with interrupts disabled.
92 Its sole responsibility is to wake the associated threaded handler. The second
93 stage, the threaded handler, is the function passed to request_irq() as the
94 interrupt handler. It runs in process context, scheduled by the kernel.
95
96 From waking the interrupt thread until threaded handling is completed, the
97 interrupt source is masked in the interrupt controller. This ensures that the
98 device interrupt remains pending but does not retrigger the CPU, allowing the
99 system to exit IRQ context and handle the interrupt in a scheduled thread.
100
101 By default, the threaded handler executes with the SCHED_FIFO scheduling policy
102 and a priority of 50 (MAX_RT_PRIO / 2), which is midway between the minimum and
103 maximum real-time priorities.
104
105 If the threaded interrupt handler raises any soft interrupts during its
106 execution, those soft interrupt routines are invoked after the threaded handler
107 completes, within the same thread. Preemption remains enabled during the
108 execution of the soft interrupt handler.
109
110 Summary
111 =======
112
113 By using sleeping locks and forced-threaded interrupts, PREEMPT_RT
114 significantly reduces sections of code where interrupts or preemption is
115 disabled, allowing the scheduler to preempt the current execution context and
116 switch to a higher-priority task.
117

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

PREEMPT_RT 동작 이론

1-23

SPDX 라이선스 식별자는 GPL-2.0입니다.

동작 이론

저자: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

서문

`PREEMPT_RT`는 Linux kernel을 real-time kernel로 변환합니다. `spinlock_t` 같은 locking primitive를 preempt 가능하고 priority inheritance를 인식하는 `rtmutex` 구현으로 바꾸고 threaded interrupt 사용을 강제하여 이를 달성합니다.

그 결과 entry code, scheduler, low-level interrupt handling routine 같은 일부 critical code path를 제외한 kernel 전체를 preempt할 수 있게 됩니다.

이 변환은 kernel execution context 대부분을 scheduler의 제어 아래 두고 preemption point 수를 크게 늘립니다. 따라서 높은 priority task가 runnable 상태가 된 시점부터 CPU에서 실제로 실행될 때까지의 latency를 줄입니다.

Scheduling policy

24-41

Scheduling

Linux scheduling의 핵심 원리와 관련 user-space API는 `sched(7)` man page에 문서화되어 있습니다.

기본적으로 Linux kernel은 `SCHED_OTHER` scheduling policy를 사용합니다. 이 policy에서는 scheduler가 다른 runnable task와 비교해 현재 task가 공정한 CPU time 몫을 소비했다고 판단할 때 task를 preempt합니다.

그러나 새로운 `SCHED_OTHER` task가 runnable이 되는 즉시 preemption한다고 보장하지 않으므로 현재 task가 계속 실행될 수 있습니다.

이 동작은 `SCHED_FIFO` 같은 real-time scheduling policy와 다릅니다. Real-time policy를 사용하는 task가 runnable이 되고 현재 task보다 priority가 높으면 scheduler가 즉시 그 task를 실행 대상으로 선택합니다. 선택된 task는 보통 event를 기다리며 block하는 방식으로 CPU를 자발적으로 양보할 때까지 계속 실행합니다.

Sleep 가능한 spin lock

42-64

Sleep 가능한 spin lock

여러 lock type과 real-time configuration에서의 동작은 `Documentation/locking/locktypes.rst`에 자세히 설명되어 있습니다.

Non-`PREEMPT_RT` configuration에서 `spinlock_t`를 얻을 때는 먼저 preemption을 끄고 lock을 사용할 수 있을 때까지 능동적으로 spin합니다. Lock이 해제되면 preemption을 다시 켭니다.

Real-time 관점에서 이 방식은 바람직하지 않습니다. Preemption을 끄면 scheduler가 더 높은 priority task로 전환할 수 없어 latency가 늘어날 수 있기 때문입니다.

이를 해결하기 위해 `PREEMPT_RT`는 spinning lock을 preemption을 끄지 않는 sleep 가능한 spin lock으로 바꿉니다. `PREEMPT_RT`의 `spinlock_t`는 `rtmutex`로 구현됩니다.

경합 중인 lock을 얻으려는 task는 spin하는 대신 CPU migration을 끄고 자신의 priority를 lock owner에게 기부하는 priority inheritance를 수행하며, lock을 사용할 수 있을 때까지 자발적으로 schedule out합니다.

CPU migration을 비활성화하면 preemption을 끄는 것과 같은 CPU 고정 효과를 얻으면서도 preemption은 허용할 수 있습니다. 따라서 task는 sleep 가능한 lock을 보유한 동안 같은 CPU에서 계속 실행됩니다.

Priority inheritance

65-82

Priority inheritance

`PREEMPT_RT` kernel의 `spinlock_t`와 `mutex_t` 같은 lock type은 priority inheritance(PI)를 지원하는 `rtmutex` 위에 구현됩니다. Task가 이 lock에서 block하면 PI 메커니즘이 block된 task의 scheduling parameter를 lock owner에게 일시적으로 전파합니다.

예를 들어 `SCHED_FIFO` task A가 `SCHED_OTHER` task B가 보유한 lock에서 block하면 A의 scheduling policy와 priority를 B가 일시적으로 상속합니다. 그 뒤 A는 lock을 기다리며 sleep하고 B는 사실상 system에서 가장 높은 priority task가 됩니다.

이 덕분에 B가 계속 실행하고 진행하여 마침내 lock을 해제할 수 있습니다. B가 lock을 해제하면 원래 scheduling parameter로 돌아가고 task A가 실행을 재개할 수 있습니다.

Threaded interrupt

83-109

Threaded interrupt

Interrupt handler도 preemption disabled 상태이며 scheduler 제어 밖에서 실행되는 code의 원천입니다. `PREEMPT_RT`는 interrupt 처리를 scheduler 제어 아래 두기 위해 threaded interrupt handler를 강제합니다.

강제 threading에서는 interrupt 처리를 두 단계로 나눕니다. 첫 단계인 primary handler는 interrupt가 꺼진 IRQ context에서 실행되며, associated threaded handler를 깨우는 일만 담당합니다.

두 번째 단계인 threaded handler는 `request_irq()`에 interrupt handler로 전달한 function입니다. 이 handler는 kernel이 schedule하는 process context에서 실행됩니다.

Interrupt thread를 깨운 시점부터 threaded 처리가 끝날 때까지 interrupt controller에서 interrupt source를 mask합니다. 따라서 device interrupt는 pending 상태로 남지만 CPU를 다시 trigger하지 않으며, system은 IRQ context에서 빠져나와 scheduled thread에서 interrupt를 처리할 수 있습니다.

기본적으로 threaded handler는 `SCHED_FIFO` scheduling policy와 50의 priority, 즉 `MAX_RT_PRIO / 2`로 실행합니다. 이는 real-time priority 최솟값과 최댓값의 중간입니다.

Threaded interrupt handler가 실행 중 soft interrupt를 발생시키면 해당 soft interrupt routine은 threaded handler가 끝난 뒤 같은 thread 안에서 호출됩니다. Soft interrupt handler를 실행하는 동안에도 preemption은 활성화된 상태로 유지됩니다.

요약

110-116

요약

`PREEMPT_RT`는 sleep 가능한 lock과 강제 threaded interrupt를 사용하여 interrupt 또는 preemption이 비활성화되는 code section을 크게 줄입니다. 그 결과 scheduler가 현재 execution context를 preempt하고 더 높은 priority task로 전환할 수 있습니다.