红联Linux门户
Linux帮助

Linux Kernel中如何使用高精度timer(hrtimer)

发布时间:2014-11-21 15:25:44来源:linux网站作者:myarrow

前面已经讲过,高精度timer是通过hrtimer来实现的,hrtimer通过可编程定时器来现,在等待时,不占用CPU。

在用户态,只要我们调用usleep,则线程在kernel态执行时,则使用hrtimer进行不占CPU的等待。


在Kernel中如何使用的呢?

先看看eventpoll.c中的ep_poll函数:

static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, 
int maxevents, long timeout) 

int res = 0, eavail, timed_out = 0; 
unsigned long flags; 
long slack = 0; 
wait_queue_t wait; 
ktime_t expires, *to = NULL; 

if (timeout > 0) { 
struct timespec end_time = ep_set_mstimeout(timeout); 

slack = select_estimate_accuracy(&end_time); 
to = &expires; 
*to = timespec_to_ktime(end_time); 
} else if (timeout == 0) { 
/*
* Avoid the unnecessary trip to the wait queue loop, if the
* caller specified a non blocking operation.
*/ 
timed_out = 1; 
spin_lock_irqsave(&ep->lock, flags); 
goto check_events; 

fetch_events: 
spin_lock_irqsave(&ep->lock, flags); 

if (!ep_events_available(ep)) { 
/*
* We don't have any available event to return to the caller.
* We need to sleep here, and we will be wake up by
* ep_poll_callback() when events will become available.
*/ 
init_waitqueue_entry(&wait, current); 
__add_wait_queue_exclusive(&ep->wq, &wait); 

for (;;) { 
/*
* We don't want to sleep if the ep_poll_callback() sends us
* a wakeup in between. That's why we set the task state
* to TASK_INTERRUPTIBLE before doing the checks.
*/ 
set_current_state(TASK_INTERRUPTIBLE); 
if (ep_events_available(ep) || timed_out) 
break; 
if (signal_pending(current)) { 
res = -EINTR; 
break; 

spin_unlock_irqrestore(&ep->lock, flags); 
if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) 
timed_out = 1; 

    spin_lock_irqsave(&ep->lock, flags); 

__remove_wait_queue(&ep->wq, &wait); 

set_current_state(TASK_RUNNING); 

check_events: 
/* Is it worth to try to dig for events ? */ 
eavail = ep_events_available(ep); 

spin_unlock_irqrestore(&ep->lock, flags); 

/*
* Try to transfer events to user space. In case we get 0 events and
* there's still timeout left over, we go trying again in search of
* more luck.
*/ 
if (!res && eavail && 
!(res = ep_send_events(ep, events, maxevents)) && !timed_out) 
goto fetch_events; 

return res; 
}


看到上面的schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)了吗?它就是hrtimer中调用来执行等待超时的函数,其函数原型为:

/**
* schedule_hrtimeout_range - sleep until timeout
* @expires: timeout value (ktime_t)
* @delta: slack in expires timeout (ktime_t)
* @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
*/
int __sched schedule_hrtimeout_range(ktime_t *expires, unsigned long delta,
const enum hrtimer_mode mode)
{
return schedule_hrtimeout_range_clock(expires, delta, mode,
CLOCK_MONOTONIC);
}


在ep_poll中,其slack和to的计算方法如下:

struct timespec end_time = ep_set_mstimeout(timeout);
slack = select_estimate_accuracy(&end_time);
to = &expires;
*to = timespec_to_ktime(end_time);

如果你在Kernel中需要高精度timer,可以参照此方法实现自己的高精度timer超时。