web-dev-qa-db-ja.com

Linuxカーネルスペースでスリープする方法は?

FIFOで最高の優先度を持つ特定のCPUに割り当てられたカーネルスレッドがあります。このスレッドは時々スリープしますが、時間間隔はできるだけ正確でなければなりません。したがって、これを念頭に置いてくださいカーネル空間で眠る最も正確な方法は何でしょうか?

6
Andreea Tanasa

これは 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/25
      msleep(1〜20)は、呼び出し元が意図したとおりに動作しない可能性があり、多くの場合、より長くスリープします(1〜20ミリ秒の範囲で指定された値に対して実際のスリープは約20ミリ秒)。多くの場合、これは望ましい動作ではありません。
    • usleepがないのはなぜですか/適切な範囲は何ですか?
      _usleep_range_はhrtimersの上に構築されているため、ウェイクアップは非常に正確(ish)になります。したがって、単純なusleep関数は、望ましくない割り込みを多数導入する可能性があります。

      範囲の導入により、スケジューラーは、他の理由で発生した可能性のある他のウェイクアップとウェイクアップを自由に合体させるか、最悪の場合、上限の割り込みを発生させることができます。

      指定する範囲が広いほど、割り込みをトリガーしない可能性が高くなります。これは、特定のコードパスの遅延/パフォーマンスの許容上限とバランスを取る必要があります。ここでの正確な許容範囲は状況によって異なります。したがって、適切な範囲を決定するのは呼び出し元に任されています。

より大きなミリ秒のスリープ(10ms +)

  • msleepまたはおそらく_msleep_interruptible_ [.____を使用してください。]
    • 違いは何ですか?
      msleepは現在のタスクを_TASK_UNINTERRUPTIBLE_に設定しますが、_msleep_interruptible_はスリープをスケジュールする前に現在のタスクを_TASK_INTERRUPTIBLE_に設定します。要するに、違いは、信号によって睡眠を早期に終了できるかどうかです。一般に、割り込み可能なバリアントが必要であることがわかっている場合を除いて、msleepを使用します。
25
Sam Protsenko

カーネルスレッドを使用して定期的なタスクを実装するために、hrtimerとwaitqueueの組み合わせを使用しました。

  1. ウェイトキューと定期的なhrtimerを作成する
  2. wait_event()/wait_event_timeout()を使用して待機キューのカーネルスレッドをブロックします
  3. hrtimerコールバック呼び出しでwake_up()/wake_up_all()

また、見つかったばかりで、hrtimer_init_sleeper()およびschedule()を使用してスリープを実装できます。 __ wait_event_hrtimeout() または do_nanosleep() を参照してください。しかし、私はそれを試したことがありません。

0
alexander