首先是配置并初始化hrtimers的API。在开始的时候我们讲struct hrtimer的时候,提到要使用struct hrtimer要先初始化,函数声明代码如下:
void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
enum hrtimer_mode mode)
//给定时钟初始化定时器
{
debug_init(timer, clock_id, mode);
__hrtimer_init(timer, clock_id, mode);
}
以上函数实现了一个高精度定时器的初始化,下面是相关元素的解释:
/**
* hrtimer_init – 给定时钟初始化定时器
* @timer:
将要被初始化的定时器
* @clock_id:
将要被用到的时钟
* @mode:
定时器模式 abs/rel
*/
mode可以使用五个常数,如下:
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0x0,
/* 时间是绝对的 */
HRTIMER_MODE_REL = 0x1,
/*时间是相对的 */
HRTIMER_MODE_PINNED = 0x02,
/* 定时器被绑定到CPU */
HRTIMER_MODE_ABS_PINNED = 0x02,
HRTIMER_MODE_REL_PINNED = 0x03,
};
hrtimer_init()函数里面调用了__hrtimer_init()函数,下面是该函数的原型:
static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,enum hrtimer_mode mode)
{
struct hrtimer_cpu_base *cpu_base;
int base;
memsettimer, 0, sizeof(struct hrtimer));
cpu_base = &__raw_get_cpu_var(hrtimer_bases);
if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
clock_id = CLOCK_MONOTONIC;
base = hrtimer_clockid_to_base(clock_id);
timer->base = &cpu_base->clock_base[base];
timerqueue_init(&timer->node);
#ifdef CONFIG_TIMER_STATS
timer->start_site = NULL;
timer->start_pid = -1;
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
}
__hrtimer_init()函数调用了struct hrtimer_cpu_base结构体对CPU进行相关的初始化,并使用memset()函数,原型如下:
void *memset(void *s, int c, size_t n)
{
int i;
char *ss = s;
for (i = 0; i < n; i++)
ss = c;
return s;
}
这个函数清空了memory里面的东西,完成了初始化,memset(timer, 0, sizeof(struct hrtimer))。
在这里注意一下,还是前面说到的一个问题,我用的源代码是3.2.12的,而2.6.X的源代码里所提供的,其实只有两个常数。
二、相关的接口代码
定时器初始化之后,进行设定定时器的到期时间,并启动定时器,函数声明代码hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode),timer代表将要被添加的定时器,tim代表到期时间,mode代表定时器模式。如果启动成功,则返回0,否则返回1。
如果要取消一个设置好的定时器,可以使用int hrtimer_cancel(struct hrtimer *timer)和int hrtimer_try_to_cancel(struct hrtimer *timer),这两个函数的区别是,后者提供了额外的返回值-1,如果定时器当前正在执行因而无法停止,则返回-1.在这种情况下,hrtimer_cancel会一直等处理程序执行完毕。另外,如果定时器处于未激活状态,两个函数的返回值都是0,如果处于激活状态(即状态为HRTIMER_STATE_INACTIVE或者HRTIMER_STATE_ENQUEUED),二者都返回1(读者务必注意,在2.6.X版本的源代码中,处于激活状态的两个常数是HRTIMER_STATE_PENDING或者HRTIMER_STATE_ENQUEUED,无非改了模样了,这个注意一下就好)。
如果要重启一个取消的定时器,可以使用static inline int hrtimer_restart(struct hrtimer *timer)。
上面讲的几个函数应该是最基本的,也没什么大的讲头,下面的函数才是高精度定时器的精彩之处,也就四高精度定时器的到期机制和回调函数的运行方式,运用红黑树的方法既节省资源又提高效率。
在讲精彩之处之前,首先要跟读者说一下几个补充知识,其实前面我们也已经提到了,无非这里重复和补充一下:
Ø
高精度定时器按照时间在一棵红黑树上排序。
Ø
他们独立于周期时钟,采用纳秒时间戳而非jiffies的时间规格。
Ø
This patch introduces a new subsystem for high-resolution kernel timers.这句话里的patch这个单词有点意思,他是说高精度定时器作为一个补丁包被安装到系统里的,在2.6.16之前是没有这个概念的。
Ø
高精度定时器的框架在编译的时候是在内核里,但是如果没有配置高精度定时器,那么高精度定时器是按照普通的定时器来运行。
Ø
最后一点,高精度定时器是采用红黑树算法实现的,而普通的定时器是采用时间轮循算法实现的.
根据上面的几点,我们可以知道高精度定时器框架总是有一部分会编译到内核中去的,即使禁止了对高分辨率定时器的支持。在这种情况下,高分辨率定时器的到期是有一个低分辨率时钟驱动的。这避免了代码复制,因为高分辨率定时器的用户,在没有高分辨率计时能力的系统上,无需对时间相关代码提供一个额外的版本。这种情况下,仍然会采用高分辨率框架,但只是以低分辨率运行。即使高分辨率定时器支持已经编译到内核中,但在启动时只提供了低分辨率计时功能,这与上述情况是相同的。因此我们在这里讲的高分辨率定时器,要分成两种情况,一种是高分辨率模式下的高分辨率定时器,另一种是高分辨率模式下的低分辨率定时器。
|