75 模块编程之定时器

前言

这个 主要是 最开始的时候了解驱动的时候, 看到的一系列的 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 的相关处理 

 

 

 完

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值