FIFOで最高の優先度を持つ特定のCPUに割り当てられたカーネルスレッドがあります。このスレッドは時々スリープしますが、時間間隔はできるだけ正確でなければなりません。したがって、これを念頭に置いてくださいカーネル空間で眠る最も正確な方法は何でしょうか?
これは Documentation/timers/timers-howto.txt からの関連する抜粋です:
非原子的文脈:
_
*sleep[_range]
_ファミリーの関数を使用する必要があります。ここにはさらにいくつかのオプションがありますが、それらのいずれも正しく機能する可能性がありますが、「適切な」スリープ機能を使用すると、スケジューラー、電源管理に役立ち、ドライバーを改善するだけです:)
- ビジーウェイトループに支えられています:
udelay(unsigned long usecs)
- Hrtimersに支えられて:
usleep_range(unsigned long min, unsigned long max)
- Jiffies/legacy_timersに支えられています
msleep(unsigned long msecs)
msleep_interruptible(unsigned long msecs)
_
*delay
_ファミリとは異なり、これらの各呼び出しを駆動する基本的なメカニズムはさまざまであるため、注意が必要な癖があります。「少数の」使用のための睡眠(<〜10us?)
udelay
を使用します
- なぜ
usleep
ではないのですか?
低速のシステムでは、(組み込み、ORおそらくスピードステップのPC!)usleep
のhrtimerを設定するオーバーヘッド)may価値がないかもしれません。そのような評価は明らかにあなたの特定の状況に依存しますが、それは知っておくべきことです。〜USECSのスリープOR小さなミリ秒(10us-20ms):
- _
usleep_range
_を使用する
- なぜ(1ms-20ms)
msleep
しないのですか?
元々ここで説明されています:
http://lkml.org/lkml/2007/8/3/25msleep
(1〜20)は、呼び出し元が意図したとおりに動作しない可能性があり、多くの場合、より長くスリープします(1〜20ミリ秒の範囲で指定された値に対して実際のスリープは約20ミリ秒)。多くの場合、これは望ましい動作ではありません。usleep
がないのはなぜですか/適切な範囲は何ですか?
_usleep_range
_はhrtimersの上に構築されているため、ウェイクアップは非常に正確(ish)になります。したがって、単純なusleep
関数は、望ましくない割り込みを多数導入する可能性があります。
範囲の導入により、スケジューラーは、他の理由で発生した可能性のある他のウェイクアップとウェイクアップを自由に合体させるか、最悪の場合、上限の割り込みを発生させることができます。
指定する範囲が広いほど、割り込みをトリガーしない可能性が高くなります。これは、特定のコードパスの遅延/パフォーマンスの許容上限とバランスを取る必要があります。ここでの正確な許容範囲は状況によって異なります。したがって、適切な範囲を決定するのは呼び出し元に任されています。より大きなミリ秒のスリープ(10ms +)
msleep
またはおそらく_msleep_interruptible
_ [.____を使用してください。]
- 違いは何ですか?
msleep
は現在のタスクを_TASK_UNINTERRUPTIBLE
_に設定しますが、_msleep_interruptible
_はスリープをスケジュールする前に現在のタスクを_TASK_INTERRUPTIBLE
_に設定します。要するに、違いは、信号によって睡眠を早期に終了できるかどうかです。一般に、割り込み可能なバリアントが必要であることがわかっている場合を除いて、msleep
を使用します。
カーネルスレッドを使用して定期的なタスクを実装するために、hrtimerとwaitqueueの組み合わせを使用しました。
wait_event()/wait_event_timeout()
を使用して待機キューのカーネルスレッドをブロックしますwake_up()/wake_up_all()
また、見つかったばかりで、hrtimer_init_sleeper()
およびschedule()
を使用してスリープを実装できます。 __ wait_event_hrtimeout() または do_nanosleep() を参照してください。しかし、私はそれを試したことがありません。