linux驱动-定时器教程
定时器介绍在 Linux 内核驱动开发中定时器Timer是一个基于jiffies系统时钟滴答数运作的核心机制用于在指定时间后执行特定任务。其实现位于kernel/linux/timer.h和kernel/timer.c文件中。定时器不是从某个时刻开始“倒计时”而是设定一个未来的绝对时间点expires。系统时钟中断会不断检查当前jiffies是否到达该目标值一旦到达内核就会执行预设的超时函数。定时器类似于一种软件中断当系统时钟滴答数到达特定值时触发中断系统执行超时函数而且是处于非进程的上下文中所以调度函数必须遵守以下规则没有 current 指针、不允许访问用户空间。因为没有进程上下文相关代码和被中断的进程没有任何联系。不能执行休眠或可能引起休眠的函数和调度。任何被访问的数据结构都应该针对并发访问进行保护以防止竞争条件。内核定时器的调度函数运行过一次后就不会再被运行了相当于自动注销但可以通过在被调度的函数中重新调度自己来周期运行。在SMP系统中调度函数总是在注册它的同一CPU上运行以尽可能获得缓存的局域性。操作步骤1.初始化void init_timer(struct timer_list *timer); // 初始化定时器结构体。 void setup_timer(struct timer_list *timer, (*function)(unsigned long), unsigned long data);//初始化时一并设置超时函数和参数。2.注册/开启计时器要想定时器生效还需要将定时器添加到内核专门的链表中void add_timer(struct timer_list *timer)3.重新注册修改要修改一个定时器的调度时间可以通过调用mod_timer(struct timer_list *timer, unsigned long expires)。mod_timer()会重新注册定时器到内核而不管定时器函数是否被运行过。Linux 内核定时器是“一次性”的触发一次就失效了。如果想让超时函数再次被调用必须重新激活它。4.注销注销一个定时器可以通过del_timer(struct timer_list *timer)或del_timer_sync(struct timer_list *timer)。其中del_timer_sync是用在 SMP 系统上的在非SMP系统上它等于del_timer当要被注销的定时器函数正在另一个 cpu 上运行时del_timer_sync()会等待其运行完所以这个函数会休眠。另外还应避免它和被调度的函数争用同一个锁。对于一个已经被运行过且没有重新注册自己的定时器而言注销函数其实也没什么事可做。int timer_pending(const struct timer_list *timer);这个函数用来判断一个定时器是否被添加到了内核链表中以等待被调度运行。注意当一个定时器函数即将要被运行前内核会把相应的定时器从内核链表中删除相当于注销。函数列表分类函数名作用参数说明返回值初始化init_timer初始化定时器结构体。这是使用前必须做的第一步。timer: 指向struct timer_list的指针。无初始化setup_timer旧版API初始化时一并设置超时函数和参数。timer: 定时器指针function: 超时回调data: 传给回调的参数。无初始化timer_setup新版API推荐类型更安全的初始化方式替代setup_timer。timer: 定时器指针callback: 超时回调flags: 标志位通常填0。无启动/修改add_timer将已设置好超时时间expires的定时器激活加入内核调度队列。timer: 定时器指针。无启动/修改mod_timer最常用。用于修改定时器的超时时间。若定时器未激活则会激活它。timer: 定时器指针expires:绝对超时时间通常用jiffies 偏移。1修改了已激活的定时器0定时器原本未激活。启动/修改mod_timer_pending安全版本。仅当定时器当前处于激活状态时才修改超时时间。同mod_timer。同mod_timer。停止/删除del_timer停用定时器。不等待正在其他CPU执行的回调函数完成适合中断上下文。timer: 定时器指针。1成功停用一个激活的定时器0定时器原本未激活。停止/删除del_timer_sync同步版本。会等待其他CPU上的回调函数执行完毕。不能在中断上下文调用。timer: 定时器指针。1成功停用一个激活的定时器0定时器原本未激活。辅助timer_pending检查定时器当前是否处于激活挂起状态。timer: 定时器指针。1激活状态0未激活。辅助msecs_to_jiffies将毫秒转换为jiffies单位必须使用此函数以保证兼容性。m: 要转换的毫秒数。转换后的jiffies值。辅助usecs_to_jiffies将微秒转换为jiffies单位。m: 要转换的微秒数。转换后的jiffies值。