Linux Posix Timer实现代码分析
作者:网络转载 发布时间:[ 2014/2/25 13:41:01 ] 推荐标签:操作系统 linux 开发 测试技术
定时器的删除操作与新建定时器对应,释放定时器建立时分配的资源。
定时器的启动
int timer_settime(timer_t timer_id, int flags, struct itimerspec* new_setting, struct itimerspec* old_setting);
参数timer_id是timer_create返回的定时器id号。
参数flags为TIMER_ABSTIME或者0,代表设置的超时值是还是相对时间
参数new_setting是需要被设置的超时时间
参数old_setting用于返回设置新超时值之前定时器的超时时间
timer_setting的功能主要由宏
CLOCK_DISPATCH(timr->it_clock, timer_set, (timr, flags, &new_spec, rtn));
完成,该宏默认情况下会调用common_timer_set。
int common_timer_set(struct k_itimer *timr, int flags,
struct itimerspec *new_setting, struct itimerspec *old_setting)
common_timer_set中,会设置timr参数中包含的hrtimer(struct k_itimer:: it.real.timer),通过hrtimer机制完成定时器的超时设置,hrtimer的超时函数被设置为posix_timer_fn。
|
static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
。。。
// 如果定时器处于循环模式,每一次到期时加一
if (timr->it.real.interval.tv64 != 0)
si_private = ++timr->it_requeue_pending;
// 调用posix_timer_event发送定时器超时消息
// 如果定时器设置的是SIGEV_NONE且处于循环模式,则posix_timer_event返回值为 // 非0。这时定时器的循环设置将在这个超时函数中完成(返回值设为 // HRTIMER_RESTART可使hrtimer模块重启定时器)。
if (posix_timer_event(timr, si_private))
if (timr->it.real.interval.tv64 != 0)
hrtimer_forward (timer, now, timr->it.real.interval);
ret = HRTIMER_RESTART;
在定时器没有设置SIGEV_NONE时,超时函数posix_timer_event将不会重启处于循环模式的定时器,重启定时器的工作会在signal处理的函数中。
posix_timer_event的主要功能是填充sigqueue结构,并发送到相应的sigpending(Linux的signal机制)队列。
int posix_timer_event(struct k_itimer *timr, int si_private)
。。
imr->sigq->info.si_code = SI_TIMER; // SI_TIMER比较重要,下文会提到
。。。
if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
struct task_struct *leader;
// 注意这里后一个参数是0,代表发给线程
int ret = send_sigqueue(timr->sigq, timr->it_process, 0);
if (likely(ret >= 0)) // 如果成功发送,则返回;否则发给该线程所属的进程
return ret;
timr->it_sigev_notify = SIGEV_SIGNAL;
leader = timr->it_process->group_leader;
put_task_struct(timr->it_process);
timr->it_process = leader;
}
// 将信号发给进程(后一个参数为1)
return send_sigqueue(timr->sigq, timr->it_process, 1);
send_sigqueue是Linux的signal机制实现的函数,但该函数中有一个小细节与timer相关。
// 下面条件判断定时器超时消息是否已经在sigpending队列中,如果已经在,说明上一 // 次超时还没有处理,下一次定时器超时已经再次到达。这时只增加sigqueue的 // si_overrun标记位以标记定时器超时溢出,而不会再一次排队sigqueue
if (unlikely(!list_empty(&q->list))) {
/*
* If an SI_TIMER entry is already queue just increment
* the overrun count.
*/
BUG_ON(q->info.si_code != SI_TIMER);
q->info.si_overrun++;
goto out;
}
q->info.si_overrun = 0;
// 将sigqueue排入sigpending队列
。。。
out:
unlock_task_sighand(t, &flags);
|

sales@spasvo.com