Linux驱动之定时器(mod_timer)

本文深入讲解Linux内核定时器的使用方法,包括定时器结构、API函数、使用流程及实例。通过具体代码示例,展示如何创建、初始化、设置超时时间及处理函数,以及如何在驱动中使用定时器。

文章摘自一下几位网友。非常感谢他们。

http://blog.sina.com.cn/s/blog_57330c3401011cq3.html

#include<linux/timer.h>struct timer_list { 
    struct list_head list;  
    unsigned long expires; //定时器到期时间 
    unsigned long data; //作为参数被传入定时器处理函数
    void (*function)(unsigned long);
};

Linux的内核中定义了一个定时器的结构:

 

利用这个结构我们可以在驱动中很方便的使用定时器。

 

一: timer的API函数:

初始化定时器:

void init_timer(struct timer_list * timer);

增加定时器:

void add_timer(struct timer_list * timer);

删除定时器:

int del_timer(struct timer_list * timer);

修改定时器的expire:

int mod_timer(struct timer_list *timer, unsigned long expires);

 

二:使用定时器的一般流程为:

(1)创建timer、编写超时定时器处理函数function;

(2)为timer的expires、data、function赋值;

(3)调用add_timer将timer加入列表----添加一个定时器;

(4)在定时器到期时,function被执行;

(5)在程序中涉及timer控制的地方适当地调用del_timer、mod_timer删除timer或修改timer的expires。

 

三:下面看一个例子:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/init.h>
#include <linux/timer.h>
struct timer_list mytimer;//定义一个定时器
void  mytimer_ok(unsigned long arg)
{
           printk("Mytimer is ok\n");
           printk("receive data from timer: %d\n",arg);
   }
 
static int __init hello_init (void)
{
    printk("hello,world\n");
    init_timer(&mytimer);     //初始化定时器
    mytimer.expires = jiffies+100;//设定超时时间,100代表1秒
    mytimer.data = 250;    //传递给定时器超时函数的值
    mytimer.function = mytimer_ok;//设置定时器超时函数
    add_timer(&mytimer); //添加定时器,定时器开始生效
    return 0;
}
   
static void __exit hello_exit (void)
 
{
    del_timer(&mytimer);//卸载模块时,删除定时器
    printk("Hello module exit\n");
}
 
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("CXF");
MODULE_LICENSE("Dual BSD/GPL");

四:交叉编译后,放到开发板上:

#insmod timer.ko

可以发现过一秒后定时器过期函数被执行了,打印出了信息,250也被正确传递了。

#rmmod timer.ko

我们也可以用lsmod | grep timer  来查看是否加载了timer驱动。

可以用dmesg | tail -20 查看驱动打印的信息

dmesg -c 清楚信息

 

五:进一步理解定时器:

在上面的定时器超时函数mytimer_ok(unsigned long arg)中,添加如下代码:

mytimer.expires = jiffies+100;//设定超时时间,100代表1秒

 mytimer.function = mytimer_ok;//设置定时器超时函数

add_timer(&mytimer); //添加定时器,定时器开始生效

 

交叉编译后,放到开发板上

#insmod timer.o

  发现每隔一秒,mytimer_ok函数就执行一次,这是因为每次定时器到期后,都

又重新给它设置了一个新的超时时间,并且新的超时函数指向自己,形成一个递

归,所以就会一直执行下去。

  #rmmod timer

可以卸载模块,当然打印也就结束了,注意因为定时器超时函数不停的打印信息

,导致输入上面的命令时会被定时器超时函数不停的打印信息淹没,不用管他,

耐心的把上面的命令输完就可以成功卸载。

https://blog.youkuaiyun.com/qq_41673920/article/details/81363926

