(本章基于:Linux-4.4.0-37)
内核定时器可在用户设定时间到达后调用一段任务,基本数据定义、API如下:
struct timer_list {
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
......
......
};
定时器基本数据类型,expires表明定时器期望jiffies所达到的值,当时间达到此值,将会调用function函数,并使用data作为参数;
void init_timer(struct timer_list *timer)
初始化定时器
int add_timer(struct timer_list *timer)
添加一个定时器到内核动态定时器链表
int del_timer(struct timer_list *timer)
注销一个定时器
int del_timer_sync(struct timer_list *timer)
和del_timer相似,但它保证在返回时,定时器函数不在任何一个CPU上执行。del_timer_sync用来避免竞争情况在SMP系统上,并在UP内核中和del_timer相同。应当优先使用del_timer_sync;
int mod_timer(struct timer_list *timer)
当一个定时器被已经被插入内核动态定时器链表,我们可以通过这个函数来修改他的的expires;
需要注意的是,这个定时器函数是被一个类似硬件中断(软中断)所触发,所以它处在中断上下文(原子上下文)中而不是进程上下文。当你处在进程上下文之外,你必须遵守下列规则:
1)没有允许存取用户空间. 因为没有进程上下文, 没有和任何特定进程相关联的到用
户空间的途径.
2)这个 current 指针在原子态没有意义, 并且不能使用因为相关的代码没有和已被
中断的进程的联系.
3)不能进行睡眠或者调度. 原子代码不能调用 schedule 或者某种 wait_event, 也
不能调用任何其他可能睡眠的函数. 例如, 调用 kmalloc(..., GFP_KERNEL) 是违
犯规则的. 旗标也必须不能使用因为它们可能睡眠。
例程:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#define TIMER_INTERVAL (5 * HZ) //5s
static struct timer_list timer;
static long unsigned int start;
static void
hello_cleanup(void)
{
del_timer_sync(&timer);
}
void
timer_function(unsigned long arg)
{
long unsigned int current_time = jiffies;
printk(KERN_INFO "timer:%d\n", (int)((current_time - start) / HZ));
mod_timer((struct timer_list*)arg, current_time + TIMER_INTERVAL);
}
static __init int hello_init(void)
{
start = jiffies;
init_timer(&timer);
timer.expires = start + TIMER_INTERVAL;
timer.function = timer_function;
timer.data = (unsigned long)&timer;
add_timer(&timer);
printk(KERN_ALERT "hello init success!\n");
return 0;
}
static __exit void hello_exit(void)
{
hello_cleanup();
printk(KERN_WARNING "helloworld exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stone");