概述
先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
一 why
一般地,在我们嵌入式软件开发中,使用定时器的目的是为了实现周期性地执行某项工作;同样地,linux内核也实现了一种定时器,用于实现内核周期性执行某项工作。
二 what
linux内核实现的这种定时器,称之为动态定时器,是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,它的实现位于Linux/timer.h 和 kernel/timer.c 文件中。
被调度的函数是异步执行的,类似于一种“软件中断”,处于非进程的上下文中,所以这个被调度函数应该遵循如下规则
1. 没有 current 指针,不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。
2. 不能执行休眠(或可能引起休眠的函数)和调度。
3. 任何被访问的数据结构都应该针对并发访问进行保护,以防止竞争条件。
4. 被调度函数运行过一次后就不会再被运行了(相当于自动注销),但可以通过在被调度的函数中重新调度自己来周期运行。
2.1 内核定时器的数据结构
struct timer_list {
struct list_head entry; // 当一个定时器被注册到内核之后,entry 字段用来连接该定时器到一个内核链表中
unsigned long expires; // 表示期望定时器执行的 jiffies 值,到达该 jiffies 值时,将调用 function 函数
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base; //内核内部实现所用的
/* ... */
};
2.2 初始化
由于linux内核版本的不同,关于初始化部分的实现有不同的函数,低版本的用init_timer,高版本是timer_setup
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
init_timer(&dev->getIntrTimer);
dev->getIntrTimer.data = (unsigned long) dev;
dev->getIntrTimer.function = GetIntrTimerCallback;
/* ... */
add_timer(&dev->getIntrTimer);
#else
timer_setup(&dev->getIntrTimer, GetIntrTimerCallback, 0);
/* the third argument may include TIMER_* flags */
/* ... */
#endif
比如当前我的linux版本是4.15,所以在我的实验中,使用的就是timer_setup
2.3 注册
初始化定时器成功之后,我们需要注册该定时器,函数为
add_timer
2.4 修改
定时运行过程中的定时器周期修改函数为
mod_timer
前面我们知道,当定时周期来到时,会执行被调函数,如果我们此时不修改定时器到期时间,则接下来就不会在执行被调函数了,我们可以在被调函数中修改定时器到期时间,实现周期性执行被调函数。
三 how
定时器内核编程示例
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
static struct timer_list test_timer;
static void irq_test_timer_function(struct timer_list *timer)
{
printk("22 again in irq_test_timer_functionn");
mod_timer(&test_timer, jiffies + 2 * HZ);
}
static int timer_drv_init(void)
{
test_timer.expires = jiffies + 2 * HZ;
timer_setup(&test_timer, irq_test_timer_function, 0);
add_timer(&test_timer);
printk(KERN_INFO "already init and add timern");
return 0;
}
static void timer_drv_exit(void)
{
printk(KERN_INFO "exit timer drvn");
del_timer(&test_timer);
}
module_init(timer_drv_init);
module_exit(timer_drv_exit);
MODULE_LICENSE("GPL");
Makefile文件
obj-m:=test_timer.o
KDIR:= /lib/modules/$(shell uname -r)/build
PWD:= $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
四 test
1. 上传到Ubuntu系统
2. 编译 make
3. 加载 sudo insmod test_timer.ko
4. 查看运行情况 dmesg | tail
5. 卸载 sudo rmmod test_timer
加载时打印
卸载时打印
最后
以上就是害怕鞋子为你收集整理的linux内核模块编程(二)----timer定时器的全部内容,希望文章能够帮你解决linux内核模块编程(二)----timer定时器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复