
Linux延迟和定时器管理
时间是继内存之后常用的资源之一。它用于执行几乎所有的事情:延迟工作、睡眠、调度、超时以及许多其它任务。
时间有两类:
- 绝对时间:指一天的日期和时间,内核使用绝对时间了解具体时间。有一种硬件芯片称为实时时钟(RTC)。
- 相对时间:相对时间的作用是被内核调度程序使用,为了处理相对时间,内核依赖于被称作定时器的CPU功能(外设),也称作内核定时器。
内核定时器分为两个不同的部分
- 标准定时器或系统定时器
- 高精度定时器
标准定时器
-
Jiffy和HZ
Jiffy是在***<linux/jiffies.h>***中声明的内核时间单位,HZ是Jiffies在1s内递增的次数,取决于硬件和内核版本,也决定了时钟中断触发的频率。Jiffies每个增量被称为一个Tick。
不同的系统上采用了不同类型的Jiffy变量防止溢出。
-
定时器API
定时器在内核中表示为timer_list的一个实例:
- expires:定时器到期时间,时间以用节拍表示。
- entry:双向链表,定时器链表入口。
- data:传递给回调函数。
- base:用来指定定时器在哪个CPU上执行。
- function:定时器到期时执行函数的地址。
初始化定时器
-
设置定时器,提供用户定义的回调函数和数据:
-
设置过期时间。当定时器初始化时,需要在启动回调之前设置它的过期时间:
-
释放定时器。定时器用过之后需要释放:
高精度定时器(HRT)
高精度定时器之所以被称为高精度,是因为它的精度能达到微妙(最高可至纳秒),而标准定时器的精度则为毫秒。标准定时器取决于HZ,而HRT实现是基于ktime。<linux/hrtimer.h>
初始化HRT
-
初始化hrtimer。hrtimer初始化之前,需要设置ktime,它代表持续时间:
-
启动hrtimer:
-
取消hrtimer。取消定时器或者查看是否可能取消它:
内核中的延迟和睡眠
延迟有两种类型,取决于代码运行的上下文:原子的或非原子的。<linux/delay.h>
-
原子上下文
原子上下文的任务无法进入睡眠状态,无法进行调度,所以延迟必须使用繁忙-等待。
以下几个函数作用是消耗足够长的时间,达到延迟的效果:
-
ndelay (unsigned long nseus) /* 精度取决于硬件定时器的精度 */
-
udelay (unsigned long usecs)
-
mdelay (unsigned long msecs)
-
-
非原子上下文
非原子上下文中,内核提供 ***sleep[_range]***系列函数,使用哪个函数取决于需要延迟多长时间。
- udelay(unsigned long usecs):基于繁忙-等待循环。睡眠时长小于或等于10us左右建议使用该函数。
- usleep_range(unsigned long min, unsigned long max):依赖于hrtimer,睡眠数微妙到数毫秒(10ms~20ms)时建议使用。
- msleep(unsigned long msecs):由jiffies/传统定时器支持。对于数毫秒以上的长睡眠(10ms+)建议使用该函数。
