Adeos在Xenomai体系结构中的位置
你将会注意到Adeos接口直接暴露在硬件抽象层构成了Xenomai核的基础。因此,大多数对Adeos服务的要求从HAL层开始解决,它的实现能在相干arch/<archname>/hal目录中找到,通用的位可以在arch/generic/hal下取得。看1看后者是最好的方法去理解Xenomai怎样为了自己的目的利用Adeos的。
2.1. Xenomai的重要和次要域
Xenomai允许运行实时线程在严格内核空间或在Linux线程地址空间。在文章剩下的部份,我们把后者称作Xenomai线程,不会与常规Linux任务产生混淆(即便他们属于 SCHED_FIFO 类)。Xenomai管理的所有线程
可以从实时nucleus中获知。
支持实时线程排他的运行在内核空间仅仅是1个共同核时期的1个回想,在用户空间真实时支持来临之前,当实时利用仅能在嵌入到内核模块运行;这些特点Xenomai还保存着主要的目的是支持延迟利用,这里不做讨论。
更有趣的是Xenomai对Linux有1个共生的方法;例如,这个使它不同于RTAI/LXRT的实现。以此为目的,Xenomai线程不但能像基于内核的Xenomai线程运行在管线里最高优先级域(即,主要域)的上下文中,而且可以运行在常规Linux空间(即,次要域),即便经历更高的调度延迟,仍被Xenomai当作实时的。在Xenomai的术语中,前者被称为运行在主要履行模式,而后者处于次要履行模式。
为了对运行在次要域的线程提供完全的实时支持,Xenomai需要实现以下几点:
- 公共的优先级模型。只能调度,我们需要1种方法使实时核和Linux内核同享相同的优先级模型相对线程同享控制。换句话说,1个Xenomai线程需要是自己的优先级在任什么时候候严格生效,不管它当前的域,在所有的Xenomai线程中。Xenomai采取称为根线程可变优先级的技术,通过这个Linux内核自动继承被实时核控制的Xenomai线程的优先级,这恰好产生在进入次要域的时候。实际上,这意味着当前运行在主要域的Xenomai线程没有必要抢占运行在次要域中的线程,除非它们的有效优先级确切更高。例如,上面的行动跟RTAI/LXRT相反,在RTAI/LXRT中线程迁移到Linux空间事实上会丢失它们实时有限级,通过继承RTAI调度器定义的最低优先级实现。也就是说,常规Linux任务队Xenomai1无所知,这仅仅产生在属于SCHED_FIFO的类中,当与来自主要域的Xenomai线程竞争CPU时总会被抢占,即便他们依然会与运行在次要域中的Xenomai线程竞争优先级明智。
- 程序履行时间的可预测性。当1个Xenomai线程运行在Linux(即,次要)域,不管履行内核还是利用代码,它的时序不应当被非实时的Linux中断活动搅动,通常来讲被任何低优先级、产生在内核层的异步异步活动。1个简单的方法来禁止后者产生的概率是当Xenomai线程运行在Linux域时使Linux内核保持中断饥饿,因此没有推延处理睬在这段时间内触发上半部中断处理。使Linux内核遭受中断饥饿的方法是当内部需要中间Adeos域的时候阻塞他们,坐在被实时核和Linux内核占用的中断之间,在Xenomai术语中叫做中断屏蔽。不管甚么时候Xenomai线程在Linux内核空间被调用这个屏蔽都会被占用,在其它的情况下不同。需要注意的是屏蔽支持能被启用/禁用在每一个线程基础上,或在Xenomai构建时系统范围的基础上;默许情况下对Xenomai是被禁用的并且不是内建的。
- 细粒度的Linux内核。为了从次要履行模式中取得最好,我们需要Linux内核表现出最短的可能非抢占部份,因此在Xenomai线程运行在次要域变成准备运行以后重调度的机会会尽快的被捉住。另外,这确保了Xenomai线程能在1个短的和有时间界的1段时间内从主要域迁移到次要域,由于这个操作包括了到达1个内核重调度点。由于这个,
2.2. 系统调用盗取
由于Xenomai实时API(即,skins)可以堆积在Xenomai的nucleus上,能将它们自己的1组服务导出给用户空间Xenomai线程,必须有1种方法对适当的处理程序的分离对应的系统调用,而常规的系统调用都是在1起的。Xenomai拦截每个Xenomai线程需要处理的Xenomai或Linux域的系统调用圈套/异常。这通使用适当的Adeos定阅事件处理程序实现。Xenomai使用这类能力来:
(1)将来自利用程序要求的实时服务分发给恰当的系统调用途理程序;
(2)确保每个系统调用都会在其相应的域中履行,不管是Xenomai还是Linux。
2.3. 中断传播
由于实时nucleus在管线的最前面,当有感兴趣的中断来临时在Xenomai域中的实时nucleus会第1个被通知,中断被处理以后,nucleus会将该中断标记并传递到管线,如果必要终究会传递到Linux内核域。当被产生的中断唤醒时,实时nucleus会在外部中断处理程序返回后(以防中断堆积)重新调度,并会转换成它控制的可运行线程的最高优先级。
当没有实时活动被阻塞时,Xenomai域会将CPU的控制权交给中断屏蔽域。也就是说当Xenomai域空闲时让出CPU,当Xenomai有事件处理时,抢占CPU。对中断通过管线,Adeos有两种传播模式:隐式模式和显示模式。隐式模式由系统自动传播中断,显示模式需要手动传播中断。
3. 技能和诀窍
3.1 启用/禁用中断源
除能完全延迟1个域使不再有中断能经过它,直到它被明确的撤消延迟,Adeos允许在硬件层选择性的禁用/重启用中断的实际源。
接收了这个盒子后,Adeos处理所有域的中断制止的要求,包括Linux内核的和实时核的。这意味着在硬件PIC层禁用中断要求源,并锁住从这个中断源到当前域在管线层的任何中断的分发。相反的,启用中断意味侧重新激活PIC层的中断源,并允许从这个源到当前域的进1步分发。因此,1个想启用1个中断源的域必须是与制止这个中断源的域是同1个,由于这样的操作是域独立的。
实际上,这意味着,成对使用时,rthal_irq_disable()和rthal_irq_enable()服务集成了构成了Xenomai基础的实时HAL内相干Adeos的调用,必须由同1Adeos域解决。例如,如果1个实时中断处理程序用rthal_irq_request()服务于某个中断源连在1起,禁用中断源使用rthal_irq_disable(),那末这个源将会被Xenomai域阻塞直到同1中断源的rthal_irq_enable()被同1域调用。处理这个要求失败将会致使受影响的中断通道永久性丢失。
3.2. 域间同享中断
1个在域间同享硬件中断时误用Adeos管线的典型例子以下:
void realtime_eth_handler (unsigned irq, void *cookie)
{
/*
* This interrupt handler has been installed using
* rthal_irq_request(), so it will always be invoked on behalf of
* the Xenomai (primary) domain.
*/
rthal_irq_disable(irq);
/* The Xenomai domain won't receive this irq anymore */
rthal_irq_host_pend(irq);
/* This irq has been marked as pending for Linux */
}
void linux_eth_handler (int irq, void *dev_id, struct pt_regs *regs)
{
/*
* This interrupt handler has been installed using
* rthal_irq_host_request(), so it will always be invoked on
* behalf of the Linux (secondary) domain, as a shared interrupt
* handler (Linux-wise).
*/
rthal_irq_enable(irq);
/*
* BUG: This won't work as expected: we are only unlocking the
* interrupt source for the Linux domain which is current here,
* not for the Xenomai domain!
*/
在上面的这个不工作的例子中,由于Xenomai对所有截获的中断总是使用显示的传播模式,接下来的以太网将会在Xenomai日志中被标记为阻塞,等待Xenomai处理程序可能手动的将它传播给Linux。但是由于中断依然被Xenomai锁在管线层(别忘了实际上没有人从Xenomai域解决了期望的rthal_irq_enable()),这样的是不会产生的,由于Xenomai处理程序直到锁被移除才会运行的。因此,我们庆祝吧。
荣幸的是,对适当的同享中断有个方法,域间需要保持中断源禁用直到终究处理结束(例如,处理电平动身的中断是其中的1个问题):实际上,你不需要做任何事情,由于在把它传递给管线之前Adeos已屏蔽了来自PIC层的进来任何中断。因此,你仅仅需要处理你看到的合适相干域处理程序的中断,并肯定在最后1个的时候使用rthal_irq_enable()来重启用中断源。不管什么时候Linux内核是那些接收者之1,常规的内核处理程序将会自动重启用,所以基本上你只需要担心在处理程序中调用rthal_irq_enable(),这个函数不会传播传进来的中断到Linux内核。
特别的在x86体系结构上,由于性能缘由,Adeos接收到的时钟中断将不会被屏蔽。这就是说,中断源将不会是你想以任何方式禁用的,所以这不是个问题。
3.3. 中断同享和延迟
但是,当传播通过全部管线保持屏蔽1个中断源可能会增加延迟。
由于Adeos保证没有由于中断在任何域上堆积引发栈溢出的产生,并且由于它在动身中断处理程序之前会延迟当前阶段,在Xenomai处理程序中没有必要禁用中断源。相反你乃至会想重新启用它,这样行将产生的中断可以被立刻记录下来,并且在当前处理程序调用返回后回立即被处理。
所以,解决方法是以这类方法重写先前的例子,以下:
void realtime_eth_handler (unsigned irq, void *cookie)
{
rthal_irq_enable(irq);
rthal_irq_host_pend(irq);
/* This irq has been marked as pending for Linux */
}
void linux_eth_handler (int irq, void *dev_id, struct pt_regs *regs)
{
/* process the IRQ normally. */
}
4. 结论
Adeos是相当简单的1段代码,如果使用得当包括了许多有趣的属性。Adeos模型的主干是时间管线,正因如此,它提供了所有我们在Xenomai中需要的重要特点:
- 可预测的中断延迟;
- 精确中断虚拟化控制(每一个域和每一个中断处理程序注册,每一个域和每一个CPU的中断屏蔽);
- 统1、优先级和面向域的事件传播模型;
- 1个通用和简单的API来简化客户代码的移植。
Xenomai使用这些特点来寻求Linux内核带来的实时服务的最大可能的集成。Xenomai的主要模式在最低的微秒即的延迟提供真的实时性能。另外,Xenomai在Linux未来演变中赌注,来改良内核的整体粒度,例如PREEMPT_RT,因此次要模式仍在在肯定意义上的实时,即便是最坏情况下的延迟也是可测的。这就是为何Xenomai从第1天开始就努力工作来到达与Linux内核高度集成的层次。斟酌共生,寻求共利。
5. 链接
- Karim Yaghmour's Adeos 提议: http://www.opersys.com/ftp/pub/Adeos/adeos.pdf
- 乐观中断保护: http://citeseer.nj.nec.com/stodolsky93fast.html
- GNA上的Adeos工作目录: https://gna.org/projects/adeos/
- 下载最新的Adeos补钉: http://download.gna.org/adeos/patches/
- Adeos API 参考手册: http://home.gna.org/adeos/doc/api/globals.html