4.4.5 timer中断流向Linux(从interrupt log回放)
按上文所述,timer中断3已经记录到root domain的interrupt log。在《3.4.1.3 IPIPE interrupt log数据结构》中,已经讨论过interrupt log的记录与回放。本小结,讨论什么时机来回放interrupt log中的timer中断3。
从interrupt log中查询出未处理的中断,进行处理,为方便描述简称interrupt log回放。核心函数就是__ipipe_next_irq,它是__ipipe_set_irq_pending的反向操作。从下图的函数调用关系可知,IPIPE总是通过调用__ipipe_sync_stage来完成interrupt log回放。
第一,dispatch_irq_head中进行回放
当dispatch_irq_head中执行head domain已经注册的中断处理程序head->irqs[3].handler(即xnintr_core_clock_handler)返回后,有一个地方会回放root domain的interrupt log。
static void dispatch_irq_head(unsigned int irq) /* hw interrupts off */
{
............
// 调用对应的中断处理程序
head->irqs[irq].handler(irq, head->irqs[irq].cookie);
............
// 重新获取当前CPU的头域上下文
p = ipipe_this_cpu_head_context();
__clear_bit(IPIPE_STALL_FLAG, &p->status); // 清除IPIPE_STALL_FLAG标志位
// 检查是否仍然在头域中运行
if (likely(__ipipe_current_context == p)) {
// 检查是否是从头域进入的代码
if (old->domain == head) {
// 是的,进行立即同步
if (__ipipe_ipending_p(p))
__ipipe_sync_stage();
return;
}
// 切换回根域上下文
__ipipe_set_current_context(ipipe_this_cpu_root_context());
}
/*
* 此时我们一定是在根域中运行,在根域
* 回放高优先级中断(慢路径)。
*/
__ipipe_do_sync_pipeline(head);
}
在dispatch_irq_head,如果检测到当前的上下文已经是root domain,说明没有Xenomai实时任务需要调度,此时会调用__ipipe_do_sync_pipeline。经过层层调用,
__ipipe_do_sync_pipeline->__ipipe_sync_stage->__ipipe_do_sync_stage最终会执行root domain的irqs[3].handler,即之前注册的__ipipe_do_IRQ!
走到了__ipipe_do_IRQ之后,会回归到Linux中断子系统,调用__handle_domain_irq,顺着Linux的中断处理流程,最终回到Linux中virq 3对应的中断处理程序arch_timer_handler_virt!
第二,其它情况下进行回放
有很多地方都会进行root domain的中断 3的回放,这里只是贴一下图,暂时不分析。以后分析进程调度的时候,再做详细分析。
对4.4章做一个小结:
timer中断是一个特殊的中断,必须在head domain/Xenomai和root domain/Linux中执行,所以中断发生后,会经过一个巧妙和复杂的过程,完成中断的流动。