定时器
1. 指定timeout时刻执行超时处理函数
2. 一旦到期,内核会删除该定时器,超时处理函数只会执行一次
3. 定时器基于软中断实现,在定时器的处理函数中,不允许休眠
数据结构
头文件 #include <linux/timer.h>

expires: 不是超时时间,而是将来的某个时刻点 即 jiffies + timeout
代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
MODULE_DESCRIPTION("Frocheng: Driver for DEMO!");
MODULE_AUTHOR("Frodo Cheng");
MODULE_LICENSE("GPL");
MODULE_VERSION("V0.0.1");
#define HELLO_TIMEOUT_SEC (1ULL * HZ)
static struct timer_list hello_timer;
static char* name = "HelloTimer";
static void timer_handle_cb(struct timer_list * pt)
{
printk("===[frocheng]===[%s]===[%s]===[%d]===[%s]===\n",__FILE__, __func__, __LINE__, name);
mod_timer(&hello_timer, jiffies + 2 * HELLO_TIMEOUT_SEC);
}
static int __init hello_init(void)
{
printk("===[frocheng]===[%s]===[%s]===[%d]===[Hello !]===\n",__FILE__, __func__, __LINE__);
hello_timer.expires = jiffies + 2 * HELLO_TIMEOUT_SEC;
init_timer_key(&hello_timer, timer_handle_cb, 0, name, NULL);
add_timer(&hello_timer);
return 0;
}
static void __exit hello_exit(void)
{
del_timer(&hello_timer);
printk("===[frocheng]===[%s]===[%s]===[%d]===[Bye bye...]===\n",__FILE__, __func__, __LINE__);
}
module_init(hello_init);
module_exit(hello_exit);
由于超时处理函数中,有一个prink的操作,便不试验了,把这个printk的操作,放到工作队列中去处理。
代码,工作队列
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
MODULE_DESCRIPTION("Frocheng: Driver for DEMO!");
MODULE_AUTHOR("Frodo Cheng");
MODULE_LICENSE("GPL");
MODULE_VERSION("V0.0.1");
#define HELLO_TIMEOUT_SEC (1ULL * HZ)
static struct timer_list hello_timer;
static struct work_struct w;
static char* name = "HelloTimer";
static void wq_handle_cb(struct work_struct * w)
{
printk("===[frocheng]===[%s]===[%s]===[%d]===[%s]===\n",__FILE__, __func__, __LINE__, name);
}
static void timer_handle_cb(struct timer_list * pt)
{
mod_timer(&hello_timer, jiffies + 2 * HELLO_TIMEOUT_SEC);
schedule_work(&w);
}
static int __init hello_init(void)
{
printk("===[frocheng]===[%s]===[%s]===[%d]===[Hello !]===\n",__FILE__, __func__, __LINE__);
INIT_WORK(&w, wq_handle_cb);
hello_timer.expires = jiffies + 2 * HELLO_TIMEOUT_SEC;
init_timer_key(&hello_timer, timer_handle_cb, 0, name, NULL);
add_timer(&hello_timer);
return 0;
}
static void __exit hello_exit(void)
{
del_timer(&hello_timer);
printk("===[frocheng]===[%s]===[%s]===[%d]===[Bye bye...]===\n",__FILE__, __func__, __LINE__);
}
module_init(hello_init);
module_exit(hello_exit);
结果

注意:
由于是 ONE SHOT 方式的timer,如果需要循环的执行,那么就需要在 callback 中
1. 不断的更新 expires 域的值
2. 不断的add_timer
3. 为了安全 在 1,2之前先 del_timer(),因为,如果执行到了处理函数,内核已经执行了 del_timer(),但是即便如此,此时 del_timer() 也无影响。
但是以上三步的执行路径并不具备原子性,所以用一个 mod_timer(),一个原子性操作的接口,完成以上三步。
本文深入解析Linux定时器的工作原理,包括其数据结构、关键API如init_timer_key、add_timer及mod_timer的使用方法,以及如何避免定时器处理函数中的休眠操作。通过具体代码示例,展示了如何创建和管理一个基于软中断的定时器,特别强调了在超时处理函数中调用工作队列以处理可能引起阻塞的任务。
1万+

被折叠的 条评论
为什么被折叠?



