1. 内核定时器的作用
当中断触发时,修改定时器时间间隔,进入定时器回调函数,待完成回调则恢复。
2. 定时器嵌入其他数据结构
struct timer_list timer, 这个结构体作为定时器的数据结构,通过jiffies进行时间间隔的配置:
1 | mod_timer(&timer,jiffies + msecs_to_jiffies(40)); |
旧版本的定时器数据结构:
1 2 3 4 5 6 7 | struct timer_list{ /* OTHERS */ unsigned long expires; void (*function)(unsigned long ); unsigned long data; /* OTHERS */ }; |
新版本的定时器数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | struct timer_list { /* * All fields that change during normal runtime grouped to the * same cacheline */ struct hlist_node entry; unsigned long expires; void (*function)( struct timer_list *); u32 flags; #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }; |
此时的struct timer_list * 作为一个结构体指针传进去,这时候有一个神秘的接口可以把该结构体找到并且正确传递到函数中。
参考这个博客就知道这个数据结构怎么用:
https://lwn.net/Articles/735892/
3. 怎么用timer_list接口
1 2 3 4 5 6 7 | 1. timer_setup(&timer,current_key_timer_func,0); 初始化 2. mod_timer(&timer,jiffies + msecs_to_jiffies(40));其他地方调用启动定时器 3. 回调接口 static void current_key_timer_func( struct timer_list *tm) { struct key_table_list *dev = from_timer(dev,tm,timer); } |
把tm 传递给timer然后赋给dev,dev 存在一个timer。
4. 一个中断的驱动demo可以融入io中断、原子锁、tasklet以及定时器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /* tasklet func */ static void keys_tasklet_func(unsigned long data) { /* fetch which gpio's */ struct key_table_list *dev = ( struct key_table_list * ) data; ev_press = 1; /* mod_timer set */ mod_timer(&dev->timer,jiffies + msecs_to_jiffies(40)); } /* interrupt API */ static irqreturn_t buttons_interrupt( int irq, void *dev_id) { struct key_table_list *dev = ( struct key_table_list * ) dev_id; int tmp_value = -1; tmp_value = gpio_get_value(dev->gpio); printk( "button interrupt at [%d] key [No.%d]......key_status [%s]\n" , dev->gpio, dev->key, (tmp_value > 0) ? "pulled-up" : "pressed-down" ); tasklet_schedule(&dev->tasklet); return IRQ_RETVAL(IRQ_HANDLED); } /* current key function */ static void current_key_timer_func( struct timer_list *tm) { struct key_table_list *dev = from_timer(dev,tm,timer); int level = -1; level = gpio_get_value(dev->gpio); atomic_set(&dev->status,level); wake_up_interruptible(&button_waitq); } |
只提供关键代码。
4. 中断机制
1. 底半部机制: tasklet、工作队列、软中断和线程化irq。
tasklet:软中断执行上下文,顶半步返回,利用tasklet处理。
工作队列: 内核线程执行上下文,调度和睡眠。
软中断: 软中断执行上下文,不允许睡眠。
线程化irq: request_threaded_irq 和 devm_request_threaded_irq 申请中断。
Life is mess, don't let mess mess us.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库