一、问题描述
1. 要实现的功能
编写一个Linux 按键驱动,按下按键时,产生中断,在中断中启动定时器进行防抖处理。
2. 出现的问题
在中断处理函数中,调用 add_timer
函数设置定时器超时函数,并启动定时器。编写完驱动程序和 app 应用程序之后,按下按键,系统就崩溃了。提示如下:
二、问题分析
1. add_timer 函数使用不合理
在看资料学习Linux 内核定时器的时候,里面提到 add_timer
函数要在调用 init_timer
函数初始化完成之后调用,修改定时器超时值和启动定时器 要使用 mod_timer
函数。
在中断处理函数中,使用 mod_timer
修改和激活定时器。实际运行之后,就没再出现系统崩溃的问题。
2. 为什么我会犯这样的问题
我看了 add_timer
函数的实现,发现 add_timer
的实现和 mod_timer
的实现”基本一致”,我想试试是不是一样的。我看到的 add_timer
的函数的实现是这样的:
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
EXPORT_SYMBOL(add_timer);
add_timer 函数分成两部分,上半部分跟 DEBUG
有关,下半部分直接就是调用 mod_timer
修改超时值和激活定时器。
查看BUG_ON 的代码实现,我当时看到的是这样的:
#ifndef HAVE_ARCH_BUG_ON
#define BUG_ON(condition) do { if (condition) ; } while (0)
#endif
这里相当于执行了一次 condition
,无论真假,后面都没实际执行内容。condition
的语句是
static inline int timer_pending( const struct timer_list *timer )
{
return timer->entry.next != NULL;
}
相当于比较了一次 timer→entry.next 是不是为空。
所以我当时认为 add_timer
和 mod_timer
的作用是一样的
3. 导致我理解出错的原因
仔细分析之后发现,BUG_ON
函数还有一种实现是:
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
按照我当前内核的配置,调用的应该是这个实现的 BUG_ON
函数。但是为什么vscode 会调整出错呢?原因是 vscode 没识别 autoconf.h
文件的配置,所以没按照系统配置的宏进行跳转。
这个 BUG_ON
函数,在条件满足的情况下,会调用 BUG()
函数,BUG() 函数还涉及很多其他内容,后面再分析。
三、配置 vscode 识别 autoconf.h 文件
打开 vscode 的 .vscode/c_cpp_properties.json
文件,增加如下配置:
"forcedInclude": [
"linux_kernel/include/generated/autoconf.h"
],
强制包含 autoconf.h
文件