关闭

lk中的timer

298人阅读 评论(0) 收藏 举报
分类:
kmain中会调用timer_init来初始timer_queue,并通过
void timer_init(void)
{
list_initialize(&timer_queue);


/* register for a periodic timer tick */
platform_set_periodic_timer(timer_tick, NULL, 10); /* 10ms */
}
并通过platform_set_periodic_timer 设定timer每10ms中断一次,中断callback是timer_tick
我们看一个平台的实现
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, time_t interval)
{
enter_critical_section();


t_callback = callback;


*REG(PIT_CLEAR) = 1;
*REG(PIT_INTERVAL) = interval;
*REG(PIT_START_PERIODIC) = 1;


unmask_interrupt(INT_PIT);


exit_critical_section();


return NO_ERROR;
}
将callback 赋值给t_callback,并写寄存器设定中断间隙为10ms
void platform_init_timer(void)
{
register_int_handler(INT_PIT, &platform_tick, NULL);
}
我们会在提前调用platform_init_timer,在其中调用register_int_handler 来设定timer的irq number INT_PIT的callback函数是platform_tick。
static enum handler_return platform_tick(void *arg)
{
*REG(PIT_CLEAR_INT) = 1;
if (t_callback) {
return t_callback(arg, current_time());
} else {
return INT_NO_RESCHEDULE;
}
}


最终在platform_tick这个函数中调用t_callback


最终结论就是在timer的中断函数中最后会调用timer_tick函数.
static enum handler_return timer_tick(void *arg, time_t now)
{
timer_t *timer;
enum handler_return ret = INT_NO_RESCHEDULE;


#if THREAD_STATS
thread_stats.timer_ints++;
#endif


for (;;) {
/* see if there's an event to process */
timer = list_peek_head_type(&timer_queue, timer_t, node);
if (likely(!timer || now < timer->scheduled_time))
break;


/* process it */
DEBUG_ASSERT(timer->magic == TIMER_MAGIC);
list_delete(&timer->node);
// timer = list_remove_head_type(&timer_queue, timer_t, node);
// ASSERT(timer);


#if THREAD_STATS
thread_stats.timers++;
#endif


// TRACEF("firing callback %p, arg %p\n", timer->callback, timer->arg);
if (timer->callback(timer, now, timer->arg) == INT_RESCHEDULE)
ret = INT_RESCHEDULE;
}


/* let the scheduler have a shot to do quantum expiration, etc */
if (thread_timer_tick() == INT_RESCHEDULE)
ret = INT_RESCHEDULE;


return INT_RESCHEDULE;
}
timer_tick 是个死循环,会从变量timer_queue 中是否有到期的时间
if (likely(!timer || now < timer->scheduled_time))
如果有的话,就从timer_queue 中删除,
list_delete(&timer->node);
并调用这个timer 到期时间需要执行的callback
if (timer->callback(timer, now, timer->arg) == INT_RESCHEDULE)


然后在坚持当前thread的时间片是否用完了,如果完了,就要重新调度.




timer系统部分运作原理解讲完了,我们下来看看是否使用timer


我们以gpio_keypad.c 为例
timer_initialize(&keypad->timer);
timer_set_oneshot(&keypad->timer, 0, gpio_keypad_timer_func, NULL);


可以看到先调用timer_initialize 初始化一个timer_t 结构体
void timer_initialize(timer_t *timer)
{
timer->magic = TIMER_MAGIC;
list_clear_node(&timer->node);
timer->scheduled_time = 0;
timer->periodic_time = 0;
timer->callback = 0;
timer->arg = 0;
}


在调用timer_set_oneshot 来加入到timer_queue 中
void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, void *arg)
{
time_t now;


// TRACEF("delay %d, callback %p, arg %p\n", delay, callback, arg);


DEBUG_ASSERT(timer->magic == TIMER_MAGIC);


if (list_in_list(&timer->node)) {
panic("timer %p already in list\n", timer);
}


now = current_time();
timer->scheduled_time = now + delay;
timer->periodic_time = 0;
timer->callback = callback;
timer->arg = arg;


// TRACEF("scheduled time %u\n", timer->scheduled_time);


enter_critical_section();


insert_timer_in_queue(timer);


exit_critical_section();
}


设定到期时间和callback
timer->scheduled_time = now + delay;
timer->periodic_time = 0;
timer->callback = callback;


然后插入到timer_queue list中
static void insert_timer_in_queue(timer_t *timer)
{
timer_t *entry;


list_for_every_entry(&timer_queue, entry, timer_t, node) {
if (entry->scheduled_time > timer->scheduled_time) {
list_add_before(&entry->node, &timer->node);
return;
}
}


/* walked off the end of the list */
list_add_tail(&timer_queue, &timer->node);
}


可见timer_queue中是按scheduled_time 来从小到大排序的


下来接timer到期,然后再timer中的callback函数中调用gpio_keypad_timer_func。


如果需要continue time的话,就在gpio_keypad_timer_func 中继续调用timer_set_oneshot。
static enum handler_return
gpio_keypad_timer_func(struct timer *timer, time_t now, void *arg)
{

kp->current_output = out;
if (out < kpinfo->noutputs) {
gpio = kpinfo->output_gpios[out];
if (kpinfo->flags & GPIOKPF_DRIVE_INACTIVE)
gpio_set(gpio, polarity);
else
gpio_config(gpio, polarity ? GPIO_OUTPUT : 0);
timer_set_oneshot(timer, kpinfo->settle_time,
 gpio_keypad_timer_func, NULL);
goto done;
}


}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:94372次
    • 积分:7228
    • 等级:
    • 排名:第3064名
    • 原创:684篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条
    最新评论