← Documents Documentation/timers/delay_sleep_functions.rst GitHub 원문 ↗

Linux 6.18.37 · Timers

Kernel delay와 sleep 함수 선택

ndelay·udelay·mdelay, usleep_range, fsleep와 msleep을 context, 정밀도, duration에 따라 선택하는 기준을 설명합니다.

Source pathDocumentation/timers/delay_sleep_functions.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

먼저 atomic context인지 판단한다

delay_sleep_functions.rst:3-62

Delay API 선택의 첫 질문은 현재 code가 sleep할 수 있는가입니다. Hardirq, softirq, spinlock 또는 raw spinlock 보유, preemption disabled 문맥에서는 scheduler에 CPU를 넘길 수 없어 busy-wait 계열만 사용할 수 있습니다. Process context라면 대부분 sleep 계열이 CPU와 전력 면에서 낫습니다.

조건권장 계열
Atomic contextndelay, udelay, mdelay
Sleep 가능, 짧은 us 범위와 tolerance 있음usleep_range 또는 usleep_range_state
Sleep 가능, ms 이상msleep 또는 fsleep
호출부에서 duration 범위가 넓음fsleep이 적절한 내부 방법 선택

Hardware register가 바뀔 때까지 기다린다면 고정 delay보다 read_poll_timeout 계열처럼 condition과 timeout을 함께 표현하는 방법을 우선합니다.

*delay() busy-wait의 오차와 한계

delay_sleep_functions.rst:63-80

ndelay, udelay와 mdelay는 calibrated loop 또는 architecture timer를 돌며 CPU를 계속 점유합니다. 아주 짧은 hardware settling time에는 필요하지만 긴 duration은 scheduler latency와 전력을 악화시킵니다.

udelay가 요청보다 일찍 끝날 수 있는 원인에는 loops_per_jiffy 계산 오차, cache behavior, CPU frequency 변화와 loop instruction 실행 시간이 있습니다. mdelay는 큰 값에서 udelay argument overflow를 피하는 wrapper이지만 긴 busy-wait를 권장한다는 뜻은 아닙니다.

usleep_range와 fsleep·msleep

delay_sleep_functions.rst:81-122

usleep_range(min, max)는 scheduler가 min 이후 max 안에서 wakeup을 다른 timer와 합칠 수 있게 하여 정확도와 전력을 조정합니다. 정확한 한 점보다 hardware가 허용하는 range를 전달해야 timer coalescing 기회가 생깁니다.

msleep은 jiffy resolution 때문에 짧은 값에서 큰 상대 오차가 생길 수 있습니다. fsleep은 요청 duration에 따라 udelay, usleep_range 또는 msleep 계열을 선택해 caller가 경계값을 직접 관리하는 부담을 줄입니다.

/* 20~30 us 사이면 허용 */
usleep_range(20, 30);

/* 범위가 동적으로 크게 변할 수 있음 */
fsleep(delay_us);

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 Delay and sleep mechanisms
4 ==========================
5
6 This document seeks to answer the common question: "What is the
7 RightWay (TM) to insert a delay?"
8
9 This question is most often faced by driver writers who have to
10 deal with hardware delays and who may not be the most intimately
11 familiar with the inner workings of the Linux Kernel.
12
13 The following table gives a rough overview about the existing function
14 'families' and their limitations. This overview table does not replace the
15 reading of the function description before usage!
16
17 .. list-table::
18 :widths: 20 20 20 20 20
19 :header-rows: 2
20
21 * -
22 - `*delay()`
23 - `usleep_range*()`
24 - `*sleep()`
25 - `fsleep()`
26 * -
27 - busy-wait loop
28 - hrtimers based
29 - timer list timers based
30 - combines the others
31 * - Usage in atomic Context
32 - yes
33 - no
34 - no
35 - no
36 * - precise on "short intervals"
37 - yes
38 - yes
39 - depends
40 - yes
41 * - precise on "long intervals"
42 - Do not use!
43 - yes
44 - max 12.5% slack
45 - yes
46 * - interruptible variant
47 - no
48 - yes
49 - yes
50 - no
51
52 A generic advice for non atomic contexts could be:
53
54 #. Use `fsleep()` whenever unsure (as it combines all the advantages of the
55 others)
56 #. Use `*sleep()` whenever possible
57 #. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient
58 #. Use `*delay()` for very, very short delays
59
60 Find some more detailed information about the function 'families' in the next
61 sections.
62
63 `*delay()` family of functions
64 ------------------------------
65
66 These functions use the jiffy estimation of clock speed and will busy wait for
67 enough loop cycles to achieve the desired delay. udelay() is the basic
68 implementation and ndelay() as well as mdelay() are variants.
69
70 These functions are mainly used to add a delay in atomic context. Please make
71 sure to ask yourself before adding a delay in atomic context: Is this really
72 required?
73
74 .. kernel-doc:: include/asm-generic/delay.h
75 :identifiers: udelay ndelay
76
77 .. kernel-doc:: include/linux/delay.h
78 :identifiers: mdelay
79
80
81 `usleep_range*()` and `*sleep()` family of functions
82 ----------------------------------------------------
83
84 These functions use hrtimers or timer list timers to provide the requested
85 sleeping duration. In order to decide which function is the right one to use,
86 take some basic information into account:
87
88 #. hrtimers are more expensive as they are using an rb-tree (instead of hashing)
89 #. hrtimers are more expensive when the requested sleeping duration is the first
90 timer which means real hardware has to be programmed
91 #. timer list timers always provide some sort of slack as they are jiffy based
92
93 The generic advice is repeated here:
94
95 #. Use `fsleep()` whenever unsure (as it combines all the advantages of the
96 others)
97 #. Use `*sleep()` whenever possible
98 #. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient
99
100 First check fsleep() function description and to learn more about accuracy,
101 please check msleep() function description.
102
103
104 `usleep_range*()`
105 ~~~~~~~~~~~~~~~~~
106
107 .. kernel-doc:: include/linux/delay.h
108 :identifiers: usleep_range usleep_range_idle
109
110 .. kernel-doc:: kernel/time/sleep_timeout.c
111 :identifiers: usleep_range_state
112
113
114 `*sleep()`
115 ~~~~~~~~~~
116
117 .. kernel-doc:: kernel/time/sleep_timeout.c
118 :identifiers: msleep msleep_interruptible
119
120 .. kernel-doc:: include/linux/delay.h
121 :identifiers: ssleep fsleep
122

