内核定时器
内核时钟中断发生后检测各定时器是否到期。利用定时器,我们可以设定在未来的某一时刻,触发一个特定的事件。这种定时器的计时单位基于jiffies值的计数,也就是说,它的精度只有1/HZ,假如你的内核配置的HZ是1000,系统中的定时器的精度就是1ms。
1.定时器数据结构 timer_list
struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct list_head entry;
unsigned long expires;
struct tvec_base *base;
void (*function)(unsigned long);
unsigned long data;
int slack;
#ifdef CONFIG_TIMER_STATS
int start_pid;
void *start_site;
char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
//字段用于把一组定时器组成一个链表,至于内核如何对定时器进行分组,我们会在后面进行解释。
entry
//字段指出了该定时器的到期时刻,也就是期望定时器到期时刻的jiffies计数值。
expires
//每个cpu拥有一个自己的用于管理定时器的tvec_base结构,该字段指向该定时器所属的cpu所对应tvec_base结构。
base
//字段是一个函数指针,定时器到期时,系统将会调用该回调函数,用于响应该定时器的到期事件。
function
//该字段用于上述回调函数的参数。
data
//对有些对到期时间精度不太敏感的定时器,到期时刻允许适当地延迟一小段时间,该字段用于计算
slack
2.定时器的初始化
定时器的初始化实质就是对结构体赋值
#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
.entry = { .prev = TIMER_ENTRY_STATIC }, \
.function = (_function), \
.expires = (_expires), \
.data = (_data), \
.base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \
.slack = -1, \
__TIMER_LOCKDEP_MAP_INITIALIZER( \
__FILE__ ":" __stringify(__LINE__)) \
}
#define TIMER_INITIALIZER(_function, _expires, _data) \
__TIMER_INITIALIZER((_function), (_expires), (_data), 0)
#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \
__TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE)
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)
定时器的 种初始化
[1]
void function(unsigned long)
{
printk("1-hello!\n");
}
//0是传递给function的参数
DEFINE_TIMER(my_timer,function,0,0);
[2]
void function(unsigned long)
{
printk("2-hello!\n");
}
struct timer_list my_timer = TIMER_INITIALIZER(function,jiffies + HZ,0);
[3]
void function(unsigned long)
{
printk("3-hello!\n");
}
//系统繁忙时可延时
struct timer_list my_timer = TIMER_DEFERRED_INITIALIZER(function,jiffies + HZ,0);
[4]
void function(unsigned long)
{
printk("4-hello!\n");
}
struct timer_list my_timer;
init_timer(&my_timer);
my_timer.function = function;
my_timer.data = (unsigned long)0;
my_timer.expires = jiffies + HZ;
[5]
void function(unsigned long)
{
printk("5-hello!\n");
}
struct timer_list my_timer;
setup_timer(&my_timer,function,0);
3.添加定时器
//注册内核定时器,将定时器加入到内核动态定时器链表,即启动定时器
//add_timer中调用了mod_timer
void add_timer(struct timer_list * timer);
//添加定时器到指定cpu
extern void add_timer_on(struct timer_list *timer, int cpu);
4.移除定时器
//删除定时器
int del_timer(struct timer_list * timer);
//等待定时器处理完之后删除,此函数不能出现在中断上下文。一般用在多CPU场合,定时器被另一个CPU使用的情况。
int del_timer_sync(struct timer_list * timer);
5.修改定时器
//设置下一次触发事件的时间,每次设置之后,执行完定时器后就会失效,要想循环使用,需要在定时函数中添加
int mod_timer(struct timer_list *timer, unsigned long expires);
6.定时器应用实例
timer_demo1.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <asm/atomic.h>
struct timer_list timer;
atomic_t times;
//定时器超时函数
void test_timer_fn(unsigned long arg)
{
mod_timer(&timer, jiffies+HZ); //设置超时时间 1s
//原子计数值加一
atomic_inc(×);
printk("atomic value: %u\n", atomic_read(×));
}
int timer_demo_init(void)
{
//原子计数值初始化
atomic_set(×, 0);
init_timer(&timer);
timer.function= test_timer_fn;
//timer.expires = jiffies + HZ;//如果设置了这句就不需要调用mod_timer来修改expires
add_timer(&timer);
//设置超时时间,启动定时器
mod_timer(&timer, jiffies + HZ); //设置超时时间 1s
return 0;
}
void timer_demo_exit(void)
{
del_timer(&timer);
printk("timer_demo_exit success\n");
}
module_init(timer_demo_init);
module_exit(timer_demo_exit)
MODULE_AUTHOR("wyy");
MODULE_LICENSE("GPL");
timer_demo2.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <asm/atomic.h>
atomic_t times;
void test_timer_fn(unsigned long arg);
//如果设置了expires非零就不需要在timer_demo_init中调用mod_timer来修改expires
DEFINE_TIMER(timer,test_timer_fn,0,0);
//定时器超时函数
void test_timer_fn(unsigned long arg)
{
mod_timer(&timer, jiffies+HZ); //设置超时时间 1s
//原子计数值加一
atomic_inc(×);
printk("atomic value: %u\n", atomic_read(×));
}
int timer_demo_init(void)
{
//原子计数值初始化
atomic_set(×, 0);
add_timer(&timer);
//设置超时时间,启动定时器
mod_timer(&timer, jiffies + HZ); //设置超时时间 1s
return 0;
}
void timer_demo_exit(void)
{
del_timer(&timer);
printk("timer_demo_exit success\n");
}
module_init(timer_demo_init);
module_exit(timer_demo_exit)
MODULE_AUTHOR("wyy");
MODULE_LICENSE("GPL");