分类: IT业界
2013-01-22 16:04:59
原文地址:内核定时器 作者:broadviewbj
内核定时器
内核定时器是设备驱动程序中经常要用到的另一个重要的内核设施。如果驱动程序希望在将来某个可度量的时间点到期后,由内核安排执行某项任务(此处的任务通常是驱动程序自身定义的某个函数,接下来的叙述中称之为定时器函数),便可以使用定时器来完成。
设备驱动程序中对内核定时器的一个典型使用场景是用它来实现轮询机制,因为定时器函数自身可以重新启用它所在的定时器,所以在一个时间段到期后,定时器函数被调用,在函数内部因为又重新启用了该定时器,这样便形成了一个不断循环的定时器函数被系统调用的模式。此种情形下,如果设备驱动程序需要周期性地检查设备的某种操作状态,便可以在定时器函数中来完成。
驱动程序等内核模块如果要使用定时器,首先应该定义一个定时器类型的变量。struct 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;
};
其中在驱动程序中常用的是以下三个成员:
unsigned long expires
指定定时器的到期时间。
void (*function)(unsigned long)
定时器函数。当expires中指定的时间到期时,该函数将被触发。
unsigned long data
定时器对象中携带的数据。通常的用途是,当定时器函数被调用时,内核将把该成员作为实际参数传递给定时器函数。之所以要这样做,是因为定时器函数将在中断上下文中执行,而非当前进程的地址空间中。
其他的一些成员将主要由内核使用,用以实现定时器的内核机制,在后面会看到这些成员的用法。
为了让读者对驱动程序使用内核定时器有个直观的印象,接下来将先给出一段示例代码,然后再对其中一些关键函数的使用及其内核实现机制进行分节讨论。下面的代码展示了一个设备驱动程序通过使用内核定时器来轮询设备状态。
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设备驱动程序内核机制》
图书详细信息:http://blog.chinaunix.net/space.php?uid=13164110&do=blog&id=3078991