linux 设备驱动程序 时间流 之 延迟执行 -2

关于短延迟:
延迟通过使用jiffies达不到目的,只能使用内核函数:

udelay(unsigned long usecs);
mdelay(unsigned long msecs);

前者用软件循环指定的微妙数,后者调用前者达到延迟毫秒级。udelay函数只能用于获取较短的时间延迟,因为loops_per_second值的精度只有8位,所以,当计算更长的延迟时会积累出相当大的误差。尽管最大能允许的延迟将近1秒(因为更长的延迟就要溢出),推荐的 udelay 函数的参数的最大值是取1000微秒(1毫秒)。延迟大于 11 毫秒时可以使用函数 mdelay。
要特别注意的是 udelay 是个忙等待函数(所以 mdelay 也是),在延迟的时间段内无法运行其他的任务,因此要十分小心,尤其是 mdelay,除非别无他法,要尽量避免使用。
mdelay 在 Linux 2.0 中并不存在,头文件 sysdep.h 弥补了这一缺陷。

任务对列:
未完待续。。。

内核定时器:
内核中维护一个双向的timer_list结构的链表,内核每1秒钟遍历100(与具体的时钟中断的频率有关系?)次该链表,每次都要检查该链表上的timer_list结构的超时值,若超时,则调用相应的注册函数(马上调用吗?),然后从链表中移除这个entry。

注:根据《The Design of Unix Operating System》中关于时钟中断的代码那一段可以看到,在每个时钟中断里,都要检查那个双向的timer_list结构的链表,呵呵。

因此,定时器是另一个竞态资源,即使是在单处理器系统中。定时器函数访问的任何数据结构都要进行保护以防止并发访问,保护方法可以用原子类型(第10章讲述)或者用自旋锁。

删除定时器时也要小心避免竞态。考虑这样一种情况:某一模块的定时器函数正在一个处理器上运行,这时在另一个处理器上发生了相关事件(文件被关闭或模块被删除)。结果是,定时器函数等待一种已不再出现的状态,从而导致系统崩溃。为避免这种竞态,模块中应该用 del_timer_sync 代替 del_timer。如果定时器函数还能够重新启动自己的定时器(这是一种普遍使用的模式),则应该增加一个“停止定时器”标志,并在调用del_timer_sync之前设置。这样定时器函数执行时就可以检查该标志,如果已经设置,就不会用 add_timer 重新调度自己了。

还有一种会引起竞态的情况是修改定时器:先用 del_timer 删除定时器,再用 add_timer 加入一个新的以达到修改目的。其实在这种情况下简单地使用 mod_timer 是更好的方法。



对time_list结构的操纵以及定时器队列的操纵有:
init_timer(...); add_timer(...), del_timer(...), del_timer_sync(...)等等,具体请看转载2

你可能感兴趣的:(数据结构,timer,linux,list,任务,loops)