一、用途
用于在未来某个特定的时间点(基于时钟滴答)调度执行某个函数,同时在时间点到来前不会阻塞当前进程。
eg:轮询设备状态、关闭软驱马达
二、特性
1. 是一个数据结构
2. 任务可重新运行(自己注册)
3. 只会在注册自己的处理器上运行
4. 异步执行,故在单处理器系统上,是竞态的潜在来源(定时器访问的数据结构需进行并发访问保护:原子变量或自旋锁)
5. 即使不是抢占式内核,且CPU忙于内核空间,定时器也会在正确的时间到期
三、接口
struct timer_list {
/* ... */ //未列出字段,以下为公共字段
unsigned long expires; //期望定时器执行的jiffies值
void (*function)(unsigned long);//到达jiffies值时,执行此函数
unsigned long data; //参数(参数的数据结构的指针强制转换成ulong格式)
}
使用方法:
1. 初始化:调用init_timer 或 将TIMER_INITIALIZER赋予某个静态结构
2. 修改三个公共字段,然后 add_timer
3. 定时器到期前可禁止:del_timer
其他接口:
int mod_timer(struct timer_list *timer, unsigned long expires);
/* 更新定时器到期时间 */
int del_timer_sync(struct timer_list *timer);
/* 确保返回时无CPU在运行定时器,在SMP系统上避免竞态
注意:非原子上下文调用时可能会休眠,其他情况会进入忙等待
小心在拥有锁时调用
确保不发生重新注册(可用一个标志来实现) */
int timer_pending(const struct timer_list * timer);
/* 判断定时器是否在调度运行 */
四、内核实现
timer_list结构的base字段包含一个指针,指向per-CPU数据结构。该指针告诉我们哪个CPU在运行定时器,若为NULL,则定时器未调度运行。
注册定时器时(add_timer或mod_timer),最终会由internal_add_timer执行,该函数将新的定时器添加到与当前CPU关联的“级联表”(里面含有一个定时器双向链表)中。
当__run_timers被激发时,会执行当前定时器滴答上的所有挂起的定时器。