<think>嗯,用户的问题是关于Linux系统在电源管理(pm)流程中,suspend时使用del_timer删除定时器,resume时用add_timer添加定时器,但在定时器回调函数中调用mod_timer导致系统崩溃的解决方案。这个问题涉及内核定时器子系统和电源管理的交互,属于比较底层的技术问题。 用户提供的参考资料很有价值,引用[1]介绍了Linux timer子系统的架构,提到定时(timer)和计时(timekeeping)的区别;引用[2]详细说明了del_timer和del_timer_sync的区别;引用[3]展示了应用层定时器的使用;引用[4]则提到RT-Thread中rt_timer_start函数的问题,虽然不在Linux内核中,但说明了对同一个timer进行多次操作可能引发的链表破坏问题。 用户的实际需求是解决crash问题。可能的原因是: 1. 定时器生命周期管理不当:在suspend时删除定时器,但定时器可能在删除前已经被激活,导致resume后产生冲突。 2. 竞态条件:在suspend/resume过程中,定时器可能被同时触发,导致mod_timer操作和系统状态不一致。 3. 定时器上下文问题:在中断上下文调用了可能休眠的函数。 4. 多次操作同一个timer:类似引用[4]提到的问题,导致定时器链表被破坏。 解决方案需要考虑: - 改用del_timer_sync确保定时器处理函数退出后再继续操作 - 检查定时器回调函数是否在中断上下文执行,避免调用可能休眠的函数 - 使用timer_pending检查定时器状态 - 考虑使用timer_shutdown完全关闭定时器 - 添加适当的同步机制如自旋锁保护共享数据 用户可能是在开发内核模块或驱动时遇到这个问题,说明ta有一定内核开发经验。我会提供详细的解决步骤,包括代码示例和原理说明,并提醒谨慎操作防止系统不稳定。同时给出相关问题帮助用户深入理解定时器机制。 </think>以下是针对 Linux 系统中在电源管理(PM)流程中结合 `del_timer`/`add_timer` 和 `mod_timer` 导致系统崩溃的**根本原因分析与解决方案**,结合了内核定时器机制和 PM 设计的核心原理: --- ### **根本原因分析** 1. **定时器生命周期管理冲突** - `suspend` 时调用 `del_timer` 仅**解除定时器与处理器的绑定**,但**未清除其内部状态**(如 `.function` 回调指针)。若在 `del_timer` 后、`resume` 前的阶段回调函数被触发(例如中断延迟),此时定时器处于"游离状态",在回调中调用 `mod_timer` 会操作一个已被移除的定时器,导致内核链表损坏(如引用[4]所述的链表节点自环问题)。 2. **竞态条件(Race Condition)** - `resume` 后调用 `add_timer` **重新激活定时器**时,若此时定时器回调已在其他 CPU 上运行(例如中断下半部),`mod_timer` 可能**并发修改定时器内部状态**,破坏定时器链表(如 `timer_list->entry` 的 `next/prev` 指针异常引用[4])。 3. **中断上下文限制** 定时器回调默认在**中断上下文**执行(如 `softIRQ`)。若回调中调用 `mod_timer` 时恰逢系统处于 `suspend` 后的低功耗状态,可能因访问休眠设备或未初始化的资源触发内核异常(如无效内存访问)。 --- ### **解决方案** #### 1. **替换 `del_timer` → `del_timer_sync`** - **作用**:确保在 `suspend` 路径中**等待正在执行的回调函数退出**,避免定时器"游离状态"(引用[2]): ```c void suspend_handler() { del_timer_sync(&my_timer); // 阻塞直至回调结束 } ``` - **注意**:`del_timer_sync` 可能在中断上下文中阻塞,需确认调用位置合法性(如 `suspend` 流程通常处于进程上下文)。 #### 2. **替换 `add_timer` → `mod_timer`** - **作用**:统一使用 `mod_timer` 管理定时器状态,避免手动管理激活/禁用状态: ```c void resume_handler() { mod_timer(&my_timer, jiffies + msecs_to_jiffies(100)); // 安全激活或更新 } ``` - **原理**:`mod_timer` 内部自动处理定时器是否已激活的逻辑,避免重复加入链表(引用[4]问题的预防)。 #### 3. **回调函数中增加状态保护** - 在回调函数开头检查系统状态,阻止在 `suspend` 期间操作: ```c static void timer_callback(struct timer_list *t) { if (system_state != SYSTEM_RUNNING) // 检查系统状态 return; // 安全执行 mod_timer() 或其他操作 mod_timer(&my_timer, ...); } ``` - **关键变量**:使用 `system_state`(`SYSTEM_SUSPEND`/`SYSTEM_RUNNING`)或自定义 PM 状态标志。 #### 4. **使用 `timer_setup` + `timer_shutdown`(推荐)** - **Linux 4.15+** 引入 `timer_shutdown`,彻底销毁定时器(清除回调等元数据): ```c void suspend_handler() { timer_shutdown_sync(&my_timer); // 替代 del_timer_sync } void resume_handler() { timer_setup(&my_timer, timer_callback, 0); // 重新初始化 mod_timer(&my_timer, ...); } ``` - **优势**:避免残留回调指针,从根源解决"游离定时器"问题。 --- ### **验证与调试建议** 1. **内核调试工具** - 启用 `CONFIG_DEBUG_OBJECTS_TIMERS` 检测定时器使用错误(如重复初始化)。 - 使用 `ftrace` 跟踪定时器生命周期: ```bash echo function > /sys/kernel/tracing/current_tracer echo '*timer*' > /sys/kernel/tracing/set_ftrace_filter ``` 2. **竞态检测** - 在 `suspend/resume` 和回调函数中增加 `spin_lock_irqsave` 保护共享数据(谨慎使用,避免死锁)。 --- ### **典型修复代码示例** ```c static struct timer_list my_timer; static void my_timer_callback(struct timer_list *t) { if (system_state < SYSTEM_RUNNING) // 跳过非运行状态 return; // 业务逻辑 mod_timer(&my_timer, jiffies + HZ); } static int driver_suspend(struct device *dev) { timer_shutdown_sync(&my_timer); // 安全销毁定时器 return 0; } static int driver_resume(struct device *dev) { timer_setup(&my_timer, my_timer_callback, 0); // 重新初始化 mod_timer(&my_timer, jiffies + HZ); // 激活 return 0; } ``` --- ### **相关问题** 1. `del_timer_sync` 在中断上下文中调用为何会导致死锁?如何避免? 2. Linux 内核的 `system_state` 变量包含哪些状态?如何在内核模块中安全使用? 3. `timer_shutdown_sync` 与 `del_timer_sync` 在实现机制上有何本质区别? 4. 在实时系统(如 RT-Preempt)中,定时器回调函数的执行上下文有何特殊限制? > 引用原理: > - 定时器游离状态与链表损坏:[^4] > - `del_timer_sync` 的阻塞行为:[^2] > - 中断上下文限制与休眠检测:[^1] 可通过内核文档 [Timers and timekeeping](https://docs.kernel.org/core-api/timekeeping.html) 深入理解设计细节。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值