LINUX系统延时函数

当一个设备驱动需要处理它的硬件的反应时间, 涉及到的延时常常是最多几个毫秒. 在这个情况下, 依靠时钟嘀哒显然不对路.

内核函数 ndelay, udelay, 以及 mdelay 对于短延时好用, 分别延后执行指定的纳秒数, 微秒数或者毫秒数. [27]它们的原型是:

#include
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);

这些函数的实际实现在 , 是体系特定的, 并且有时建立在一个外部函数上. 每个体系都实现 udelay, 但是其他的函数可能或者不可能定义; 如果它们没有定义, 提供一个缺省的基于 udelay 的版本. 在所有的情况中, 获得的延时至少是要求的值, 但可能更多; 实际上, 当前没有平台获得了纳秒的精度, 尽管有几个提供了次微秒的精度. 延时多于要求的值通常不是问题, 因为驱动中的短延时常常需要等待硬件, 并且这个要求是等待至少一个给定的时间流失.

udelay 的实现( 可能 ndelay 也是) 使用一个软件循环基于在启动时计算的处理器速度, 使用整数变量 loos_per_jiffy. 如果你想看看实际的代码, 但是, 小心 x86 实现是相当复杂的一个因为它使用的不同的时间源, 基于什么 CPU 类型在运行代码.

为避免在循环计算中整数溢出, udelay 和 ndelay 强加一个上限给传递给它们的值. 如果你的模块无法加载和显示一个未解决的符号, __bad_udelay, 这意味着你使用太大的参数调用 udleay. 注意, 但是, 编译时检查只对常量进行并且不是所有的平台实现它. 作为一个通用的规则, 如果你试图延时几千纳秒, 你应当使用 udelay 而不是 ndelay; 类似地, 毫秒规模的延时应当使用 mdelay 完成而不是一个更细粒度的函数.

重要的是记住这 3 个延时函数是忙等待; 其他任务在时间流失时不能运行. 因此, 它们重复, 尽管在一个不同的规模上, jitbusy 的做法. 因此, 这些函数应当只用在没有实用的替代时.

有另一个方法获得毫秒(和更长)延时而不用涉及到忙等待. 文件 声明这些函数:

void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds)

前 2 个函数使调用进程进入睡眠给定的毫秒数. 一个对 msleep 的调用是不可中断的; 你能确保进程睡眠至少给定的毫秒数. 如果你的驱动位于一个等待队列并且你想唤醒来打断睡眠, 使用 msleep_interruptible. 从 msleep_interruptible 的返回值正常地是 0; 如果, 但是, 这个进程被提早唤醒, 返回值是在初始请求睡眠周期中剩余的毫秒数. 对 ssleep 的调用使进程进入一个不可中断的睡眠给定的秒数.

通常, 如果你能够容忍比请求的更长的延时, 你应当使用 schedule_timeout, msleep, 或者 ssleep.

[27] udelay 中的 u 表示希腊字母 mu 并且代表 micro.

你可能感兴趣的:(linux驱动开发,LINUX系统)