内核延时函数接口
延时的函数有delay
和sleep
两种类型:
delay接口
void ndelay(unsigned long nsecs);//纳秒延时 void udelay(unsigned long usecs);//微妙延时 void mdelay(unsigned long msecs);//毫秒延时
sleep接口
void msleep(unsigned int msecs);//毫秒级延时 long msleep_interruptible(unsigned int msecs);//毫秒级延时,可被信号打断 void ssleep(unsigned int seconds);//秒级延时
delay和sleep的区别
delay
型延时:忙等待,占用CPU资源,延迟过程无法进行其他任务。
sleep
型延时:休眠,不占用CPU资源,其它模块此时可以使用CPU资源。
低分辨率定时器
jiffies和HZ
jiffies
:全局变量,表示系统启动以来产生的节拍数。每产生一次中断,jiffies
自动加一。
HZ
:赫兹,也叫节拍率,表示每秒种产生多少次中断。
例如:HZ
为200
,代表每秒产生200
次中断,那2
秒钟jiffies
的值就应该是400
。因此系统的运行时间可以用jiffies/HZ表示。
一秒钟:jiffies
+ HZ
表示一秒钟
原因:内核中统计时间是通过jiffies,因此要比较时间或者定时也是通过jiffies。
例如程序运行一秒钟,内核如何知道运行了一秒?答案是运行一秒后的jiffies值和运行前的jiffies值进行比较,如果相差为一个HZ,则代表一秒钟。jiffies+HZ其实就是一秒后jiffies的值,所以jiffies+HZ可以间接表示一秒钟。
定时2秒:jiffies
+ 2*HZ
。以此类推
获取当前的jiffies
值,可以用get_jiffies_64()
函数。
将时间转为对应的jiffies
值,可以用msecs_to_jiffies()
等函数,例如msecs_to_jiffies(1000)
代表1秒,函数返回值其实就是HZ
。
相关接口
#include<linux/timer.h> struct timer_list { struct list_head list; unsigned long expires; //定时器到期时间,传入的是jiffies值 unsigned long data; //作为参数被传入定时器处理函数 void (*function)(unsigned long); };
void init_timer(struct timer_list * timer);//初始化定时器 void add_timer(struct timer_list * timer);//添加一个定时器 int mod_timer(struct timer_list *timer, unsigned long expires);//修改定时器的定时时间expires int del_timer(struct timer_list * timer);//删除定时器
unsigned int jiffies_to_msecs (const unsigned long j);//将jiffies转为对应的毫秒值 unsigned int jiffies_to_usecs (const unsigned long j);//将jiffies转为对应的微秒值 unsigned long msecs_to_jiffies (const unsigned int m);//将毫秒值转为对应的jiffies unsigned long usecs_to_jiffies (const unsigned int u);//将微秒值转为对应的jiffies
定时器使用示例
使用步骤:
1、调用init_timer
初始化一个定时器,给struct timer_list
各成员赋值。
2、调用add_timer
将定时器添加到内核定时器链表,时间到后回调函数自动调用,用mod_timer
修改expires
的值可实现循环定时。
3、不需要定时器时,调用del_timer
删除。
单次定时
加载驱动一秒钟后,打印出“timer handler, data:520
”:
#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h>//jiffies在此头文件中定义 #include <linux/timer.h>//struct timer_list struct timer_list timer; static void timer_handler (unsigned long arg) { printk("timer handler, data:%d\n", arg); } static int __init my_init(void) { printk("%s enter\n", __func__); init_timer(&timer); timer.expires = get_jiffies_64() + msecs_to_jiffies(1000);//定时1秒 timer.function = timer_handler; timer.data = 520; add_timer(&timer); return 0; } static void __exit my_exit(void) { printk("%s enter\n", __func__); del_timer(&timer); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
循环定时
实现循环定时就是在定时时间到了之后,调用mod_timer函数再次修改定时时间。
每隔一秒钟打印“timer handler, data:520
”
#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h>//jiffies在此头文件中定义 #include <linux/timer.h>//struct timer_list struct timer_list timer; static void timer_handler (unsigned long arg) { printk("timer handler, data:%d\n", arg); mod_timer(&timer, get_jiffies_64() + msecs_to_jiffies (1000)); } static int __init my_init(void) { init_timer(&timer); timer.expires = get_jiffies_64() + msecs_to_jiffies (1000);//定时1秒 timer.function = timer_handler; timer.data = 520; add_timer(&timer); return 0; } static void __exit my_exit(void) { del_timer(&timer); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
end
往期推荐