内核定时器timer_list

内核定时器

内核时钟中断发生后检测各定时器是否到期。利用定时器,我们可以设定在未来的某一时刻,触发一个特定的事件。这种定时器的计时单位基于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(&times);
        printk("atomic value: %u\n", atomic_read(&times));
}

int timer_demo_init(void)
{
    //原子计数值初始化
    atomic_set(&times, 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(&times);
        printk("atomic value: %u\n", atomic_read(&times));
}

int timer_demo_init(void)
{
    //原子计数值初始化
    atomic_set(&times, 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");

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/81285341