3. 한국어 전문 번역

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

Delay와 sleep 방법 선택

1-15

이 문서는 코드에 delay를 넣는 올바른 방법이 무엇인지라는 흔한 질문에 답한다. 이 문제는 hardware delay를 처리해야 하지만 Linux kernel 내부 동작에는 익숙하지 않을 수 있는 driver 작성자가 특히 자주 마주한다.

아래 표는 사용할 수 있는 function family와 각 방식의 제약을 대략 비교한다. 이 표는 빠른 선택을 돕기 위한 것이며 실제 사용 전에 각 function 설명을 읽는 절차를 대신하지 않는다.

Function family 비교

17-50
비교 항목*delay()usleep_range*()*sleep()fsleep()
구현 기반busy-wait loophrtimertimer list timer다른 방식을 조합
atomic context가능불가능불가능불가능
짧은 구간의 정밀도정밀함정밀함조건에 따라 다름정밀함
긴 구간의 정밀도사용 금지정밀함최대 12.5% slack정밀함
interruptible variant없음있음있음없음

Non-atomic context의 일반 선택 순서

52-61
  • 확신이 없다면 다른 방식의 장점을 조합한 fsleep()을 사용한다.
  • 가능하면 *sleep() family를 사용한다.
  • *sleep()의 정밀도가 충분하지 않을 때 usleep_range*()를 사용한다.
  • 아주 짧은 delay에만 *delay()를 사용한다.

각 function family의 세부 동작과 제한은 이어지는 절에서 설명한다.

*delay() family

63-78

이 function은 추정된 clock speed와 jiffy 값을 사용해 요청한 시간이 지날 만큼 loop를 반복하며 busy-wait한다. udelay()가 기본 구현이고 ndelay()와 mdelay()는 단위와 범위를 달리한 variant다.

주된 사용 목적은 sleep할 수 없는 atomic context에서 delay를 만드는 것이다. Atomic context에 delay를 추가하기 전에는 정말 필요한지 먼저 확인해야 한다.

.. kernel-doc:: include/asm-generic/delay.h
    :identifiers: udelay ndelay

.. kernel-doc:: include/linux/delay.h
    :identifiers: mdelay

usleep_range*()와 *sleep() family

81-101

이 function은 hrtimer 또는 timer list timer를 사용해 요청한 기간 동안 task를 sleep 상태로 둔다. 적절한 function을 선택할 때는 세 가지 성질을 고려한다.

  • hrtimer는 hash 기반 timer list 대신 red-black tree를 사용하므로 비용이 더 크다.
  • 요청한 sleep이 가장 먼저 만료될 timer라서 실제 hardware timer를 다시 programming해야 할 때 hrtimer 비용이 더 커진다.
  • timer list timer는 jiffy 기반이므로 항상 어느 정도 slack을 제공한다.

선택 순서는 다시 말해 확신이 없으면 fsleep(), 가능하면 *sleep(), *sleep()의 정밀도가 부족하면 usleep_range*()다. 먼저 fsleep()의 function 설명을 확인하고 정밀도에 관한 자세한 내용은 msleep() 설명을 확인한다.

Kernel-doc 원본 위치

104-121
.. kernel-doc:: include/linux/delay.h
    :identifiers: usleep_range usleep_range_idle

.. kernel-doc:: kernel/time/sleep_timeout.c
    :identifiers: usleep_range_state

.. kernel-doc:: kernel/time/sleep_timeout.c
    :identifiers: msleep msleep_interruptible

.. kernel-doc:: include/linux/delay.h
    :identifiers: ssleep fsleep

usleep_range(), usleep_range_idle(), ssleep(), fsleep()의 선언과 설명은 include/linux/delay.h에 있고, usleep_range_state(), msleep(), msleep_interruptible()의 구현 문서는 kernel/time/sleep_timeout.c에서 가져온다.