如何在Linux内核空间中睡觉?

And*_*asa 5 linux linux-kernel thread-sleep

我有一个内核线程,它在具有FIFO和最高优先级的特定CPU上分配.该线程不时休眠,但时间间隔必须尽可能精确.那么考虑到这一点,在内核空间中最精确的睡眠方式是什么?

Sam*_*nko 17

以下是来自Documentation/timers/timers-howto.txt的相关摘录:

非原子背景:

您应该使用*sleep[_range]函数系列.这里还有一些选项,虽然其中任何一个都可以正常工作,使用"正确"的睡眠功能将有助于调度程序,电源管理,并让你的驱动程序更好:)

  • 由busy-wait循环支持:
    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家庭不同,驱动这些呼叫的基本机制各不相同,因此您应该注意一些怪癖.

睡觉"少数"USECS(<~10us?)

  • 使用 udelay
    • 为什么不usleep呢?
      在较慢的系统上,(嵌入式,或者可能是速度步进的PC!)设置hrtimers的开销usleep 可能不值得.这样的评估显然取决于您的具体情况,但需要注意的是.

睡觉~USECS或小型MSECS(10us - 20ms):

  • 使用 usleep_range
    • 为什么不msleep(1ms - 20ms)?
      最初在这里解释:
      http://lkml.org/lkml/2007/8/3/250
      msleep(1~20)可能无法执行调用者的意图,并且通常会睡得更久(实际睡眠时间约为20毫秒) 1~20ms范围).在许多情况下,这不是理想的行为.
    • 为什么没有usleep/什么是好的范围?
      由于usleep_range构建在hrtimers之上,唤醒将非常精确(ish),因此简单的 usleep功能可能会引入大量不需要的中断.

      通过引入范围,调度程序可以自由地将唤醒与其他可能因其他原因发生的唤醒合并,或者在最坏的情况下,为您的上限触发中断.

      您提供的范围越大,您触发中断的可能性就越大; 这应该与特定代码路径的延迟/性能的可接受上限相平衡.这里的精确公差是特定于情况的,因此留给调用者来确定合理的范围.

睡眠更大的MSECS(10ms +)

  • 使用msleep或可能msleep_interruptible
    • 有什么不同?
      msleep将当前的任务TASK_UNINTERRUPTIBLE ,而msleep_interruptible把当前任务 TASK_INTERRUPTIBLE调度睡觉前.简而言之,不同之处在于睡眠是否可以通过信号提前结束.一般情况下,只要使用,msleep除非您知道您需要可中断的变体.


ale*_*der 1

我使用 hrtimer 和 waitqueue 的组合来使用内核线程实现周期性任务:

  1. 创建 waitqueue 和定期 hrtimer
  2. 使用阻塞等待队列上的内核线程wait_event()/wait_event_timeout()
  3. 在 hrtimer 回调调用中wake_up()/wake_up_all()

另外,刚刚发现,您可以使用hrtimer_init_sleeper()和实现睡眠schedule(),请参阅__wait_event_hrtimeout()do_nanosleep()。但我没有尝试过。