前言
这个 主要是 最开始的时候了解驱动的时候, 看到的一系列的 case, 这里 来大致剖析一下 相关的道理
这些模块 是怎么和内核交互的, 内核的这些业务是怎么实现的
这里主要是一个模块创建了一个 timer, 然后 0.3秒后执行, 然后 在执行的过程中递归加入当前任务到下一次队列
然后这里主要是设计了 模块来调用 timer 的相关系统函数, 以及 kthread 的相关知识
测试用例
测试模块如下, 模块主要是来自于 某git仓库, 这里未记录信息, 感谢原作者
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
/* 1 jiffy---10ms */
static struct timer_list my_timer;
static int timer_isr_enter_counts = 0;
void my_timer_callback( unsigned long data )
{
int retval;
pr_info( "%s called (%ld).\n", __FUNCTION__, jiffies );
timer_isr_enter_counts++;
if(timer_isr_enter_counts < 5){
retval = mod_timer( &my_timer, jiffies + msecs_to_jiffies(1000) );
if (retval)
pr_info("Timer firing failed\n");
}
}
static int __init timer_init(void)
{
int retval;
pr_info("Timer module loaded\n");
setup_timer( &my_timer, my_timer_callback, 0 );
pr_info( "Setup timer to fire in 300ms (%ld)\n", jiffies );
retval = mod_timer( &my_timer, jiffies + msecs_to_jiffies(300) );
if (retval)
pr_info("Timer firing failed\n");
return 0;
}
static void __exit timer_exit(void)
{
int retval;
retval = del_timer( &my_timer );
if (retval)
pr_info("The timer is still in use...\n");
timer_isr_enter_counts = 0;
pr_info("Timer module unloaded\n");
return;
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_AUTHOR("e665106");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple timer Module");
MODULE_ALIAS("a simplest module");
setup_timer & mod_timer
setup_timer 的相关宏定义如下
里面主要是调用了 __init_timer, 然后设置了 timer->function, timer-data
init_timer 主要是出实例化了一下 timer_list 这个数据结构
mod_timer 中将 timer 添加到 timer_base 中进行驱动
my_timer_callback 的执行
这里可以看出是另外一个 进程在执行 my_timer_callback, 执行的代码是 my_timer_callback 函数
当前进程的顶级调用堆栈是 call_timer_fn, 应该是一个 timer 相关的进程
我们看一下这里的 expires 的计算方式 ”jiffies + msecs_to_jiffies(1000)”
断点之前的日志信息如下, 上一次调用的 jiffies 为 4294979737
(initramfs) insmod stdtimer/stdtimer.ko
[ 349.433292] Timer module loaded
[ 349.438411] Setup timer to fire in 300ms (4294979655)
(initramfs) [ 349.768425] my_timer_callback called (4294979737).
查看内核源码根目录下面的 .config
可以看到 1s 大概是会转换为 250 jiffies
4294979737 + 250 = 4294979987
然后我们程序中拿到的是 4294979990, 这里可能是做了一个 补齐, 或者之类 这里不去 深究
然后这里 mod_timer 大概是等价于 删除了 timer, 然后更新了 timer 的触发时间, 然后新增 timer, 相当于就是 更新了 timer 的触发时间
进而 会产生下一次调用
然后 下一次调用的时候 会再次 mod_timer 更新触发时间为 1s 之后
直到 第五次的时候, 不在 mod_timer, 整个定时任务 流程结束
执行 my_timer_callback 的进程
这里从 timer->function 中可以看出是 我们这里的 my_timer_callback
然后 从上下文可以看到 my_timer_callback 的执行是在 中断中进行处理的
TIMER 软中断来负责处理 这批 定时任务
执行之后 my_timer_callback 中更新了 timer 的 expires
这一次 my_timer_callback 的执行日志为, expires 等于 4294979992 + 250 = 4294980242
但是 上面再 mod_timer 中输出是没有输出完整的调用堆栈的, 所以 这也是调试的时候需要注意的第一个地方, 多半原因是 中断进程中 调用 系统调用 有什么关系吧
(initramfs) insmod stdtimer/stdtimer.ko
[ 349.433292] Timer module loaded
[ 349.438411] Setup timer to fire in 300ms (4294979655)
(initramfs) [ 349.768425] my_timer_callback called (4294979737).
[ 350.790615] my_timer_callback called (4294979992).
这里 run_timer_softirq 中处理的是 timer_bases[BASE_STD] 的相关任务
从上面可以看出的是 timer_bases[BASE_STD] 中执行, 获取到我们的 my_timer_callback 任务
可以看到 tf->flags 为 0, 因为 我们使用的 setup_timer 传递的两个参数, 到最终 init_timer 的地方传入的 flags 为默认值 0
因此这里选择 timer_base 的地方选择的是 timer_bases[BASE_STD]
几个 timer_base
NR_BASES 为 2, 这里将循环内联起来了
之后的时候, 有一些初始化 timer_bases[BASE_STD], timer_bases[BASE_DEFERABLE], hrtimer_bases 的相关处理
完