delays - Information on the various kernel delay / sleep mechanisms

そういえば、delay/sleepの使い分けに関して、2019/6/14付けでドキュメント追加されたのでまとめておく。

---

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/Documentation/timers/timers-howto.rst


# delays - Information on the various kernel delay / sleep mechanisms

> This document seeks to answer the common question: "What is the RightWay (TM) to insert a delay?"

このドキュメントは一般的な質問" delayの正しい導入方法とは何か？”にこたえるものである。

> This question is most often faced by driver writers who have to　deal with hardware delays and who may not be the most intimately　familiar with the inner workings of the Linux Kernel.

この問題は、ハードウェアの遅延に対処する必要があり、Linux Kernel内部の動きに精通していないであろうドライバー実装者がしばしば直面します。

# Inserting Delays

> The first, and most important, question you need to ask is "Is my　code in an atomic context?"  This should be followed closely by "Does　it really need to delay in atomic context?" If so...

まず最初に、もっとも重要な事として、あなたがこの質問を聞くときに、「自分のコードはAtomic contextであるか」を考えねばならない。これはすなわち、「atomic context内でdelayが本当に必要なのか」と同義である。もしそうならば…

## ATOMIC CONTEXT:

> You must use the `*delay` family of functions. These　functions use the jiffie estimation of clock speed　and will busy wait for enough loop cycles to achieve　the desired delay:

"*delay"ファミリーの関数を使わなければならない。これらの関数は、jiffeiesで推定されたクロック速度の予測値を用いて、指定された遅延に対する十分なループサイクルを伴う、busy wait(busy loop)を行う。

`	ndelay(unsigned long nsecs)
	udelay(unsigned long usecs)
	mdelay(unsigned long msecs) `

> udelay is the generally preferred API; ndelay-level precision may not actually exist on many non-PC devices.

udelayは一般的に推奨されるAPIです。ndelay-level precisionは多くの非PC deviceでは実際には存在していない。

> mdelay is macro wrapper around udelay, to account for 	possible overflow when passing large arguments to udelay. 	In general, use of mdelay is discouraged and code should 	be refactored to allow for the use of msleep.

mdelayは、udelayのmacro wrappweであり、udelayでは大きすぎる引数がオーバーフローするのを保護するために用いられます。一般的には、mdelayを用いることは推奨されません、msleepを使用できるようにコードをリファクタリングするべきです。、

## NON-ATOMIC CONTEXT:

> You should use the `*sleep[_range]` family of functions.
There are a few more options here, while any of them may 	work correctly, using the "right" sleep function will help the scheduler, power management, and just make your driver better :)

"*sleep[_range]"ファミリーの関数を使うべきだろう。いくつかの選択肢があるが、"正しい" sleep functionを用いると、スケジューラ―、パワーマネジメントに役立ち、あなたのドライバーをより良くすることができます（笑顔）。


- Backed by busy-wait loop:
    - ` udelay(unsigned long usecs) `
- Backed by hrtimers:
    - ` usleep_range(unsigned long min, unsigned long max)`
- Backed by jiffies / legacy_timers
    - ``` msleep(unsigned long msecs)
		msleep_interruptible(unsigned long msecs) ```

> Unlike the `*delay` family, the underlying mechanism driving each of these calls varies, thus there are quirks you should be aware of.

"*delay" ファミリーと異なり、これらの関数呼び出しを駆動する基本的なメカニズムは一様ではなく、注意するべき癖があります。

### SLEEPING FOR "A FEW" USECS ( < ~10us? ):
- Use udelay
- Why not usleep?
    -  On slower systems, (embedded, OR perhaps a speed-stepped PC!) the overhead of setting up the hrtimers for usleep *may* not be worth it. Such an evaluation will obviously depend on your specific situation, but it is something to be aware of.
    -  遅いシステム（組み込みや、speed stepped中のPC)では、usleepのためにhrtimerを設定するためのオーバーヘッドには価値がない"かも"しれません。あなたの特定の状況によって明らかに依存する評価結果であることを、気を付ける必要があります。

### SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
- Use usleep_range
- Why not msleep for (1ms - 20ms)?
    - Explained originally here: 
        - ` http://lkml.org/lkml/2007/8/3/250 `
    - msleep(1~20) may not do what the caller intends, and 			will often sleep longer (~20 ms actual sleep for any 			value given in the 1~20ms range). In many cases this 			is not the desired behavior.
    - msleep(1～20) は、呼び出し側の意図しない動作をする可能性があり、多くの場合、より長い時間スリープします（1～20 msの範囲内で指定をされたとしても、実際には20msスリープされる）。多くの場合、これは望ましい動作ではありません。
- Why is there no "usleep" / What is a good range?
    - Since usleep_range is built on top of hrtimers, the 			wakeup will be very precise (ish), thus a simple 			usleep function would likely introduce a large number 			of undesired interrupts.
    - usleep_rangeは、hrtimerの上に実装されているため、復帰は非常に正確（らしく）なります。そのために、望ましくない割り込みを多数発生させる可能性があります。

### SLEEPING FOR LARGER MSECS ( 10ms+ )
- Use msleep or possibly msleep_interruptible
- What's the difference?
    - msleep sets the current task to TASK_UNINTERRUPTIBLE 			whereas msleep_interruptible sets the current task to 			TASK_INTERRUPTIBLE before scheduling the sleep. In 			short, the difference is whether the sleep can be ended 			early by a signal. In general, just use msleep unless 			you know you have a need for the interruptible variant. 
    - msleepは、現在のタスクをTASK_UNINTERRUPTIBLE 			にセットします。msleep_interruptible は、現在のタスクをスリープのスケジューリング前にTASK_INTERRUPTIBLE にセットします。つまり、この違いとはシグナルによってスリープがすぐに復帰できるか否かのです。一般に割り込み可能な処理であることが分かっている場合を除き、msleepを使用します。