Linux内核各种delay(延时)机制的选择


Linux内核各种delay(延时)机制的选择

驱动开发者如何选择合适的延时方法呢?

首先,也是最重要的,你要搞明白“自己的代码是否是位于原子上下文的?”,然后是否真的需要在一个原子上下文中延时?

对于原子上下文的情况,你必须使用‘*delay’相关的函数,这些函数使用时钟速度的jiffie预估值并且通过忙等待足够的循环次数实现指定的延时,这些函数如下:

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

udelay通常是首选的API;ndelay在某些非PC设备上可能会不精确;mdelay是基于udelay的宏扩展,用于处理传入udelay过大值而溢出的情况,通常不建议使用mdelay而是重构代码来使用msleep。(毫秒延时已经很长了,msleep允许休眠)

对于非原子上下文,可以使用‘*sleep[_range]’相关函数,对于同一个延时需求可能多个函数都能胜任,不过选择最合适的sleep函数有助于调度器的合理调度,可以优化功耗,也能让你的驱动更好。函数如下:

usleep_range(unsigned long min, unsigned long max)
msleep(unsigned long msecs)
msleep_interruptible(unsigned long msecs)

usleep_range基于hrtimers(高精度时钟)实现,msleep基于jiffies或者传统计时器实现。这些函数的底层实现不同,使用时要注意。

对于小于10us的延时,使用udelay即可,由于时间太短,构造基于hrtimers的usleep在一些速度慢的系统上不划算。当然这取决于你的应用场景,但是要注意到这点。

对于10us-20ms的延时,使用usleep_range,它指定了一个延时范围,最早会在min醒来,最晚会在max醒来。对于1ms-20ms使用msleep常常延时过长(通常都是20ms),这当然不是我们所期望的结果。

为什么没有usleep而是usleep_range?如何选择合适的range?

由于 usleep_range 建立在 hrtimers 之上,唤醒将非常精确(ish),因此一个简单的 usleep 函数可能会引入大量不需要的中断。

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

你提供的范围越大,你不会触发中断的机会就越大; 这应该与特定代码的延迟/性能可接受的上限相平衡。 此处的准确容差因情况而异,因此由调用者确定合理的范围。

如果延时10ms以上,可以使用msleep或者msleep_interruptible,前者设置当前任务状态为TASK_UNINTERRUPTIBLE,后者设置当前任务为TASK_INTERRUPTIBLE,可以通过信号打断。一般使用msleep,除非你有明确的打断延时需求才选择msleep_interruptible。

最后还提供了一个灵活的睡眠函数——fsleep(unsigned long usecs),它可以延时任意长度,但是不可中断。它底层实际上会根据不同的延时长度调用前面的延时函数。

展开阅读全文

页面更新:2024-05-26

标签:可能会   计时器   上下文   功耗   上限   开发者   原子   内核   底层   时钟   函数   长度   合适   机制   需求   情况   代码   数码

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top