定时器成员:
expires 定时器定时的滴答数(当前的滴答数为jiffies)
function 到那个时刻内核调用的函数
data 由于可能多个定时器调用一个函数,为了使得这个函数能够区分不同的定时器,通过在结构中data来标识这个定时器,并且通过调用function(data)使得function能区分它们,也就是 data起到ID的作用。
使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。 time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。function就是时间到了以后的回调函数,它的参数就是timer_list中的data。 data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。在预置时间到系统调用function,同时系统把这个time_list从定时队列里清除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()把这个timer_list加进定时队列。
管理定时器的接口
----------------------------------------------------------
创建定时器需要先定义它:
struct timer_list my_timer;
接着需要通过一个辅助函数初始化定时器数据结构的内部值,初始化必须在使用其他定时器管理函数对定时器进行操作前完成。
init_timer(&my_timer);
现在可以填充结构中需要的值了(与定时器直接相关的三个参数):
my_timer.expires = jiffies + delay; // 定时器超时时的节拍数
my_timer.data = 0; // 给定时器处理函数传入参数0
my_timer.function = my_function; // 定时器超时时调用的函数
my_timer.expires表示超时时间,它是以节拍为单位的绝对计数值。如果当前jiffies计数等于或大于my_timer.expires,那么my_function指向的处理函数就会开始执行,另外该函数还要使用长整型参数my_timer.data。如果你不需要这个参数,可以简单地传递0(或任何其他值)给处理函数。
最后,必须激活定时器:
add_timer(&my_timer);
大功告成,定时器可以工作了!但请注意定时值的重要性。当前节拍计数大于或等于指定的超时值时,内核就开始执行定时器处理函数。虽然内核可以保证不会在超时时间到期前运行定时器处理函数,但是有可能延误定时器的执行。一般来说,定时器都在超时后马上就回执行,但是也有可能被推迟到一下时钟节拍才能运行,所以不能用定时器来实现任何硬实时任务。
有时可能需要更改已经激活的定时器超时时间,所以内核通过函数mod_timer()来实现该功能,该函数可以改变指定的定时器超时时间:
mod_timer(&my_timer, jiffies+new_delay);
mod_timer()函数也可操作那些已经初始化,但还没有被激活的定时器,如果定时器未被激活,mod_timer()会激活它。如果调用时定时器未被激活,该函数返回0;否则返回1。但不论哪种情况,一旦从mod_timer()函数返回,定时器都将被激活而且设置了新的定时值。
如果需要在定时器超时前停止定时器,可以使用del_timer()函数:
del_timer(&my_timer);
被激活或未被激活的定时器都可以使用该函数,如果定时器还未被激活,该函数返回0;否则返回1。注意,你不需要为已经超时的定时器调用该函数,因为它们超时后会自动被删除。
当删除定时器时,必须小心一个潜在的竞争条件。当del_timer()返回后,可以保真的只是: 定时器不会再被激活(也就是,将来不会执行),但是在多处理机器上定时器中断可能已经在其他处理器上运行了,所以删除定时器时需要等待可能在其他处理器上运行的定时器处理程序都退出,这时就要使用del_timer_sync()函数执行删除工作:
del_timer_sync(&my_timer);
和del_timer()函数不同,del_timer_sync()函数不能在中断上下文中使用。
测试代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
static char *who= "who";
static int time= 1;//定时器大小参数
static int arg= 0;//是否修改定时器
module_param(time, int, S_IRUGO);
module_param(arg, int, S_IRUGO);
module_param(who, charp, S_IRUGO);
static struct timer_list my_timer;
static void timer_function(unsigned long sign)
{
printk(KERN_EMERG"Timer out %d\n",sign);
}
static int timer_init(void)
{
int i=0;
init_timer(&my_timer);//初始化定时器
my_timer.expires = jiffies + time*100; // 定时器超时时的节拍数
my_timer.data = 3; // 给定时器处理函数传入参数0
my_timer.function = timer_function; // 定时器超时时调用的函数
add_timer(&my_timer); //激活定时器
if(0!=arg)
{
my_timer.data= arg; // 给定时器处理函数传入参数0
mod_timer(&my_timer, jiffies+arg*100);//修改定时器
}
return 0;
}
static int timer_exit(void)
{
printk(KERN_EMERG"GOOBYE,WORLD\t\n");
return 0;
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("Dual BSD/GPL");
EXPORT_SYMBOL(who);
EXPORT_SYMBOL(time);
EXPORT_SYMBOL(arg);
测试方法&结果:
[root@localhost timer]# insmod timer.ko time=10 arg=20
[root@localhost timer]#
Message from syslogd@ at Mon Aug 13 12:08:25 2012 ...
localhost kernel: Timer out 20
[root@localhost timer]# rmmod timer.ko
[root@localhost timer]#
Message from syslogd@ at Mon Aug 13 12:08:46 2012 ...
localhost kernel: GOOBYE,WORLD
[root@localhost timer]# insmod timer.ko time=10
[root@localhost timer]#
Message from syslogd@ at Mon Aug 13 12:08:58 2012 ...
localhost kernel: Timer out 3
[root@localhost timer]#