内核定时器

内核定时器可以实现定时执行某个事务,一个典型的应用就是使用内核定时器实现轮训操作,因为定时器到时后可以在定时器函数里面重新定时启用该定时器,达到循环启用定时器的作用,这样可以实现定时轮训硬件

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;
};
注意事项
内核定时器基本上会在"软件中断"上下文中运行,所以定时器函数要注意以原子地运行;且定时器始终会在调度它的同一CPU上运行。另外需要遵守以下规则:
o 不允许访问用户空间;
o 不允许访问current指针;
o 不能执行休眠或调度。
所有处于进程上下文之外的程序都要遵守这些规则。

内核提供两个API来判断中断上下文和原子上下文

#include 
int in_interrupt(); // 如果在中断上下文,则返回非零值
int in_atomic();    // 如果在原子上下文,则返回非零值
定时器应用api
#include 
void init_timer(struct timer_list *timer); // 初始化定时器
struct timer_list TIMER_INITIALIZER(_function, _expires, _data); // 宏初始化并指定相关成员值
void add_timer(struct timer_list *timer); // 向内核添加定时器
int del_timer(struct timer_list *timer); // 移除定时器
应用场景
struct device_regs *devreg = NULL; //定义一个用于表示设备寄存器的结构体指针
struct timer_list  demo_timer; //定义一个内核定时器对象
//定义定时器函数,当定时器对象demo_timer中expires成员指定的时间到期后,该函数将被调用
static void demo_timer_func (unsigned long data)
{
    //在定时器函数中重新启动定时器以实现轮询的目的
    demo_timer.expires = jiffies + HZ;
    add_timer(&demo_timer);
    //定时器函数将data参数通过类型转换获得设备寄存器的结构体指针
    struct device_regs *preg = (struct device_regs *) data;
    //定时器函数此后将会读取设备状态
    ...
}
//用于打开设备的函数实现
static int demo_dev_open(…)
{
    ...
    //分配设备寄存器结构体的指针变量,最好放在模块初始化函数中…
    devreg = kmalloc(sizeof(struct device_regs), GFP_KERNEL);
    ...
    init_timer(&demo_timer); //调用内核函数init_timer来初始化定时器对象demo_timer
    demo_timer.expires = jiffies + HZ; //设定定时器到期时间点,从现在开始的1秒钟
    demo_timer.data = (unsigned long) devreg; //将设备寄存器指针地址作为参数
    demo_timer.function = &demo_timer_func;
    add_timer(&demo_timer);
    ...
}
//用于关闭设备的函数实现
static int demo_dev_ release(…)
{
    ...
    del_timer_sync(&demo_timer); //删除定时器对象
    ...
}


你可能感兴趣的:(Linux)