免费国外ddos网站,网页设计与网站建设课设,小程序制作软件下载,中国建设人才网证书查询文章目录 1. 简介1.1 实时OS1.2 Adeos域 (Domain)中断管道#xff08;Interrupt Pipe#xff09;事件管道(event pipeline)乐观的中断保护系统事件传播基于Linux的实现 1.3 Adeos为Xenomai提供的服务Xenomai的主要和次要域名系统调用拦截中断传播启用/禁用中断源在域之间共享… 文章目录 1. 简介1.1 实时OS1.2 Adeos域 (Domain)中断管道Interrupt Pipe事件管道(event pipeline)乐观的中断保护系统事件传播基于Linux的实现 1.3 Adeos为Xenomai提供的服务Xenomai的主要和次要域名系统调用拦截中断传播启用/禁用中断源在域之间共享中断中断共享和延迟结论Xenomai用户层实时的实现(TSC)Xenomai多API构架(skin)Xenomai的应用接口在Cobalt和LInux之间迁移线程Real-Time Driver Model (RTDM)Tooling with CobaltXenomai 和 Linux 的关系 1.4 实时linux基础1.5 RTAI vs Xenomai1.6 XenomaiXenomai系统架构xenomai3的两种配置Adeos/iPipeHAL核/钴(Cobalt)调度(scheduler)用户接口(skins)Xenomai与PREEMPT_RT的差异RTDM 1.7 Xenomai资源task latency的产生原理GIC原理如何选择xenomai特性 2. 安装2.1 在覆盆子(pi)的Xenomai 32.2 观察与分析2.3 Performance性能表现Linux实时性对比user/kernel/timer IRQ (R-pi)user/kernel/timer IRQ (Beaglebone) 2.4 Cyclictest原理 3. Xenomai移植3.1 Installing the Cobalt corexenomai目录结构Cobalt内核的准备配置和编译Cobalt内核Cobalt内核参数Building a Cobalt/x86 kernel (32/64bit)Building Cobalt/arm kernelBuilding Cobalt/arm64 kernel 3.2 Installing the Mercury core3.3 Installing the Xenomai libraries and toolsPrerequisitesConfiguringCross-compilationBuilding the x86 libraries (32/64bit)Building the ARM librariesBuilding the ARM64 librariesTesting the installation 3.3 Building and running Xenomai 3 applicationsCompiling a Xenomai 3 applicationCompiling a RTDM-based module 3.4 Running a Xenomai 3 applicationValgrind support 3.5 Xenomai ApplicationHow to build an applicationStandard Xenomai command line optionsAccessing the tunablesApplication entry (C/C)Under the hood 3.6 AM528移植3.7 ubuntu移植 1. 简介
1.1 实时OS
现阶段的RTOS分成两个阵营
非Linux阵营VxWorksRTEMSLinux阵营 RT-linuxPreempt-rtWindRiver LinuxRTAIXenomai。
下面重点介绍Linux阵营。 RT-linux应该是第一批实时性linux可以提供硬实时有两个版本免费版和收费版收费版最初由 FSMLabsFinite State Machine Labs公司开发在2007年卖给了 WindRiver。之后 WindRiver 将其作为自己的产品 WindRiver Linux 的一个实时核心real-time core象征性的维护了一段时间与2011年8月彻底停止更新和维护。RT-linux 的性能应该很好WindRiver 应该是出于竞争的目的对其进行了收购现在 RT-linux 已经不再更新因此对于我们也只能当做了解一段历史了。 WindRiver LinuxWindRiver 为 Linux 世界提供的一个发行版具备软实时的能力应该吸收了一部分 RT-Linux 的核心技术感觉是 WindRiver 为了延长其产品线提高行业竞争力和覆盖面而开发的系统还没进行深入分析毕竟是软实时。 Preempt-rtIngo Molnar 引领的 Linux kernel 实时 patch可以改善通用 Linux 的实时性也是本项目前期工作的重点。 RTAIReal-Time Application Interface项目应该继承自 RT-linux后期吸收了 Xenomai 的一部分思想专注实时性能应用广泛。 Xenomai2001 年 8 月由 Philippe Gerum 发起其思想是来源于 Karim 的 ADEOSAdoptive Domain Environment for Operating System。发布后即被 RTAI 采用并一度合并为 RTAI/Fusion。后于2005年独立。Xenomai 的实时性能比RTAI略差因为其完全由 ADEOS 控制中断而 RTAI 是由其内核对中断进行了截断非实时的中断才交给 ADEOS这就减少了一部分实时开销。
双核如RTLinuxRTAIXenomai实时方案。运作一个real-time核心然后将修改过的GNU / Linux核心程序码视为该实时核心的空闲任务。
常用的双内核法实时补丁有 RTLinux/GPL、RTAI 和 Xenomai其中RTLinux/GPL只允许以内核模块的形式提供实时应用而RTAI和Xenomai支持在具有MMU保护的用户空间中执行实时 程序。
1.2 Adeos
Adeos的全称是Adaptive Domain Environment for Operating System它的目标是为操作系统提供了一个灵活的、可扩展的自适应环境在这个环境下多个相同或不同的操作系统可以共存共享硬件资源。
目前主要存在两类方法使多个操作系统运行在同一个系统上
第一类方法是模拟例如VMWarePlex86和VirtualPC等它们都是在已有的操作系统上提供一个虚拟的硬件环境在这个虚拟硬件环境下可以运行另外操作系统。这样用户就可以充分的利用两个或多个系统所提供的功能和软件但这种方法最大的缺点就是会极大的降低系统的性能因为它包含三个软件层次主机操作系统Host Operating System - 虚拟硬件环境 - 客户操作系统Guest Operating System。第二类方法是在硬件上实现一个所谓的超微内核nano-kernel通过这个超微内核实现硬件的共享然后再在这个内核上构建实用的操作系统例如SPACECache kernel和Exokernel等。
但这些方法都没有考虑当前已经存在的操作系统和用户。
Adeos是在已有的操作系统下插入一个软件层通过向上层多个操作系统提供某些原语和机制而实现硬件共享。但是Adeos并不对硬件的使用强加任何的限制上层的操作系统仍然可以自由的操作硬件而不会因为Adeos的存在而有任何的约束实际上上层的操作系统可以完全不知道有Adeos的存在。 Adeos除了可以实现操作系统对系统资源的共享之外还可以用于新的操作系统的开发、操作系统内核的调试、跟踪等。 目前Adeos是基于Linux内核实现的主要的应用是在Linux的实时化方面使基于Linux的系统能满足硬实时的要求LinuxRTAI。
Adeos实现的功能主要包括
中断管道机制(I—Pipe)、域管理模块和域调度模块功能。
域 (Domain)
为此Adeos允许多个实体称为域同时存在于同一台机器上。这些域名不一定相互看见但所有这些域名都看到了Adeos。域很可能是一个完整的操作系统但没有假设关于域中的内容的复杂性。但是根据系统范围内的优先级所有域都可能竞争处理外部事件例如中断或内部事件例如陷阱异常。
在基于Adeos的系统中每个操作系统都在独立的域内运行但不一定所有的域内实现的都是操作系统也可以是完成其它功能的软件实体每个域可以有独立的地址空间和类似于进程、虚拟内存等的软件抽象层而且这些资源也可以由不同的域共享。在基于Adeos的系统中存在着四种类型的交互如下图所示
A类交互是各个域对硬件的直接操作这些操作包括访存和和对硬件的设置等在这种情况下就和Adeos不存在一样B类交互是双向的一方面Adeos接收硬件产生的中断和异常另一方面Adeos也直接控制硬件C类交互指当Adeos接收到硬件中断后会执行相应域的中断服务程序D类交互指当域内的操作系统知道有Adeos存在的时候它可以主动向Adeos请求某些服务例如请求共享其它域中的资源、请求授权域优先级等。通过D类交互可以实现各个域之间的通讯。
中断管道Interrupt Pipe
对于一个计算机系统来说系统的运行是由内部和外部的中断和异常所触发的例如系统时钟中断对操作系统来说就是最重要的操作系统没有了系统时钟中断就像人没有了心跳一样所以说如果想要控制操作系统的运行最直接的方法就是接管操作系统的中断处理机制。所以Adeos的主要工作就是管理硬件的中断根据域的优先级依次执行相应域的中断服务程序从而驱动域内的系统运行同时Adeos还提供域之间的通信机制、实现域的调度等。为了实现对中断的管理和域之间的优先级控制Adeos使用了中断管道Interrupt Pipe的概念如下图所示
Adeos通过中断管道在不同的域之间传播中断而且提供了相应的机制可以让域改变自己在中断管道中的优先级在图中各个域的优先级为域1域2……域NIdle域。
通常在操作系统中对中断的处理方式有两种允许中断和禁止中断但在基于Adeos的系统中由于存在着中断管道域内的操作系统对中断的处理方式还有另外两种抛弃中断和终止中断。
如果某个域允许中断中断产生后Adeos会调用相应域的中断处理程序这和不存在Adeos的情况是类似的只不过在这种情况下中断服务程序由Adeos负责调用如果某个域禁止中断实际上并没有真正禁止硬件中断而只是设置了一个软件标志当硬件中断沿沿着中断管道进一步向下传播。如果某个域抛弃某个硬件中断当中断传播到这个域的时候Adeos不做任何的处理直接将这个中断沿着中断管道向后传播。如果某个域终止某个中断当中断传播到这个域的时候Adeos根据这个域的设置处理完这个中断之后不再将这个中断沿着中断管道向后传播也就是说后面低优先级的域将不知道有这个硬件中断的产生。
所以Adeos就是通过控制系统的中断来实现对各个域内操作系统的控制。从下图可以对基于Adeos的系统的运行模型有一个整体的概念其中D1、D2分别代表两个域且优先级为D1D2为了使描述更加清晰明了对系统作如下的假设 系统有两个域D1和D2两个域完全一样除了优先级D1D2且两个域都允许中断 整个系统只有两个硬件中断INT1和INT2 每个域有两个中断服务程序ISR1和ISR2分别对应于INT1和INT2 每个域有两个任务TASK1和TASK2不包括IDLE任务分别由ISR1和ISR2触发运行且TASK1的优先级高于TASK2只有当TASK1任务完成后TASK2才能开始运行 从上图可以看出
在T1时刻Adeos接收到了硬件的中断信号然后就开始遍历中断管道找到最高优先级的域D1然后执行域D1的中断服务程序ISR1ISR1执行完后就切换到域D1D1内的任务TASK1开始运行TASK1运行完成后域D1就被挂起SuspendedAdeos然后执行D2的中断服务程序ISR1ISR1执行完后就切换到域D2开始D2内TASK1的运行当D2的TASK1运行到T2时刻时硬件产生了中断信号INT2域D2被中断Adeos接收到INT2后又再一次开始从头遍历中断管道找到了最高优先级的域D1然后执行D1的中断服务程序ISR2ISR2执行完后就切换到域D1开始D1内任务TASK2的运行TASK2运行完成后域D1被挂起Adeos然后执行D2的中断服务程序ISR2ISR2执行完后就切换到域D2并开始域D2内被中断的任务TASK1和新触发的任务TASK2的执行当域D2的任务都执行完成后域D2被挂起系统进入IDLE状态。
事件管道(event pipeline)
必须牢记的基本Adeos结构是要求事件控制的客户域链。域是基于内核的软件组件可以要求Adeos层通知
每个传入的外部中断或自动生成的虚拟中断;Linux应用程序发出的每个系统调用内核代码触发的其他系统事件例如Linux任务切换信号通知Linux任务退出等
Adeos确保根据系统中各自的优先级以有序的方式将事件分派给各个客户域因此可以提供这些事件的及时和可预测的传递。这是通过为每个域分配静态优先级来实现的。此优先级值严格定义事件到域的传递顺序。所有活动域根据其各自的优先级排队形成Adeos用于使事件从最高优先级域到最低优先级域流动的管道抽象。将传入事件包括中断推送到管道的头部即到最高优先级域并向下进行到其尾部即到最低优先级域。下图给出了一些基于Adeos的系统的一般视图
在上图中Linux内核相对于流水线订单的位置可能是任何位置; 这就是说Linux内核仍然有一个特殊的角色因为它代表根域因为所有其他域都需要Linux来安装它们通常是通过加载体现它们的内核模块。
乐观的中断保护
为了以优先级的方式分发中断同时仍允许域创建无中断部分Adeos实现了Stodolsky, Chen, 和 Bershad描述的所谓的乐观的中断保护模型。在这篇的论文中。[http://citeseer.nj.nec.com/stodolsky93fast.html] 任何给定的域占用pipeline的阶段都能被推迟这意味着下一个到达的中断将不会被分发到域的处理者并将会被阻止以同样的举动流到最低优先级域。 当一个阶段被推迟暂停的中断累积在域中断日志中最终在这个阶段不再被推迟时被一个名为同步的内部操作处理。域使用这种特点来保护他们自己的临界区不被他们自己的中断处理有害的抢占。 然而多亏Adeos带来的中断控制虚拟化一个更高优先级的域仍能接收中断并且最终抢占任何低优先级域。实际上这意味着 即使一个基于Adeos的Linux内核经常推迟它自己的阶段来处理临界区操作一个提前运行的实时系统在pipeline中仍能在任何时候够接收中断不会产生任何延迟。 当一个域处理完了它所接收到的待处理的中断它会调用一个特殊的Adeos服务让出CPU到pipeline的下一个域所以后者可以依次处理唤醒它的待处理的事件并且这个周期会持续到管线的最低优先级域。 下图说明了运行在多CPU上的多个域怎样通过Adeos pipeline抽象共享传入的中断。当然当一个阶段被推迟必须正确的标记待解决中断这是通过一个每域每CPU中断日志实现的见下面的解释
系统事件传播
中断不是唯一一种可以流经管线抽象的事件Linux内核自己触发的内部事件或者它的应用程序产生的所谓的系统事件。从根本上说系统事件是陷阱、异常或某些Linux内核的动作的同步通知并通过管线通知任何感兴趣的部分。
由于这些事件的本质是同步的没有办法通过推迟操作推迟他们的唤醒仅仅是因为你不能延迟他们的处理。这样设计决定的依据来源于这样一个事 实代码触发一个系统事件可能仅仅是没有响应处理程序的干预不能继续处理例如缺页处理程序在内存寻址异常后应该立即执行延迟它没有任何意义。换句话 说在给定的域上的延迟/非延迟操作仅仅关心中断不管是真实的还是虚拟的。
基于Linux的实现
考虑到从硬件层开始构建一个操作系统的难度Adeos并没有并没有从零开始构建一个硬件抽象层目前Adeos是基于Linux内核实现的这样的话就可以将系统的启动和初始化工作都由Linux来完成在系统完成初始化后再进行Adeos的初始化工作包括接管Linux的中断管理机制Adeos功能既可以直接编译进内核也可以作为一个内核模块在系统运行时动态加载就和内核的驱动程序模块一样。 在这种实现方法下Linux作为Adeos的一个特殊的域存在我们称之为根域Root Domain。Adeos的很多功能都是依靠根域也就是Linux内核来实现的例如动态注册其它的域模块是通过Linux的动态模块加载功能实现的为其它域的任务分配任务堆栈是通过Linux内存分配接口实现的等。根域的初始化是在Adeos的初始化过程中完成的根域对于Adeos来说有一点类似于Linux初始化过程中创建的INIT进程
Adeos在Linux配置中增加了三个配置开关来配置Adeos的代码CONFIG_ADEOS_CORECONFIG_ADEOS和 CONFIG_ADEOS_MODULE。
如果定义了CONFIG_ADEOS_COREAdeos的核心支持就被编译进了Linux内核不论 Adeos功能最终编译进内核还是编译成可动态加载的模块这个编译选项都必须被定义如果定义了CONFIG_ADEOS则也隐含着对 CONFIG_ADEOS_CORE的定义Adeos功能就被编译进了内核那么从Linux启动以后Adeos功能就被使能了如果定义了 CONFIG_ADEOS_MODULE则也隐含着对CONFIG_ADEOS_CORE的定义Adeos功能被编译成可动态加载的模块只有当这个 模块被加载后Adeos的功能才会起作用。Adeos对Linux源代码树的修改涉及到30多个文件包括新增加的文件如下图所示
其中的Makefie和Config.in文件是为Adeos代码添加内核编译选项和内核配置选项 adeos目录下的generic.c包含了与平台无关的通用的Adeos代码而armv.c则包含了与ARM平台相关的通用于ARM平台的Adeos代码 在arch/arm/kernel目录下adeos.c中包含了Adeos关于中断处理的代码armksyms.c中增加了代码导出了ARM体系相 关的Adeos接口 entry-armv.S和entry-common.S中增加了截获Linux中断和系统事件的代码域的切换代码也在此处实现 同时修改了irq.c以适应Adeos的中断处理机制在process.c中修改了Linux的idle进程当Linux进入idle状态时将通 知Adeostime.c中增加了Adeos中修改定时器频率的接口 Documentation/adeos.txt对Adeos进行了简单的介绍 在init/main.c中增加了对Adeos进行初始化的代码 kernel/adeos.c中包含的是Adeos对根域也就是Linux操作的代码对kernel目录下的其它文件的修改主要是为了增加Adeos对Linux系统事件进行捕获所需的代码
1.3 Adeos为Xenomai提供的服务
Xenomai需要提供什么样的基本保证才能提供实时服务答案很简单明了
在Linux内核有机会注意到它们之前必须首先允许它处理所有传入的中断并且必须能够立即处理它们无论当前从Linux内核到使用CPU中断屏蔽将它们锁定。它还必须确保始终对其线程强制执行适当的优先级管理而不管它们当前的执行域。
无论Linux正在进行什么样的活动这些保证都能让Xenomai在最低的微秒级范围内实现可预测的中断延迟这种活动曾与Xenomai的Linux任务的快速协同调度技术即影子线程相结合提供了实时线程的确定性调度延迟。 您会注意到Adeos接口直接暴露于作为Xenomai核心基础的硬件抽象层。因此大多数对Adeos服务的请求都是从HAL发出的该实现可以在相关arch//hal 目录中找到通用位可用于arch/generic/hal。查看后者是理解Xenomai如何将Adeos用于其自身目的的最佳方法。
Xenomai的主要和次要域名
Xenomai允许运行实时线程在严格内核空间或者在Linux线程地址空间。在文章剩下的部分我们把后者称作Xenomai线程不会与 常规Linux任务产生混淆即使他们属于 SCHED_FIFO 类。Xenomai管理的所有线程可以从实时nucleus中获知。
对用户空间中真正实时支持的出现之前实时应用程序只运行到内核模块中支持实时线程排他的运行在内核空间仅仅是一个单核时代的一个回忆。Xenomai中保留此功能主要是为了支持遗留应用程序此处不再讨论。
更有趣的是Xenomai在Linux方面采用了共生方法; 例如这就是它与RTAI / LXRT实现的不同之处。为此Xenomai线程不仅能够在管道即主域中的最高优先级域的上下文中运行如基于内核的Xenomai线程而且还能够在常规Linux空间即辅助域中运行尽管Xenomai仍然被认为是实时的但遭遇更高的调度延迟。在Xenomai的术语中前者据说以主要执行模式运行而后者则经历二级执行模式。 为了向在辅助域中运行的线程提供完整的实时支持Xenomai需要实现以下功能 通用优先级机制(Common priority scheme)。在调度方面我们需要一种方法让实时核和Linux内核共享相同的优先级方案相对于它们共享控制权的线程集; 换句话说Xenomai线程应该在所有现有Xenomai线程中随时正确执行其优先级无论其当前域如何。Xenomai应用它所谓的根线程的可变优先级技术Linux内核通过该技术自动继承由进入二级域的实时核心控制的Xenomai线程的优先级。实际上这意味着当前在主域中运行的Xenomai线程不一定会抢占在辅助域中运行的线程除非它们的有效优先级实际上更高。上述行为与RTAI / LXRT所发生的情况相反例如通过继承RTAI调度程序定义的最低优先级迁移到Linux空间的线程实际上在同一个移动中失去了它们的实时优先级。这就是说Xenomai不知道的常规Linux任务只碰巧属于SCHED_FIFO类在与来自主要Xenomai域的Xenomai线程竞争CPU时总会被抢占尽管他们仍然会优先与Xenomai线程竞争在辅助域中运行。 程序执行时间的可预测性(Predictability of program execution times)。当Xenomai线程在Linux即辅助域上运行时无论是执行内核还是应用程序代码其时序都不应受非实时Linux中断活动的干扰一般来说任何低优先级的异步活动都会发生在内核级别。防止后者发生大多数机会的一种简单方法是在Xenomai线程在Linux域中运行时使Linux内核免于中断以便在此期间不会从上半部分中断处理程序触发延迟后处理时间 让Linux内核免受中断困扰的一个简单方法是在中间的Adeos域中需要时阻塞它们这些域位于实时核心和Linux内核之间这在Xenomai的术语中被称为中断屏蔽。每当Linux内核调度Xenomai线程时都会使用此屏蔽并在所有其他情况下脱离。应该注意的是屏蔽支持可以在每个线程的基础上启用/禁用或者在Xenomai构建时在系统范围内启用/禁用; 默认情况下它是针对Xenomai线程禁用的而不是内置的。 细粒度的Linux内核(Fine-grained Linux kernel)。为了从辅助执行模式中获得最佳效果我们需要Linux内核展示尽可能短的不可抢占部分以便在辅助域中运行的Xenomai线程准备就绪后尽快重新安排机会。 -跑。此外这确保Xenomai线程可以在短时间限制的时间段内从主域迁移到辅助域因为此操作涉及到达内核重新安排点。出于这个原因Xenomai受益于Linux内核整体可抢占性的持续改进趋势包括Ingo Molnar的PREEMPT_RT扩展。当然只在主域运行的Xenomai线程不受Linux内核粒度级的影响 优先倒置管理(Priority inversion management)。实时核心和Linux内核都应该处理高优先级线程不能运行的情况因为低优先级线程在可能无限制的时间内保存竞争资源。Xenomai提供了这种支持但只有PREEMPT_RT变体才能为Linux内核提供支持。出于这个原因Xenomai密切关注并为PREEMPT_RT的当前发展提供支持尽管主线内核仍然是目前的参考系统。
由于上述要求当加载Xenomai核心时底层的Adeos管道包含三个阶段所有中断都按优先级顺序流动
Xenomai的主要领域它是实时核心的所在地;中断屏蔽域;Linux域名。
系统调用拦截
由于可以在Xenomai核上堆叠的实时API即皮肤可以将自己的一组服务导出到用户空间中的Xenomai线程因此必须有一种方法可以正确地调度相应的系统调用和常规Linux内核系统调用适当的处理程序。为此Xenomai拦截Xenomai线程代表任何Xenomai或Linux域发出的每个系统调用陷阱/异常。这可以通过使用适当的Adeos服务订阅事件处理程序来实现有关更多信息请参阅 adeos_catch_event()服务指定 ADEOS_SYSCALL_PROLOGUE/IPIPE_EVENT_SYSCALL事件时。Xenomai使用此功能
将应用程序的实时服务请求分派给适当的系统调用处理程序这些处理程序由运行在实时核心上的各种API实现;通过根据需要将调用方无缝迁移到目标域确保在适当的域Xenomai或Linux的控制下执行每个系统调用。例如在将请求中继到常规Linux系统调用处理程序之前从Xenomai域中运行的Xenomai线程发出的Linux系统调用将导致调用方自动迁移到Linux域。相反在最终执行服务之前调用可能阻塞的Xenomai系统调用的Xenomai线程将被移动到Xenomai域以便调用者可以在实时核的控制下睡眠。
两者的结合使Xenomai线程特别好地集成到Linux领域。例如Xenomai和常规Linux应用程序的通用系统调用路径使前者显示为后者的自然扩展。作为对此的一个例证Xenomai线程都支持完整的Linux信号语义和ptracing功能这反过来又为它们本身提供了GDB支持。
中断传播
因为它在管道中处于领先地位所以存在于Xenomai域中的实时核心首先被通知任何感兴趣的传入中断处理它然后将这样的中断标记为传递到管道最终传递到Linux内核域如果需要的话。
当从传入中断通知时实时核在外部中断处理程序返回后重新调度如果中断堆积并切换它控制的最高优先级可运行线程。
当没有实时活动待处理时Xenomai域将CPU发送到中断屏蔽域这反过来只要它被释放到Linux内核就会通过它或者如果它被占用则阻塞它们。Adeos通过管道有两种基本的中断传播模式
在隐式模式下任何传入的中断都会被Adeos自动标记为待处理的每个接收域的日志接受中断源。在显式模式下如果中断处理程序需要则必须“手动”将中断传播到管道下的邻居域。
此设置基于每个域每个中断定义。Xenomai始终对其截获的所有中断使用显式模式。这意味着每个处理程序必须调用显式传播服务以将传入中断传递到管道。当Xenomai没有为给定的中断定义处理程序时中断无条件地传播到Linux内核当实时核不拦截这样的中断时这使系统保持工作。
启用/禁用中断源
除了能够完全停止域以便在明确未安装之前不再有中断流过它之外Adeos还允许在硬件级别选择性地禁用和相反地重新启用实际的中断源。
接管后Adeos处理所有域的中断禁用请求包括Linux内核和实时核心。这意味着在硬件PIC级别禁用中断源并锁定从该源到管道级别的当前域的任何中断传递。相反启用中断意味着重新激活PIC级别的中断源并允许从此源进一步传送到当前域。因此启用中断源的域必须与禁用它的域相同因为此类操作依赖于域。
实际上这意味着成对使用时rthal_irq_disable()和rthal_irq_enable()服务集成了构成了 Xenomai基础的实时HAL内相关Adeos的调用必须由同一Adeos域解决。例如如果一个实时中断处理程序用 rthal_irq_request()服务于某个中断源连在一起禁用中断源使用rthal_irq_disable()那么这个源将会被 Xenomai域阻塞直到同一中断源的rthal_irq_enable()被同一域调用。处理这个请求失败将会导致受影响的中断通道永久性丢失。
在域之间共享中断
一个在域间共享硬件中断时误用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 wont 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 wont 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的中断仍然被锁定在管道级别请记住没有人实际发出rthal_irq_enable() Xenomai域的预期但只是错误地从Linux中发出这不会发生因为Xenomai处理程序将不会运行直到锁被删除。因此好吧chickenandegg问题我们敬酒。
幸运的是有一种解决方案可以在需要保持中断源禁用的域之间正确共享中断直到完成最终处理例如处理级别触发的中断是其中一个问题实际上您不需要做任何事情因为Adeos已经屏蔽了PIC级别的任何输入中断然后再向其提供管道。因此您只需要根据相应的域处理程序处理中断并确保使用最后一个中断源重新启用 rthal_irq_enable()。只要Linux内核是其中一个收件人常规内核处理程序就会自动重新启用所以基本上你只需要打扰调用 rthal_irq_enable()处理程序这些处理程序不会将传入的中断传播到Linux内核的下游。
特别是在x86架构上由于性能原因在Adeos收到定时器中断时没有被屏蔽。这就是说定时器源不是你可能想要以任何方式禁用的定时器源所以这是一个非问题。
中断共享和延迟
但是在通过整个流水线进行传播时保持屏蔽中断源可能会增加延迟。
由于Adeos保证不会因为在任何给定域上堆积的中断而发生堆栈溢出并且因为它在触发中断处理程序之前也会使当前阶段停止所以不需要在Xenomai处理程序中禁用中断源。相反您甚至可能希望重新启用它以便可以立即记录更多事件并在当前处理程序调用返回后立即播放。
因此解决方案是以这种方式重写前一个示例这次正确
void realtime_eth_handlerunsigned irqvoid * cookie
{rthal_irq_enableIRQ;rthal_irq_host_pendIRQ;/ *此irq已被标记为待处理Linux * /
}void linux_eth_handlerint irqvoid * dev_idstruct pt_regs * regs
{/ *正常处理IRQ。* /
}结论
Adeos是一段相当简单的代码在正确使用时具有非常有趣的属性。Adeos方案的主干是事件管道因此它带来了我们在Xenomai中需要的所有关键功能
可预测的中断延迟;精确的中断虚拟化控制每域和每中断处理程序注册每域和每个CPU中断屏蔽;事件的统一优先和面向域的传播方案;一种通用且简单的API可简化客户端代码的可移植性。
Xenomai使用这些功能来寻求最佳的Linux内核实时服务集成。Xenomai的主要模式可在最短的微秒延迟范围内提供真正的实时性能。此外Xenomai对未来的Linux演进进行了投注如PREEMPT_RT以提高内核的整体粒度以便辅助模式在确定性意义上仍然是实时的尽管有更高的最坏情况延迟。这就是为什么Xenomai从第一天起就努力工作以达到与Linux内核紧密集成的水平。共生思想寻求共生。
Xenomai用户层实时的实现(TSC)
Xenomai除了在内核层利用Adeos实现了硬实时外它在用户空间也有很好的实时性。在S3C2410平台上为了实现用户层的实 时Xenomai实现了一个硬件计数器——Decrementer。这个硬件计数器可以在用户空问里很好地模拟TSC(Time Stamp Counter时间戳计数器)。
同时Xenomai在Linux内核中加入了一个全新的数据结构__ipipe_tscinfo可以通过此数据结构变量存放用户层需要的数据。该数据结构组成如下
在用户层应用程序通过系统调用可以迅速得到struct_ipipe_tscinfo结构体中的数据。而且为了避免受到缓存的影响Xenomai将此结构体变量存放在Linux的向量页中。内核通过函数_ipipe_mach_get_tscinfo来填充struct_ipipe_tscinfo结构体变量中的各项内容 info一typte说明在S3C2410平台上TSC是基于Decrementer硬件计数方式的 info 一udeccounter用来将Decrementer计数器的物理地址设定为0x51000038 info 一udecmask掩码用来注明使用Dec—rementet。计数器中的特定位 info一udectsc指向存放64位 TSC值的区域。
在Xenomai用户层的实时程序运行时程序都会通过系统调用得到内核填充好的struct_ipipe_tscinfo结构体变量。具体实现可参考编 译用户层实时程序时用到的由Xenomai所提的头文件/usr/xenomai/include/asm/syscallh。
Xenomai多API构架(skin)
除了提供Linux硬实时Xenomai的另一个目的是使基于Linux的实时操作系统能提供与传统的工业级实时操作系统(包括VxWorks、 pSOS、VRTX或者uITRON)功能相同的API。这样可以让这些操作系统下的应用程序能够很容易地移植到GNULinux环境中同时保持 很好的实时性。 Xenomai的核心技术表现为使用一个实时微内核(real—time nucleus)来构建这些实时API也称作skin。在实时核复用的基础上一个skin可以很好地模拟一种实时操作系统的API。它的结构图可以参考图2。
图2中Native是Xenomai自带的API各类API都有着同等的地位都独立地基于同一个实时微内核。这样做可以让内核的优点被外层所有的 API很好地继承下来。更重要的是实时微内核提供的服务被外层各种API以不同的方式表现出来由此可以增强整个系统的强壮性。
编制实时程序时在很多实时操作系统上只能在内核层实现而编制实时内核模块时会受到内核的限制比如有些实时内核不支持浮点运算模块出错时容易使整 个系统挂起而且内核模块的调试比较困难。Xenomai能够支持较好的用户层实时这为编制实时性要求不是非常高的实时程序提供了一个有效途径。
下面这 个用户层实时例程使用的是Xenomai提供的Native API
从程序中可以看出Xenomai的用户层实时程序的周期可以轻易地设定到μs级所以它完全可以适用于一般实时性要求的工程应用。
Xenomai的应用接口
Dispatching problem
Cobalt和传统的libc都实现了POSIX接口RT实时应用怎么来选择呢
• Both Cobalt and libc provide POSIX implementations
• How do RT application pick the right one?Solution: symbol wrapping
使用符号包装的方式来解决给符号首先加上_wrap开头给libcobalt解析对于不能解析的符号再传递给libc解析.
• Example pthread_mutex_lock → __wrap_pthread_mutex_lock
• libcobalt provides __wrap_*, forwards unhandled invocations to libc
• No source code changes to POSIX applications required
• Some additional services available (*_np)Supported architectures
• ARM (32 bit, 64 bit upcoming)
• Blackfin
• PowerPC (32 bit, 64 bit)
• x86 (32 bit, 64 bit, 32-on-64 bit, x32)在Cobalt和LInux之间迁移线程
Preserve Linux service for Cobalt threads
怎么样为Cobalt线程保留Linux服务
• Linux syscalls
• Fault and trap handling
• Handling of asynchronous signalsSolution: every cobalt thread is also a Linux task
每个colbalt线程同时也是一个Linux进程共享线程状态但是同一时刻只能是cobalt/linux其中的一种。
• Share thread states
• Only one can run at a time
• Migration to RT: suspend Linux task, resume Cobalt thread
• Migration to Linux (on syscall, fault/trap, signal): suspend Cobalt thread, resume Linux taskReal-Time Driver Model (RTDM)
Goals and principles
• Provide environment for co-kernel real-time drivers
• Service interface towards applications and other drivers
• Low-level primitives from implementing drivers
• Reuse Linux for non-RT purposes
(setup / shutdown, resource discovery and claiming, etc.)Two types of RTDM devices
• Character device (open/close, read, write, ioctl)
• Protocol device (socket, bind, send, recv, etc.)Device profiles
• Character: UART, UDD (analogous to UIO), Memory, ...
• Protocol: UDP/TCP (RTnet), CAN, IPC, ...Tooling with Cobalt
Debugging
• gdb works
• Improvements on synchronous stop/resume are work in progressTracing
• ftrace (tracecmd Co.)
• I-pipe latency tracer (low-level latency hunts)Valgrind/Helgrind
• No support because of unknown syscalls
• Alternative: Mercury (native support)
• Limited suitability for RT applications in generalXenomai 和 Linux 的关系
xenomai的核心思想是实时性
中断处理ipipe。
调度Aedos域的调度使用cobalt/nuclearlinux域的调度使用linux自己的scheduler。
系统调用
应用接口skins。提供兼容传统RTOS的API支持如RTAI、POSIX、VxWorks、uITRON、 pSOS等。
驱动模型RTDM。
定时器除此以外要保持扩展性和兼容性
启动使用linux的启动。
进程进程创建和进程空间管理使用linux现成机制。实时进程可以切换到linux普通进程。
内核API实时进程可以调用linux内核的普通API。调用时会发生模式切换。
内存分配使用Linux的内存分配机制。1.4 实时linux基础
实时Linux如何工作
实时RTLinux的总体思想是小型实时内核在Linux下运行这意味着实时内核比Linux内核具有更高的优先级。 实时任务由实时内核执行并且在不需要执行实时任务的情况下允许运行普通的Linux程序。 Linux可被视为实时调度程序的空闲任务。 当此空闲任务运行时它将执行自己的调度程序并调度正常的Linux进程。 由于实时内核具有更高的优先级因此当实时任务准备好运行并立即执行实时任务时通常的Linux进程将被抢占。
实时内核如何比Linux内核具有更高的优先级
基本上操作系统是由中断驱动的可以将其视为计算机的心跳
•OS中运行的所有程序均由调度程序调度该调度程序由时钟的计时器中断驱动以在特定时间重新调度。
•执行程序可以阻止或自愿放弃CPU在这种情况下通过软件中断系统调用通知调度程序。
•硬件可以生成中断来中断OS的正常计划工作以快速处理硬件。RT Linux使用中断流为实时内核提供比Linux内核更高的优先级
•当中断到达时首先将其分配给实时内核而不是Linux内核。但是存储了中断以便在实时内核完成后将其提供给Linux。
•作为第一排实时内核可以运行由这些中断驱动的实时任务。
•仅当实时内核什么也不运行时存储的中断才传递给Linux内核。
•作为第二排Linux可以调度由这些中断驱动的自己的进程。因此当正常的Linux程序运行并且有新的中断到达时
•它首先由实时内核设置的中断处理程序处理
•中断处理程序中的代码唤醒实时任务
•在中断处理程序之后立即调用实时调度程序
•实时调度程序观察到另一个实时任务已准备就绪可以运行因此它将Linux内核置于睡眠状态并唤醒该实时任务。因此需要一种在实时内核和Linux内核之间传递中断的特殊方式。每种RT Linux都以其自己的方式进行此操作。 Xenomai使用Adeos项目中的中断管道。有关更多信息另请参阅《 Adeos的生活》。
Linux内核系统调用与实时内核系统调用
如果程序希望完成某件事但没有正确的特权操作模式则通常的方法是生成特殊的软件中断称为系统调用。 程序被中断并且中断被提供给内核内核将根据程序的行为进行操作。中断中给出的消息确定必须执行哪个操作或哪个系统调用。系统调用的集合可以看作是内核的用户程序接口。 对于实时Linux我们有两个运行的内核即普通Linux内核和实时内核。对于每个特定内核分配一个唯一的软件中断。因此根据唯一的中断号我们知道它是Linux内核的系统调用还是实时内核的系统调用。因此我们有
•一组Linux系统调用使您可以调用内核API的一部分
•一组实时系统调用使您可以调用实时API的一部分注意因为实时内核首先获取中断所以实时系统调用将始终首先运行。
RT Linux任务不是Linux程序
观察实时任务和标准Linux程序之间的区别
•在实时Linux中我们可以通过对实时线程进行编程来制作实时程序。实时Linux中的非实时程序仅使用常规Linux线程。
•实时任务可以使用内核模块在内核空间中执行但也可以使用普通的C程序在用户空间中执行。
•在用户空间而不是内核空间中运行会产生一些额外的开销但是具有以下优点o内核模块中的错误可能会使整个系统崩溃但是用户空间程序中的错误只会使程序崩溃。o在内核模型中只能使用实时API和有限的内核API但是在实时用户空间程序中可以使用实时API和整个Linux API。但是在用户空间中使用Linux API时该程序不能由实时调度程序HARD实时调度而必须由Linux调度程序SOFT实时调度。因此从实时用户空间任务调用Linux API调用会将其性能从HARD实时降低为SOFT实时。调用之后任务将返回到实时调度程序。o在用户空间中您可以使用调试器调试实时程序。 例如针对C程序员的gdb。用户空间Xenomai开销与内核空间相比
将用户空间中的Xenomai任务与内核空间中的Xenomai任务进行比较观察到通过交换虚拟内存没有开销
•内核空间和用户空间都使用虚拟内存因此两者都必须在页表中查找实际内存
•Xenomai内核空间任务和Xenomai用户空间任务均被内存锁定1.内存的内核部分是锁定内存这意味着它永远无法交换到磁盘。 因此内核模块自动使用的内核内存永远不会交换到磁盘。2.内核空间中Xenomai任务的内存也无法交换到磁盘。 用户空间中的Xenomai任务是程序员在启动时锁定的内存。Xenomai API函数有一些开销
•用户空间Xenomai任务需要使用Xenomai系统调用来执行位于内核空间中的Xenomai API函数。
•内核空间的Xenomai任务只能对Xenomai API函数进行函数调用。1.5 RTAI vs Xenomai 图1所示为RTAI和Xenomai两个实时内核分别与标准Linux内核组成双内核系统是的分层结构。可以看到两者有稍微不同的组织形式与 Xenomai让ADEOS掌控所有的中断源不同的是RTAI拦截它们使用ADEOS将那些RTAI不感兴趣的中断通知送给Linux也就是中断 不影响实时时序。这样混合过程的目的是提高性能因为在这种情况下如果中断是要唤醒一个实时任务就避免了由ADEOS管理中断的开销。从这里可以看 出RTAI的实时性能应该是比Xenomai要好的。
RTAIReal-Time Linux Application interface虽然实时性能较好但对ARM支持不够更新速度极慢造成项目开发周期长研发成本高。
与RTAI相比Xenomai更加专注于用户态下的实时性、提供多套与主流商业RTOS兼容的API以及对硬件的广泛支持在其之上构建的应用系统能 保持较高实时性而且稳定性和兼容性更好此外Xenomai社区活跃紧跟主流内核更新支持多种架构对ARM的支持很好。
**Xenomai**是Linux内核的一个实时开发框架。它希望无缝地集成到Linux环境中来给用户空间应用程序提供全面的、与接口无关的硬实时性Xenomai是基于一个抽象实时操作系统核心的可以被用来在一个通用实时操作系统调用的核心上构建任意多个不同的实时接口。Xenomai项目始于 2001年8月。2003年它和RTAI项目合并推出了RTAI/fusion。2005年因为开发理念不同RTAI/fusion项目又从RTAI 中独立出来作为Xenomai项目。相比之下:
RTAI项目致力于技术上可行的最低延迟Xenomai除此之外还很着重扩展性、可移植性以及可维护性。 Xenomai项目将对Ingo Molnar的PREEMPT_PT实时抢占补丁提供支持这又是与RTAI项目的一个显著的不同。RTAI和Xenomai都有开发者社区支持都可以作为一个VxWorks的开源替代。
Xenomai是基于AdeosAdaptive Domain Environment for Operating System实现的Adeos的目标是为操作系统提供了一个灵活的、可扩展的自适应环境在这个环境下多个相同或不同的操作系统可以共存共享硬件 资源。基于Adeos的系统中每个操作系统都在独立的域内运行每个域可以有独立的地址空间和类似于进程、虚拟内存等的软件抽象层而且这些资源也可以 由不同的域共享。与以往传统的操作系统共存方法不同Adeos是在已有的操作系统下插入一个软件层通过向上层多个操作系统提供某些原语和机制实现硬件 共享。应用上主要是提供了一个用于“硬件-内核”接口的纳内核超微内核使基于Linux环境的系统能满足硬实时的要求。
Xenomai正是充分利用了Adeos技术它的首要目标是帮助人们尽量平缓地移植那些依赖传统RTOS的应用程序到GNU/Linux环境避免全部 重写应用程序。它提供一个模拟器模拟传统实时操作系统的API这样就很容易移植应用程序到GNU/Linux环境中同时又能保持很好的实时性。 Xenomai的核心技术就是使用一个实时微内核来构建这些实时API也称作“Skin”。Xenomai通过这种接口变种技术实现了针对多种传统 RTOS的应用编程接口方便传统RTOS应用程序向GNU/Linux的移植。图2描述了Xenomai的这种带Skin的分层架构。 从图2可以看出Xenomai系统包含多个抽象层Adeos纳内核直接工作在硬件之上位于Adeos之上的是与处理器体系结构相关的硬件 抽象层Hardware Abstraction Layer, HAL系统的中心部分是运行在硬件抽象层之上的抽象的实时内核实时内核实现了一系列通用RTOS的基本服务。这些基本服务可以由Xenomai的本 地APINative或由建立在实时内核上的针对其他传统RTOS的客户API提供如RTAI、POSIX、VxWorks、uITRON、 pSOS等。客户API旨在兼容其所支持的传统RTOS的应用程序在Xenomai上的移植使应用程序在向Xenomai/Linux体系移植的过程 中不需要完全重新改写此特性保证了Xenomai系统的稳健性。Xenomai/Linux系统为用户程序提供了用户空间和内核空间两种模式前者通过 系统调用接口实现后者通过实时内核实现。用户空间的执行模式保证了系统的可靠性和良好的软实时性内核空间程序则能提供优秀的硬实时性。
**skin**提供了兼容传统RTOS的API封装如RTAI、POSIX、VxWorks、uITRON、 pSOS等。
1.6 Xenomai
双核如RTLinuxRTAIXenomai实时方案。运作一个real-time核心然后将修改过的GNU / Linux核心程序码视为该实时核心的空闲任务。
在xenomai中双内核就是Xenomai的Nucleus/Cobalt Core和Linux内核。 Xenomai改变整个系统架构让ipipe - xenomai scheduler来预先处理实时任务而Linux则拉到上层成为一个任务。这样可以避免Linux因为庞大的架构而影响处理实时的时间。
Xenomai系统架构
xenomai的软件版本已经由2.xx版本过渡到3.xx,架构发生了较大变化主要在实时内核不再是原来的Adeos改由现在的cobalt。
以下是Xenomai 2.6.4 架构 Xenomai是一个linux内核的补丁藉由在底层增加一个架构负责硬体与接收中断并将中断传给上层的OS这边称为域。Xenomai的两个域
域1Xenomai。调度核心(scheduler)为Nucleus/Cobalt应用接口为Skin。xenomai2的调度器为Nucleusxenomai3的调度器为Cobalt。域2Linux。调度核心(scheduler)为Linux原生应用接口为Linux原生。
这个底层的架构Adeos是另一个开源的项目。
在API呼叫上可以看到不同层级的抽象化
ipipe_XXX - rthal_XXX - xnXXX负责传送中断的程式称为ipipe示意图 可以找到ipipe_raise_irq将中断推到管道。在ipipe上每个域都有自己的优先度高优先度的域会先接收到中断高优先度的域的线程可以preempt低优先度域的线程。
interrupt shield是中断域盾的意思。
xenomai3的两种配置
Cobalt采用双核架构是xenomai 2的延伸。Mercury使用单内核形式在linux内核上提供xenomai api由于本身依赖linux一般来说会会以及PREEMPT_RT提供实时服务。
Xenomai 3双核配置Colbat(钴) 多一个优先比linux还高叫钴的核心去处理实时的事情提供不同的实时API给不同的应用程序使用。并且利用乐观中断保护机制减少改变中断掩码一般的机制在每次进入关键部分时都要中断屏蔽而乐观中断保护可以不用。 而实时在意的“截止日期”实际上就是探讨延迟延迟越大系统越难在时内内完成完成高优先于任务自然即时能力就越差而延迟很大的来源则是中断处理。
通过使用与它并行运行的实时协同内核来补充Linux。这个名为Cobalt的小扩展内置于Linux内核中处理所有时间关键活动例如处理中断和调度实时线程。Cobalt核心优先于本机内核活动。
在这种双内核配置中所有RTOS API Xenomai都提供与Cobalt核心的接口并且只有那些API被认为是实时的包括由Xenomaiaka libcobalt实现的POSIX 1003.1c服务子集。
Xenomai 3单核配置Mercury(汞)
运用本机的linux core在PREEMPT_RT之上达到real-time的事情这里不是强制的看应用程序对反应时间和最大抖动的要求有些甚至会作到某种程度截止日期的忽略。
依靠本机Linux内核的实时功能形成Mercury核心。通常应用程序需要在目标内核中启用PREEMPT-RT扩展以提供实时服务。
但是这不是强制性的它取决于响应性和最大抖动的应用要求; 有些人甚至可以容忍一定比例的截止日期未命中。
在这种单内核配置中Xenomai提供的所有非POSIX RTOS API都可以通过本机线程库最好是NPTL但也支持传统设置的linuxthreads进行精确模拟。
Adeos/iPipe
主要负责处理irq与高分辨率计时器ipipe的工作很简单就是设定计时器并将中断往上丢 Adeos功能 事件管道
利用管道的方式将不同域的中断或系统调用往上丢
乐观的中断保护
当同一个域在处理中断时有跟她相同域的中断要进来时会将它进入待定状态等到所有待中断完成时才会处理下个域的中断。但更高优先权域的中断会抢占较低优先权域的中断。
乐观与原生中断
原生 乐观: 从前两张图可看出一般的机制在每次进入临界区时都要中断掩码而乐观中断保护可以不用所以在中断管理的时间差很多。而实时在意的“deadline”实际上就是是探讨延迟延迟越大系统越难在时内内完成完成高优先任任务自然即时能力就越差而延迟很大的来源则是中断处理。
系统事件传播
系统事件例如页面错误句柄传递方式不同于interrupt基本上是不可被stall的。 实时支持在辅助域中运行的线程 共同优先方案
当xenomai任务迁移到linux域时linux域会继承xenomai任务的优先级。
程序执行时间的可预测性
当xenomai线程进入linux二级域时不可被linux域中断抢占掉也不能被其他低优先级活动在linux内核抢占掉。通常最简单实作方式就是加一个中断盾域。
细粒度的Linux内核
为了从二级域中获得最佳效果我们需要Linux内核展示尽可能短的不可抢占部分以便在二级域中运行的Xenomai线程准备好运行后尽快重新安排机会。
优先倒置管理
实时核心和Linux内核都应该处理高优先级线程不能运行的情况因为低优先级线程在可能无限制的时间内保持满足的资源。
相关文件︰
gic.c旧版 - irq-gic.c新版
通用中断控制器GIC为ARM架构中负责分配interrupt至cpu的装置。此档案实作gic功能的界面包含initmask产生软件中断中断结束取得资讯等。内容除了gic register操作外也包含了旋转锁。it8152.c提供ITE8152PCI Bridge的支援。目前该硬体已经停止生产。timer-sp.cARM双定时器模块SP804的界面.SP804提供两个32 / 64bit倒计数器并提供定时器中断。vic.c - irq-vic.c
提供向量中断控制器VIC的界面.VIC主要存在于armv6或以前的架构中提供优先级IRQ向量等功能但并不支持SMP。在armv7之后的架构中其渐渐被NVICCortex-M 与GIC皮质-R / A取代。ipipe-tsc.c - ipipe_tsc.cTime Stamp Counter的界面提供自复制起循循数的计算。ipipe / compat.c与I-pipe遗留接口相关。sched / clock.c取得cpu_clock解析度为nanosecond开机后从0开始上数。在新版3.18ipipe中此档案并无修改。以上是一个GIC的示意图。
HAL
档案位置在xenomai-head / ksrc / arch / arm / hal.cxenomai 2.6
硬件抽象层进程透过HAL呼叫ipipe的服务。这一层主要是包装ipipe与底层资讯让nucleus可以不用看到硬体资讯。
核/钴(Cobalt)
档案位置在xenomai-head / ksrc / nucleusxenomai 2.6; xenomai-head / kernel / cobaltxenomai 3
Xenomai的内核包含调度定时器同步线程锁等等一般该有的RTOS功能负责实时任务的执行。
调度(scheduler)
优先处理实时任务linux也被视为其中一个线程本身也有调度器但须等到没有实时任务时空闲状态才会执行linux thread。 就文件有五个关于sched.c中应该有四种不同的调度方式
sched-idle.c是专门处理idle state态给linux schedule使用
sched-rt.c给实时调度程序使用FIFO RR
sched-sporadic.cPOSIX SCHED_SPORADIC调度类。
sched-tp.c时间分区典型的IMA系统
sched.c应该是负责四个schedule方式的档案用户接口(skins)
档案位置在xenomai-head / ksrc / skinsxenomai 2.6
呼叫xenomai的接口有本地rtdm posix psos uitron vrtx vxworks等。
Xenomai与PREEMPT_RT的差异
Linux内核抢占模型组态实时程度↑延迟↓但吞吐量↓
- PREEMPT_NONE着重公平和吞吐量过程在执行系统呼叫时无法被抢占。- PREEMPT_VOLUNTARY桌面允许一个低优先权的进程把自己preempt掉即便该进程正在内核模式执行着一个系统呼叫
PREEMPT低延迟桌面- PREEMPT_RT着重决定论对即时系统而言作业系统的“可决定性”比吞吐量更为重要使用固定优先权的先发制人排程策略POSIX SCHED_FIFO与SCHED_RR。PREEMPT_RT机制
可抢占的关键部分
可抢占的中断处理程序
可抢占的“中断禁用”代码序列
内核中的自旋锁和信号量的优先级继承
延期经营
延迟减少措施在“可调度/线程”上下文中执行所有活动包括IRQIRQ处理程序移到线程中执行。优先级继承是让握有自旋锁或信号量的进程可以暂时的提高优先权让他可以尽快做完关键部分释放自旋锁或信号量高优先的流程才有办法继续执行。PREEMPT_RT与xenomai的差异
RT_PREEMPT是基于linux架构去改进让更多地方能preempt达到real-time的能力Xenomai则是改变整个系统架构新增一个调度员与IRQ管理的机制让处理实时任务流程简化到只剩ipipe- scheduler就能执行不会因linux庞大的架构影响到实时任务的处理时间。RTDM
The Real-Time Driver Model (RTDM) provides a unified interface to both users and developers of real-time device drivers. Specifically, it addresses the constraints of mixed RT/non-RT systems like Xenomai. RTDM conforms to POSIX semantics (IEEE Std 1003.1) where available and applicable. 实时驱动程序模型RTDM为实时设备驱动程序的用户和开发人员提供了统一的接口。 具体来说它解决了混合实时/非实时系统如Xenomai的局限性。 RTDM在可用且适用的情况下符合POSIX语义IEEE Std 1003.1。
1.7 Xenomai资源
task latency的产生原理 GIC原理 GIC通用中断控制器GIC是arm用来集中分配interrupt至cpu的装置。它主要分配给分配器和cpu接口。
distributor负责分配中断纪录执行状态并提供寄存器以决定每个中断的启用优先级目标处理器。每个中断会有固定的中断ID以供接收的cpu辨认。cpu interface向cpu传送中断请求并提供分配器接收确认中断完成中断等信息;它也提供决定优先级掩码抢占策略的寄存器。
当启动时cpu接口会收到优先最高的待处理中断并决定它是否有足够的优先级此cpu执行参考掩码运行中断抢占若是则signal cpu.cpu读取接口的寄存器GICC_HPPIR 以接收中断此接取会得到中断ID当接收后分配会改变状态由pending- active和pending;完成之后cpu写入寄存器以示意中断已经完成。 中断类型
专用外设中断PPIID16-31。每个CPU各自独立的硬体中断。共享外设中断SPIID32~1019。外部硬体中断。软件生成的中断SGIID0~15。软体中断由一个cpu发出可指定至一个或多个cpucpu以写入GICD_SGIR的方式产生SGI其中PPI与SGI是NN模型每个cpu的中断状态各自独立; SPI是1-N模型一旦其中一个目标CPU接受中断即视为已处理。
如何选择xenomai特性
对于严格的实时要求您应该考虑为目标SoC架构和Linux内核版本提供硬实时支持。
可在此处查看双内核配置中Xenomai的硬件支持。该技术基于内核补丁该补丁引入了一种机制用于将所有关键事件转移到与内核Linux内核耦合的双内核扩展。这个过时的文档详细描述了这种称为中断管道又称I-Pipe的机制 。可以在此站点获取可用于各种内核版本的所有I-pipe修补程序 。对于单个内核配置此处提供了支持完整抢占功能也称为PREEMPT-RT 的目标体系结构列表 。实时操作涉及多少CPU核心
在双内核配置中Xenomai协同内核在不超过四个CPU内核的同时处理实时活动时通常会受益于其更简单的锁定方案。
除了运行实时活动的四个CPU核心外单个内核配置的SMP可扩展性将更好。关键问题在于实际运行实时线程的CPU内核数量以及从实时源接收中断而不是目标硬件上在线核心的总数。由于Cobalt协同内核在处理实时活动时不会与常规Linux内核共享任何锁定因此在不超过四个可用内核上固定此类活动的16路服务器仍然可以在Cobalt中提供良好的性能。基于双内核配置。Xenomai双核方案(Cobalt)的考虑因素
将Cobalt协同内核移植到新架构非常简单。
它与主线Linux内核的开发周期分离从而允许更自由地选择所需或所需的内核版本。
它可以简化最坏情况分析并使结果在托管它的主线Linux内核的更新周期内保持有效。
它允许微调非实时部分的吞吐量而不会对实时工作产生负面影响。
它不需要对常规Linux系统进行任何调整以保证实时作业的短暂和有限延迟。Xenomai单核方案(Mercury)的考虑因素
库存内核驱动程序可由实时应用程序重用无需更改前提是它们不会因不幸的实现而产生延迟问题。另一方面驱动程序需要专门用于在双内核配置上运行即通过内核RTDM接口。
编程模型可能比双内核配置更简单因为内核被认为是全局实施实时行为。这就是说谨慎的应用程序设计和实现必须是一个通用规则而不管底层的实时技术如何因为并非所有可用的服务都适合实时使用。
所有用于监控系统操作的标准实用程序都可以报告开箱即用的实时活动。另一方面双核系统必须专门为此目的调整这些工具。选择Linux内核版本
一个移植到目标SoC或平台的Linux内核。如果可能的话更喜欢主线内核版本而非源于供应商的版本。
在其他问题中通过单一PREEMPT_RT或双内核I-pipe配置运行硬实时应用程序所需的内核补丁通常基于主线内核。对于双内核配置适合目标内核的 I-pipe补丁。
如果你没有找到任何完全匹配但又感觉幸运的补丁你可以尝试应用针对内核发布的补丁只是因为它的次级版本号不同例如从3.10.22到3.10.20。但是即使它干净利落也需要进行一些额外的测试从电子邮件讨论列表中获取更多信息 可能会有所帮助。对于具有硬实时功能的单内核配置匹配目标内核的PREEMPT-RT补丁。xenomai资源
Xenomai将使各种实时操作系统API可供基于Linux的平台使用。 当目标Linux内核不能满足响应时间限制的要求时Xenomai还可以对其进行补充以基于原始的双内核方法提供严格的实时保证。
Git hosting: https://xenomai.org/gitlab/xenomai
Clone: git://git.xenomai.org/xenomai.git
Maintenance branch: stable/v3.0.x
Development branch: masterI-pipe资源
Cobalt实时内核依赖于主线Linux内核的补丁该内核引入了一个单独的高优先级执行阶段可在IRQ收到后立即运行带外中断处理程序该处理程序不能被正常的内核工作延迟。
ARM: https://xenomai.org/gitlab/ipipe-arm
ARM64: https://xenomai.org/gitlab/ipipe-arm64
PPC32: https://xenomai.org/gitlab/ipipe-ppc32
x86: https://xenomai.org/gitlab/ipipe-x862. 安装
2.1 在覆盆子(pi)的Xenomai 3
取得xenomai 3.0-rcrpi-linux 3.18.yipipe 3.18.12 arm patchtoolchain
git clone -b rpi-3.18.y git://github.com/raspberrypi/linux.git rpi-linux
git clone -b v3.0-rc4 git://git.xenomai.org/xenomai-3.git xenomai-3
wget http://download.gna.org/adeos/patches/v3.x/arm/ipipe-core-3.18.12-arm-1.patch
git clone https://github.com/raspberrypi/tools.git --depth1checkout rpi-linux至3.18.12
git checkout c963de6d8caec6278c0dde76831f9fdab5bace52
git checkout -b 3.18.12由此处取得rpi post patch补丁。
上ipipe补丁
cd rpi-linux
../xenomai-3/scripts/prepare-kernel.sh --archarm --ipipe你的patch位置/ipipe-core-3.18.12-arm-1.patch --linux.ipipe post patch注pre patch为解决ipipe patch冲突之用此处无冲突故不需要
patch -Np1 你的patch位置/3.18.12-xenomai3-temp.patch配置内核使用rpi提供的默认值
export CCPI($working_dir)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
mkdir build
make mrproper
make ARCHarm Obuild CROSS_COMPILE$CCPI bcmrpi_defconfig
make ARCHarm Obuild CROSS_COMPILE$CCPI menuconfig若补丁正确会在设定表里看到xenomai相关选项。
使用manuconfig或编辑build / .config找到CONFIG_CPU_FREQCONFIG_CPU_IDLECONFIG_KGDBONFIG_CONTEXT_TRACKING_FORCE若有的话设为n。
编译内核
make -j 5 ARCHarm Obuild CROSS_COMPILE$CCPI安装内核模块
make ARCHarm Obuild INSTALL_MOD_PATHdist modules_install安装头
make ARCHarm Obuild INSTALL_HDR_PATHdist headers_installxenomai
cd ../xenomai-3
mkdir dist
export PATH/home/erickitten/workspace/xenomai/pi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/:$PATH设定引导
./scripts/bootstrap --with-corecobalt –enable-debugpartial配置
./configure CFLAGS-mcpuarm1176jzf-s -mfpuvfp -mfloat-abihard LDFLAGS-mcpuarm1176jzf-s -mfpuvfp -mfloat-abihard --hostarm-linux-gnueabihf --with-corecobalt安装
make DESTDIRpwd/dist install复制内核
将linux-rpi / build / arch / arm / boot / Image复制到SD卡的/ boot分区并改名成kernel.img。或使用config.txt以kernel 指定名称。移动模块/补丁权限问题需使用sudo
cd ..
sudo cp -r rpi-linux/build/dist/lib/modules $(sdcard)/lib
sudo cp -r xenomai-3/dist/usr/xenomai $(sdcard)/usr2.2 观察与分析 piraspberrypi:$ cat /proc/xenomai/statCPU PID MSW CSW PF STAT %CPU NAME0 0 0 206 0 00500080 100.0 ROOT0 0 0 2688553 0 00000000 0.0 IRQ3: [timer]CPU目前这个踏是使用哪个CPU在运行而rpi是单核心CPU故显示皆为0MSW模式切换此值应仅随预期与Linux服务交互的线程而增加。当进程从主模式转成二级模式或是二级模式转成主模式时将会纪录一次的转换。cyclictest的RT任务因为会执行到memset所以会从xenomai schedule跳到linux scheduleMSW 1而执行完memset后将在跳回xenomai schedule故再1CSW上下文切换次数或特定CPU的IRQ命中PF页面错误的数量一旦mlockall生效应该停止增加STAT描述线程内部状态的位域。位值在include/nucleus/thread.h中定义参见状态和模式位。来自/proc/xenomai/sched的STAT字段给出了这些位的最重要子集的每字母1位字符符号转换。CPU自上次检索统计信息以来线程或IRQ处理程序的CPU份额。NAME线程的名称或IRQ号和注册的驱动程序。例如可以使用非可移植POSIX-API函数pthread_set_name_np进行设置。请参阅相关RTOS皮肤的API文档。 piraspberrypi:$ sudo /usr/xenomai/bin/cyclictest /dev/null 2/dev/null [1] 2253piraspberrypi:$ ps aux | grep -i cyroot 2253 0.5 0.3 4580 1464 ? S 03:34 0:00 sudo /usr/xenomai/bin/cyclictestroot 2254 2.7 0.4 2340 2132 ? SLl 03:34 0:00 /usr/xenomai/bin/cyclictestpi 2259 0.0 0.1 3540 820 ttyAMA0 S 03:34 0:00 grep --colorauto -i cypiraspberrypi:$ cat /proc/xenomai/statCPU PID MSW CSW PF STAT %CPU NAME0 0 0 255 0 00500080 100.0 ROOT0 2254 1 1 0 00b00380 0.0 cyclictest0 2256 2 48 0 00300184 0.0 cyclictest0 0 0 2913946 0 00000000 0.0 IRQ3: [timer]piraspberrypi:~$ watch -n 1 cat /proc/xenomai/statEvery 1.0s: cat /proc/xenomai/stat Wed Jan 8 03:38:43 2014CPU PID MSW CSW PF STAT %CPU NAME0 0 0 442 0 00500080 99.9 ROOT0 2254 1 1 0 00b00380 0.0 cyclictest0 2256 2 235 0 00300184 0.0 cyclictest0 0 0 2953543 0 00000000 0.1 IRQ3: [timer]在这边可以看到cyclictest有两个pid因为/usr/xenomai/bin/cyclictest它会先创一个线程并让这个线程跑nanosleep所以会有两个进程。 接着看向CSWpid 2254的cyclictest他的CSW只有1.pid 2256的却有235这是因为2256是一个xenomai实时任务而2254是一个linux的进程所以2256会优先执行直到实时任务都做完才会换低优先级的linux domain process取得CPU因此2254的CSW值才会是1而没有增加。 piraspberrypi:~$ sudo kill 2254piraspberrypi:~$ ps aux | grep -i cypi 2324 0.0 0.1 3540 820 ttyAMA0 R 03:46 0:00 grep --colorauto -i cy[1] Done sudo /usr/xenomai/bin/cyclictest /dev/null 2 /dev/nullpiraspberrypi:~$ sudo /usr/xenomai/bin/cyclictest -p FIFO /dev/null 2/dev/null 在我们了解MSW时尝试了在-p后面加上了文字如FIFORR …
发现MSV的值开始往上增加也发现一开始对于MSW的定义理解错误,trace后才了解这是xenomai在-p的指令上是使用atoi将输入的数字转为int但并没有进行侦错才导致段故障而需跳转到linux domain进行除错。 CPU PID MSW CSW PF STAT %CPU NAME0 0 0 75266 0 00500080 99.9 ROOT0 2978 1 1 0 00b00380 0.0 cyclictest0 2980 2 26846 0 00300184 0.0 cyclictest0 7559 1 1 0 00b00380 0.0 cyclictest0 7561 66 130 0 00b00184 0.0 cyclictest0 0 0 11266931 0 00000000 0.1 IRQ3: [timer]2.3 Performance性能表现
Linux实时性对比
原生Linux cyclictest -p 90 - m -c 0 -i 200 -n -h 100 -q -l 1000 logPREEMPT_RT-patchch Linux cyclictest -p 90 - m -c 0 -i 200 -n -h 100 -q -l 1000 logXenomaiLinux /usr/xenomai/bin/cyclictest -p 90 - m -c 0 -i 200 -n -v 100 -q -l 100 loguser/kernel/timer IRQ (R-pi) Xenomai 3.0 Xenomai 2.6
user/kernel/timer IRQ (Beaglebone) Xenomai 3.0 Xenomai 2.6
2.4 Cyclictest原理
概念设定一个时间间隔 - 取得现在时间 - 让处理睡一个间隔 - 处理醒来后再取一次时间 - 比对两次取得的时间差与设定的间隔差距
伪代码 clock_gettime((now))next now par-intervalwhile (!shutdown) {clock_nanosleep((next))clock_gettime((now))diff calcdiff(now, next)# update stat- min, max, total latency, cycles# update the histogram datanext interval}造成时间差的原因:
计时精准度
IRQ延迟
IRQ处理程序持续时间
调度程序延迟
调度程序持续时间Cyclictest实作流程:
1.cyclictest建立一个timerthread它一个实时的线程2.timerthread会重复的执行取第一次时间nanosleepinterval取第二次时间比对两次时间差与interval的差异3.最后将结果输出在终端
Clock_nanosleep的计时器
clock_nanosleep使用的计时器是高分辨率计时器HRT让睡眠时间可以更精确达到nanosecond的精准度但还是要看硬体能提供的精准度
因为能在更准确得时间让过程醒来并取的nanoscecond单位的时间所以可以计算到由systick无法计算到的持续时间延迟Clock_nanosleep实作流程:
1.使用spinlockxnlock_get_irqsave令CPU不接受中断2.使用xnpod_suspend_thread改变目前thread的状态3.使用xntimer_get_timeout_stopped取得勾选4.使用ticks2ts转换时间单位 int clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp){xnthread_t *cur;spl_t s;int err 0;if (xnpod_unblockable_p())return EPERM;if (clock_id ! CLOCK_MONOTONIC clock_id ! CLOCK_REALTIME)return ENOTSUP;if ((unsigned long)rqtp-tv_nsec ONE_BILLION)return EINVAL;if (flags ~TIMER_ABSTIME)return EINVAL;cur xnpod_current_thread();xnlock_get_irqsave(nklock, s); thread_cancellation_point(cur);xnpod_suspend_thread(cur, XNDELAY, ts2ticks_ceil(rqtp) 1,clock_flag(flags, clock_id), NULL);thread_cancellation_point(cur);if (xnthread_test_info(cur, XNBREAK)) {if (flags 0 rmtp) {xnsticks_t rem;rem xntimer_get_timeout_stopped(cur-rtimer);xnlock_put_irqrestore(nklock, s); ticks2ts(rmtp, rem 1 ? rem : 0); } elsexnlock_put_irqrestore(nklock, s); return EINTR;} xnlock_put_irqrestore(nklock, s);return err; }Cyclictest 测试用例POSIX间隔计时器间隔500微秒。100000次循环100负载。
命令行
cyclictest -t1 -p 80 -i 500 -l 100000使用PREEMPT LINUX
rootraspberrypi:/home/pi# sudo ./cyclictest -t1 -p 80 -i 500 -l 100000
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.00 0.01 0.05 1/61 2064
T: 0 ( 2063) P:80 I:500 C: 100000 Min: 27 Act: 49 Avg: 42 Max: 1060使用RT-PREEMPT
Linux raspberrypi 3.6.11 #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l GNU/Linux
Min: 22 Act: 31 Avg: 32 Max: 169使用Xenomai
Linux raspberrypi 3.8.13-core #1 Thu Feb 27 03:02:16 CST 2014 armv6l GNU/Linux
Min: 1 Act: 5 Avg: 6 Max: 41rootraspberrypi:/home/pi# /usr/xenomai/bin/cyclictest -t1 -p 80 -i 500 -l 10000
0.08 0.06 0.05 1/61 2060
T: 0 ( 2060) P:80 I: 500 C: 100000 Min: -4 Act: -2 Avg: 0 Max: 30TThread
P优先
I间隔
C执行周期数
Min最小延迟
Act此次延迟时间
Avg平均延迟
Max最大延迟最重要的是最大值为了确保实时要能知道最坏情况让开发者可以评估最差的情况可以在多少时间内可以做出回应。
比较Cycifictest于使用PREEMPT LINUXRT-PREEMPT以及Xenomai。使用R-pi模型B Xenoami 2.6.4
3. Xenomai移植
3.1 Installing the Cobalt core
xenomai目录结构
xenomai遵循分离源码模式将内核态的支持和用户态的库解耦。为此内核空间和用户空间组件分别位于kernel/和lib/子目录下面。其他的顶层文件夹例如scripts/、testsuite/、utils/提供在构建主机或运行时目标上使用的其他脚本和程序。
kernel/实现内核内支持代码的代码被视为Linux内核的内置扩展。 因此应该使用标准的Linux内核配置过程来定义Xenomai内核组件的各种设置。 Xenomai当前引入的所有内核代码都实现了Cobalt内核即双内核配置。 到目前为止Mercury内核在内核空间中不需要Xenomai特定的代码。lib/包含Xenomai框架导出到应用程序的各种用户空间库。 该树是与内核支持分开构建的。 构建库是为了支持选定的Cobalt或Mercury内核。
Cobalt内核的准备
Xenomai / cobalt提供了无缝集成到Linux的实时扩展内核因此第一步是将其构建为目标内核的一部分。 为此scripts / prepare-kernel.sh是一个shell脚本可以正确设置目标内核。 语法如下
$ scripts/prepare-kernel.sh [--linuxlinux-srctree]
[--ipipeipipe-patch] [--archtarget-arch]--linux指定目标内核源树的路径。 这样的内核树可以已经配置或没有配置无关紧要。该路径默认为$PWD。--ipipe指定要应用于内核树的中断管道即I-pipe补丁的路径。 可从项目的下载区域获得合适的补丁程序。 如果已经打上了I-pipe补丁则可以省略此参数否则脚本将建议一个合适的参数。 该脚本将检测内核树中是否已存在中断管道代码如果存在则跳过此操作。--arch告诉脚本有关目标体系结构的信息。 如果未指定则建议构建主机体系结构为合理的默认设置。
例如以下命令将准备位于/home/me/linux-3.10-ipipe的Linux树打上Xenomai补丁
$ cd xenomai-3
$ scripts/prepare-kernel.sh --linux/home/me/linux-3.10注意该脚本将从Xenomai源代码树中自己的位置推断Xenomai内核代码的位置。例如如果/home/me/xenomai-3/scripts/prepare-kernel.sh正在执行那么/home/me/xenomai-3/kernel/cobalt中可用的Xenomai内核代码将被修补到目标Linux内核中 。
配置和编译Cobalt内核
准备好之后即可照常配置目标内核。 所有Xenomai配置选项都可从“ Xenomai”顶级Kconfig菜单中获得。
故障排除指南中记录了几个重要的内核配置选项。
配置完成后可以照常编译内核。
如果您希望手头有几个不同的配置/构建则可以通过向每个make调用添加O … / build- 来重用相同的源。
为了交叉编译Linux内核请传递ARCH和make命令行上的CROSS_COMPILE变量。 见章节“构建Cobalt/arm内核”“构建Cobalt/powerpc内核”“构建Cobalt/Blackfin内核”“构建Cobalt/x86内核”实例。
Cobalt内核参数
Cobalt内核接受以下参数集这些参数应由引导加载程序在内核cmdline上传递。 NAME DESCRIPTION DEFAULT xenomai.allowed_group gid Enable non-root access to Xenomai services from user-space. gid is the ID of the Linux user group whose members should be allowed such access by the Cobalt core. None xenomai.sysheap_size kbytes Set the size of the memory heap used internally by the Cobalt core to allocate runtime objects. This value is expressed in kilo-bytes. 256 xenomai.state state Set the initial state of the Cobalt core at boot up, which may be enabled, stopped or disabled. See the documentation about the corectl(1) utility for a description of these states. enabled xenomai.clockfreq hz-freq Override the real-time clock frequency used in measuring time intervals with the given value. The most accurate value is normally determined by the Cobalt core automatically when initializing. It is strongly recommended not to use this option unless you really know what you are doing. This value is expressed in HZ. 0 (calibrated) xenomai.timerfreq hz-freq Override the real-time timer frequency used in programming timer shots with the given value. The most accurate value is normally determined by the Cobalt core automatically when initializing. It is strongly recommended not to use this option unless you really know what you are doing. This value is expressed in HZ. 0 (calibrated) xenomai.smi state x86-specific: Set the state of the SMI workaround. The possible values are disabled, detect and enabled. See the discussion about SMIs for a description of these states. detect xenomai.smi_mask source-mask x86-specific: Set of bits to mask in the SMI control register. 1 (global disable)
Building a Cobalt/x86 kernel (32/64bit)
约定
$linux_tree path to the target kernel sources
$xenomai_root path to the Xenomai sources对于32位和64位平台为x86构建Xenomai/Cobalt几乎是相同的。但是您应该注意无法在x86_64编译的内核上运行x86_32编译的Xenomai库反之亦然。
假设为x86_64系统通常应运行
$ cd $linux_tree
$ $xenomai_root/scripts/prepare-kernel.sh --archx86_64 \--ipipeipipe-core-X.Y.Z-x86-NN.patch
$ make xconfig/gconfig/menuconfig配置内核另请参阅此处的建议设置。
启用Xenomai选项然后
$ make bzImage modules假设为x86 32bit系统通常应运行
$ cd $linux_tree
$ $xenomai_root/scripts/prepare-kernel.sh --archi386 \--ipipeipipe-core-X.Y.Z-x86-NN.patch
$ make xconfig/gconfig/menuconfig配置内核另请参阅此处的建议设置。
启用Xenomai选项然后
$ make bzImage modulesBuilding Cobalt/arm kernel
使用名为arm-none-linux-gnueabi-gcc的代码源工具链并为CSB637板基于AT91RM9200进行编译典型的编译如下
$ cd $linux_tree
$ $xenomai_root/scripts/prepare-kernel.sh --archarm \--ipipeipipe-core-X.Y.Z-x86-NN.patch
$ mkdir -p $build_root/linux
$ make ARCHarm CROSS_COMPILEarm-none-linux-gnueabi- O$build_root/linux \csb637_defconfig
$ make ARCHarm CROSS_COMPILEarm-none-linux-gnueabi- O$build_root/linux \bzImage modulesBuilding Cobalt/arm64 kernel
将Linaro工具链与前缀aarch64-linux-gnu-和一起使用为树莓派3板cortex-a53进行编译交叉编译为如下
$ cd $linux_tree
$ $xenomai_root/scripts/prepare-kernel.sh --archarm64 \--ipipeipipe-core-X.Y.Z-arm64-NN.patch
$ mkdir -p $build_root/linux
$ make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- O$build_root/linux \defconfig
$ make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- O$build_root/linux \Image dtbs modules3.2 Installing the Mercury core
对于Mercury到目前为止除了主机Linux内核已提供的功能外您还不需要Xenomai特定的内核支持。 您的内核至少应提供高分辨率计时器支持CONFIG_HIGH_RES_TIMERS如果您的应用程序需要较短且有限的延迟则内核可能应完全抢占PREEMPT_RT。
也可以使用不具有实时支持的内核可能用于基本调试任务和/或运行对响应时间没有严格要求的应用程序。
因此与Cobalt不同没有其他准备和/或配置Mercury内核的步骤。
3.3 Installing the Xenomai libraries and tools
Prerequisites
Generic requirements (both cores) GCC must have support for legacy atomic builtins (__sync form). GCC必须支持旧式原子内建函数__sync形式。 GCC should have a (sane/working) support for TLS preferably, although this is not mandatory if building with --disable-tls. 尽管最好使用–disable-tls进行构建但GCC最好对TLS具有健全/正常运行的支持。 If you plan to enable the user-space registry support (i.e. --enable-registry), then CONFIG_FUSE_FS must be enabled in the target kernel running the real-time applications. In addition, the FUSE development libraries must be available from the toolchain. 如果计划启用用户空间 支持即–enable-registry则必须在运行实时应用程序的目标内核中启用CONFIG_FUSE_FS。 此外必须从工具链中获得FUSE开发库。 If you plan to build from the sources available from the Xenomai GIT tree (git.xenomai.org), the autoconf ( 2.62), automake and libtool packages must be available on your build system. This is not required when building from a source tree extracted from a release tarball. 如果计划从Xenomai GIT树git.xenomai.org的可用资源进行构建则autoconf 2.62automake和libtool软件包必须在构建系统上可用。 从从发行版tarball提取的源树进行构建时这不是必需的。
Cobalt-specific requirements The kernel version must be 3.10 or better. 内核版本必须为3.10或更高。 An interrupt pipeline (I-pipe) patch must be available for your target kernel. You can find the official patches issued by the Xenomai project there. Only patches from the ipipe-core series are appropriate, legacy patches from the adeos-ipipe series are not. 您的目标内核必须有中断管道I-pipe补丁。 您可以在此处找到Xenomai项目发布的官方补丁。仅适用ipipe-core系列的补丁传统adeos-ipipe系列的补丁不适用。 A timestamp counter (TSC) is required from running on a x86_32 hardware. Unlike with Xenomai 2.x, TSC-emulation using a PIT register is not available. 在x86_32硬件上运行需要时间戳计数器TSC。 与Xenomai 2.x不同使用PIT寄存器的TSC仿真不可用。
Mercury-specific requirement
There is no particular requirement for Mercury setups, although using a NPTL-based glibc or uClibc is recommended.尽管建议使用基于NPTL的glibc或uClibc但对Mercury设置没有特殊要求。
Configuring
如果构建从Xenomai GIT树git.xenomai.org获得的源则必须在Xenomai源树中生成配置脚本和Makefile。 推荐的方法是从源代码树的顶部运行附带的自动重新配置脚本
$ ./scripts/bootstrap如果从发行版tarball构建则可以从提取的源树中轻松获得一组自动配置生成的文件因此不需要重新配置。
运行时生成的configure脚本为Cobalt和Mercury内核准备构建库和程序。 内部可能需要的特定于内核的代码在构建时由编译过程自动透明地选择。
可以将下面列出的选项传递给此脚本。
通用的configuration脚本选项 NAME DESCRIPTION --withcore type Indicates which real-time core you want to build the support libraries for, namely cobalt or mercury. This option defaults to cobalt. --prefix dir Specifies the root installation path for libraries, include files, scripts and executables. Running $ make install installs these files to $DESTDIR/ . This directory defaults to /usr/xenomai. --enable-debug[partial] This switch controls the debug level. Three levels are available, with varying overhead: symbols enables debug symbols to be compiled in the libraries and executables, still turning on the optimizer (-O2). This option has no overhead, it is useful to get meaningful backtraces using gdb while running the application at nominal speed. partial includes symbols, and also turns on internal consistency checks within the Xenomai code (mostly present in the Copperplate layer). The CONFIG_XENO_DEBUG macro is defined, for both the Xenomai libraries and the applications getting their C compilation flags from the xeno-config script (i.e. xeno-config --cflags). The partial debug mode implicitly turns on --enable-assert. A measurable overhead is introduced by this level. This is the default level when --enable-debug is mentioned with no level specification. full includes partial settings, but the optimizer is disabled (-O0), and even more consistency checks may be performed. In addition to __XENO_DEBUG__, the macro CONFIG_XENO_DEBUG_FULL is defined. This level introduces the most overhead, which may triple the worst-case latency, or even more. Over the Mercury core, enabling partial or full debug modes also causes the standard malloc interface to be used internally instead of a fast real-time allocator (TLSF). This allows debugging memory-related issues with the help of Valgrind or other dynamic memory analysers. --disable-debug Fully turns off all consistency checks and assertions, turns on the optimizer and disables debug symbol generation. --enable-assert A number of debug assertion statements are present into the Xenomai libraries, checking the internal consistency of the runtime system dynamically (see man assert(3)). Passing --disable-assert to the configure script disables built-in assertions unconditionally. By default, assertions are enabled in partial or full debug modes, disabled otherwise. --enable-pshared Enable shared multi-processing. When enabled, this option allows multiple processes to share real-time objects (e.g. tasks, semaphores). --enable-registry[/registry-root-path] Xenomai APIs can export their internal state through a pseudo-filesystem, which files may be read to obtain information about the existing real-time objects, such as tasks, semaphores, message queues and so on. This feature is supported by FUSE, which must be available on the target system. Building the Xenomai libraries with the registry support requires the FUSE development libraries to available from the toolchain. In addition, CONFIG_FUSE_FS must be enabled in the target kernel. Xenomai API可以通过伪文件系统导出其内部状态可以读取该文件以获取有关现有实时对象例如任务信号量消息队列等的信息。 FUSE支持此功能该功能必须在目标系统上可用。 要使用注册表支持构建Xenomai库需要从工具链中使用FUSE开发库。 另外必须在目标内核中启用CONFIG_FUSE_FS。 When this option is enabled, the system creates a file hierachy at // under the registry root path, where you can access the internal state of the active real-time objects. The session label is obtained from the --session runtime switch. If no session name is specified, anon will be used. E.g. looking at the properties of a VxWorks task could be done as follows: 启用此选项后系统会在注册表根路径下的//中创建文件层次结构您可以在其中访问活动实时对象的内部状态。 session标签是从--session运行时开关获取的。 如果未指定session名称将使用anon。例如查看VxWorks任务的属性可以按照以下步骤进行 If not specified in the configuration switch, the registry root path will be /var/run/xenomai. $ cat /var/run/xenomai/root/anon12656/12656/vxworks/tasks/windTask
name windTask
errno 0
status ready
priority 70
lock_depth 0You may override the default root of the registry hierarchy either statically at build time by passing the desired root path to the --enable-registry configuration switch, or dynamically by using the --registry-root runtime option passed to the application. When running over Xenomai/cobalt, the /proc/xenomai interface is also available for inspecting the core system state. --enable-lores-clock Enables support for low resolution clocks. By default, libraries are built with no support for tick-based timing. If you need such support (e.g. for pSOS ™ or VxWorks ™ APIs), then you can turn it on using this option. The POSIX API does not support tick-based timing. Alchemy may use it optionally. --enable-clock-monotonic-raw The Xenomai libraries requires a monotonic clock to be available from the underlying POSIX interface. When CLOCK_MONOTONIC_RAW is available on your system, you may want to pass this switch, otherwise CLOCK_MONOTONIC will be used by default. The Cobalt core implements CLOCK_MONOTONIC_RAW, so this switch is turned on by default when building with --with-corecobalt. On the contrary, this option is turned off by default when building for the Mercury core, since we don’t know in advance whether this feature does exist on the target kernel. --enable-tls Xenomai can use GCC’s thread local storage extension (TLS) to speed up the retrieval of the per-thread information it uses internally. This switch enables TLS, use the converse --disable-tls to prevent this. Due to GCC bugs regarding this feature with some release,architecture combinations, whether TLS is turned on by default is a per-architecture decision. Currently, this feature is enabled for x86 and powerpc by default, other architectures will require --enable-tls to be passed to the configure script explicitly. Unless --enable-dlopen-libs is present, the initial-exec TLS model is selected. When TLS is disabled, POSIX’s thread-specific data management services are used internally (i.e. pthread_set/getspecific()). --enable-dlopen-libs This switch allows programs to load Xenomai-based libraries dynamically, using the dlopen(3) routine. Enabling dynamic loading introduces some overhead in TLS accesses when enabled (see --enable-tls), which might be noticeable depending on the architecture. To support dynamic loading when --enable-tls is turned on, the global-dynamic TLS model is automatically selected. Dynamic loading of Xenomai-based libraries is disabled by default. --enable-async-cancel Enables fully asynchronous cancellation of Xenomai threads created by the real-time APIs, making provision to protect the Xenomai implementation code accordingly. When disabled, Xenomai assumes that threads may exit due to cancellation requests only when they reach cancellation points (like system calls). Asynchronous cancellation is disabled by default. Fully asynchronous cancellation can easily lead to resource leakage, silent corruption, safety issues and all sorts of rampant bugs. The only reason to turn this feature on would be aimed at cancelling threads which run significantly long, syscall-less busy loops with no explicit exit condition, which should probably be revisited anyway. --enable-smp Turns on SMP support for Xenomai libraries. SMP support must be enabled in Xenomai libraries when the client applications are running over a SMP-capable kernel. --disable-sanity turns off the sanity checks performed at application startup by the Xenomai libraries. This option sets a default, which can later be overriden using the --[no-]sanity options passed to a Copperplate-based Xenomai application. Sanity checks are enabled by default when configuring. --enable-fortify Enables _FORTIFY_SOURCE when building the Xenomai code unless --enable-debugfull is also given on the command line, in which case --enable-fortify is silently ignored. --disable-valgrind-client Turns off the Valgrind client support, forcing CONFIG_XENO_VALGRIND_API off in the Xenomai configuration header. --enable-doc-build Causes the inline Xenomai documentation based on the Doxygen markup language to be produced as PDF and HTML documents. Additional documentation like manpages based on the Asciidoc markup language is produced too.
Cobalt-specific configuration options: NAME DESCRIPTION DEFAULT --enable-x86-vsyscall Use the x86/vsyscall interface for issuing syscalls. If disabled, the legacy 0x80 vector will be used. Turning on this option requires NPTL. enabled --enable-arm-tsc Enable ARM TSC emulation. kuser --enable-arm-quirks Enable quirks for specific ARM SOCs Currently sa1100 and xscale3 are supported. disabled
Mercury-specific configuration options: NAME DESCRIPTION DEFAULT --enable-condvar-workaround Enable workaround for broken priority inheritance with condition variables in glibc. This option adds some overhead to RTOS API emulators. disabled
Cross-compilation
为了交叉编译Xenomai库和程序您需要将--host和--build选项传递给configure脚本。
--host选项允许选择要为其构建库和程序的体系结构。--build选项允许选择运行编译工具的体系结构即运行配置脚本的系统。
由于交叉编译需要特定的工具因此此类工具通常以主机体系结构名称为前缀。例如用于PowerPC体系结构的编译器可以命名为powerpc-linux-gcc。
当传递--host powerpc-linux进行配置时它将自动使用powerpc-linux-作为所有编译工具名称的前缀并从该前缀中推断出主机体系结构名称。如果configure无法从交叉编译工具前缀中推断体系结构名称则必须至少在configure命令行上使用CC和LD变量手动传递所有编译工具的名称。
构建GNU交叉编译器的最简单方法可能涉及使用crosstool-ng可在此处获得。
如果要避免构建自己的交叉编译器则可能会发现更易于使用ELDK。它包括GNU交叉开发工具例如编译器binutilsgdb等以及目标系统上所需的许多预先构建的目标工具和库。有关更多详细信息请参见此处。
其他一些预先构建的工具链
Mentor Sourcery CodeBench Lite Edition可在此处获取Linaro工具链用于ARM体系结构可在此处获得。
Building the x86 libraries (32/64bit)
约定
$xenomai_root path to the Xenomai sources
$build_root path to a clean build directory
$staging_dir path to a directory that will hold the installed file temporarily before they are moved to their final location; when used in a cross-compilation setup, it is usually a NFS mount point from the target’s root directory to the local build host, as a consequence of which running make{nbsp}DESTDIR$staging_dir{nbsp}install on the host immediately updates the target system with the installed programs and libraries.Assuming that you want to build the Mercury libraries natively for a x86_64/SMP system, enabling shared multi-processing support. You would typically run:
$ mkdir $build_root cd $build_root
$ $xenomai_root/configure --with-coremercury --enable-smp --enable-pshared
$ make installConversely, cross-building the Cobalt libraries from x86_64 with the same feature set, for running on x86_32 could be:
$ mkdir $build_root cd $build_root
$ $xenomai_root/configure --with-corecobalt --enable-smp --enable-pshared \--hosti686-linux CFLAGS-m32 -O2 LDFLAGS-m32
$ make install安装构建树后即使用“ make install”应在安装根目录中填充可用于构建基于Xenomai的实时应用程序的库程序和头文件。 该目录路径默认为/usr/xenomai。
其余示例说明了如何针对各种体系结构交叉编译Xenomai。当然您必须首先为目标系统安装正确的交叉编译工具链。
Building the ARM libraries
Using codesourcery toolchain named arm-none-linux-gnueabi-gcc and compiling for a CSB637 board (AT91RM9200 based), a typical cross-compilation from a x86_32 desktop would look like:
$ mkdir $build_root/xenomai cd $build_root/xenomai
$ $xenomai_root/configure CFLAGS-marcharmv4t LDFLAGS-marcharmv4t \--buildi686-pc-linux-gnu --hostarm-none-linux-gnueabi- --with-corecobalt
$ make DESTDIR$staging_dir install与以前的版本不同Xenomai不再将任何特定于ARM架构的标志或FPU标志传递给gcc因此如上所示用户应使用CFLAGS和LDFLAGS变量传递它们其中AT91RM9200基于ARM920T内核实现了 armv4体系结构。 下表总结了CFLAGS和选项它们在以前的版本中自动传递现在需要明确传递以进行配置以支持受支持的SOC
SOCCFLAGSconfigure optionsat91rm9200-marcharmv4t -msoft-float-at91sam9x-marcharmv5 -msoft-float-imx1-marcharmv4t -msoft-float-imx21-marcharmv5 -msoft-float-imx31-marcharmv6 -mfpuvfp-imx51/imx53-marcharmv7-a -mfpuvfp3-imx6q-marcharmv7-a -mfpuvfp3–enable-smpixp4xx-marcharmv5 -msoft-float–enable-arm-tscixp4xxomap3-marcharmv7-a -mfpuvfp3-omap4-marcharmv7-a -mfpuvfp3–enable-smporion-marcharmv5 -mfpuvfp-pxa-marcharmv5 -msoft-float-pxa3xx-marcharmv5 -msoft-float–enable-arm-quirksxscale3s3c24xx-marcharmv4t -msoft-float-sa1100-marcharmv4t -msoft-float–enable-arm-quirkssa1100
如果您的工具链不支持目标体系结构则可以针对较旧的体系结构版本v6而不是v7或v4而不是v5进行构建唯一的限制是如果启用了SMP则该体系结构不应小于 v6。
Building the ARM64 libraries
ARM64 is only supported from the git repos on the next branch.
Using the Linaro toolchain with the prefix aarch64-linux-gnu- for the Raspberry Pi 3 board (cortex-a53), cross compililation from a x86_64 host would be as follows:
mkdir $build_root/xenomai cd $build_root/xenomai
../xenomai/configure CFLAGS-mtunecortex-a53 LDFLAGS-mtunecortex-a53 \
--buildi686-pc-linux-gnu --hostaarch64-linux-gnu --with-corecobalt \
--enable-smp CCaarch64-linux-gnu-gcc LDaarch64-linux-gnu-ld
$ make DESTDIR$staging_dir installPassing a value for the -mcpu flag will help generate optimized code for a specific cpu type but it’s not necessary.
Testing the installation
Booting the Cobalt kernel
In order to test the Xenomai installation over Cobalt, you should first try to boot the patched kernel. Check the kernel boot log for messages like these:
$ dmesg | grep -i xenomai
I-pipe: head domain Xenomai registered.
[Xenomai] Cobalt vX.Y.Z enabledIf the kernel fails booting, or the log messages indicates an error status instead, see the Troubleshooting guide.
Testing the real-time system (both cores)
First, run the latency test:
$ /usr/xenomai/bin/latencyThe latency test should display a message every second with minimum, maximum and average latency values. If this test displays an error message, hangs, or displays unexpected values, see the Troubleshooting guide.
If the latency test succeeds, you should try next to run the xeno-test test in order to assess the worst-case latency of your system. Try:
$ xeno-test --helpCalibrating the Cobalt core timer
The accuracy of the Cobalt timing services depends on proper calibration of its core timer. Sound factory-default calibration values are defined for each platform Xenomai supports, but it is recommended to calibrate the core timer specifically for the target system.
See the documentation about the autotune(1) utility.
3.3 Building and running Xenomai 3 applications
延迟测试在目标系统上按预期方式运行后就可以运行实时应用程序了。
您可能需要查看本文档以获取有关应用程序构建过程的详细信息。
另外您可以参考本文档以了解Xenomai 3应用程序可用的命令行选项。
Compiling a Xenomai 3 application
总结起来您应该使用xeno-config脚本来获取与Xenomai相关的正确编译和链接器标志以便为任何Cobalt或Mercury内核构建应用程序。
可在此URL上找到xeno-config脚本的完整用法。
下面是一个简单的Makefile片段用来构建使用VxWorks仿真API的单文件应用程序vxapp.c
XENO_CONFIG : /usr/xenomai/bin/xeno-config
CFLAGS : $(shell $(XENO_CONFIG) --vxworks --cflags)
LDFLAGS : $(shell $(XENO_CONFIG) --vxworks --ldflags)
CC : $(shell $(XENO_CONFIG) --cc)EXECUTABLE : vxappall: $(EXECUTABLE)%: %.c$(CC) -o $ $ $(CFLAGS) $(LDFLAGS)Compiling a RTDM-based module
构建常规内核模块/驱动程序的规则也适用于基于RTDM的驱动程序没有其他要求。 例如基于RTDM API由some.driver和bar.c这两个文件组成的用于构建some_driver.ko的Makefile为
obj-y some_driver.o
some_driver-y : foo.o bar.o应该从包含模块源的目录中在内核树之外构建此模块如下所示
$ make -C /path/to/kernel/tree M$PWD modules3.4 Running a Xenomai 3 application
对于Cobalt您将需要如本文档中所述将实时内核内置到目标Linux内核中。
对于Mercury到目前为止除了主机Linux内核已提供的功能外您还不需要Xenomai特定的内核支持。您的内核至少应提供高分辨率计时器支持CONFIG_HIGH_RES_TIMERS如果您的应用程序需要较短且有限的延迟则内核可能应完全抢占PREEMPT_RT。
任何基于Xenomai的应用程序都可以识别可能在命令行中传递的一组标准选项如本文档所述。
此外在Xenomai内核上运行的AlchemypSOS™和VxWorks™API可以定义要使用的时钟分辨率以纳秒为单位HZ 1000000000 / ns。即-{alchemy/psos/vxworks}-clock-resolution ns选项。
如果您的应用程序结合了多个API则可以传递多个时钟分辨率开关来设置它们。
默认值取决于所考虑的API。例如VxWorks™和pSOS™仿真器默认为毫秒时钟速率。默认情况下Alchemy API是无滴答的即--alchemy-clock-resolution 1。
指定大于1纳秒的分辨率要求Xenomai库提供低分辨率时钟支持请参阅–enable-lores-clock配置开关。
Valgrind support
目前仅在Mercury核心上可以使用通过Valgrind运行Xenomai应用程序。
当Valgrind API可用于应用程序过程时配置符号CONFIG_XENO_VALGRIND_API是在构建时定义的并且可以由应用程序代码测试是否存在。 请参阅此地址的工具文档。
Xenomai autoconf脚本将自动检测构建系统上的Valgrind核心标头并相应地定义此符号即/usr/include/valgrind/valgrind.h。
您可能需要在构建系统上安装Valgrind开发包以提供核心头文件。 例如这种软件包在Fedora上称为valgrind-devel。
3.5 Xenomai Application
除非另外说明否则该描述无异地适用于Cobalt和Mercury的构型。 读者可以假定应用程序总是引用与Xenomai库链接的任何可执行程序无论其目的如何。
此讨论专门涉及基于Xenomai库的构成应用程序的用户空间程序。 没有任何参考关于任何基于内核的上下文。
How to build an application
最重要的经验法则是始终分别从对xeno-config --cflags和xeno-config --ldflags的调用中检索编译和链接标志并提及应用程序使用的Xenomai API列表。 可在此URL上找到xeno-config脚本的完整用法。
从Makefile调用xeno-config:
CFLAGS : $(shell xeno-config --posix --cflags)
LDFLAGS : $(shell xeno-config --posix --ldflags)如果不使用xeno-config来获取Xenomai应用程序的正确构建标志将产生一个错误的可执行文件这根本行不通。
Standard Xenomai command line options
与Xenomai库链接的任何应用程序都会自动识别可以在命令行上传递的一组标准选项这些选项适用于任何基于Xenomai的程序。 您无需在应用程序代码中添加任何内容即可解释和执行这些选项开关。 例如--dump-config选项始终被应用程序识别转储用于构建与其链接的Xenomai库的设置
Xenomai/mercury v3.0-rc5 -- #e91216a (2015-05-12 17:58:01 0200)
CONFIG_MMU1
CONFIG_SMP1
CONFIG_XENO_ASYNC_CANCEL1
CONFIG_XENO_BUILD_ARGS -prefix/home/rpm/install/xenomai/mercury --enable-async-cancel --enable-lores-clock --enable-debugfull --enable-smp --enable-tls --with-coremercury --enable-registry --enable-pshared --enable-maintainer-mode
CONFIG_XENO_BUILD_STRINGx86_64-unknown-linux-gnu
CONFIG_XENO_COMPILERgcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)
CONFIG_XENO_DEBUG1
CONFIG_XENO_DEBUG_FULL1
CONFIG_XENO_DEFAULT_PERIOD100000
CONFIG_XENO_FORTIFY1
...
CONFIG_XENO_LIBS_DLOPEN is OFF
CONFIG_XENO_LORES_CLOCK_DISABLED is OFF
CONFIG_XENO_RAW_CLOCK_ENABLED is OFF
CONFIG_XENO_TLSF is OFF
CONFIG_XENO_WORKAROUND_CONDVAR_PI is OFF标准的选项列表 NAME DESCRIPTION --registry-root path Tells Xenomai to root the object registry at the given path, instead of the default root (see the --enable-registry switch from the configuration options). --session label Name of the session the new process will be part of (or create if not present). If --enable-pshared was given when configuring the Xenomai libraries, this label allows multiple processes giving the same label at startup to share objects created by members of the same session. All shared objects are allocated from a global heap backed by the main memory pool (see --mem-pool-size).--shared-registry Exports the registry of the process to other users. If access is possible, also depends on permissions of the registry path. By default, the registry is only accessible for the user that started the Xenomai process. --no-registry This switch disables registry support at runtime. No real-time objects will be exported to the registry, despite the registry code was compiled in. --mem-pool-size size[K|M|G] The size the main memory pool backing the session’s heap, which can be suffixed by a K(ilobyte), M(egabyte) or G(igabyte) binary multiplier. Most of the dynamic allocation requests issued from the Xenomai libraries are served from this pool. In absence of suffix, the value is normally interpreted as a count of bytes, except if lower than 65536, see below. 支持会话堆的主内存池的大小可以以KilobyteMegabyte或Gigabyte二进制乘数作为后缀。 Xenomai库发出的大多数动态分配请求都从该池中获得。 在没有后缀的情况下该值通常解释为字节数除非低于65536请参见下文。 If the value is lower than 65536 with no suffix, it is
interpreted as a count of kilobytes for backward compatibility
purpose with the former syntax. This work around may disappear
anytime when transitioning to Xenomai 3.0 final, so make sure
to fix any launch script(s) accordingly. Typically, suffixing
the current value with a K multiplier would address the issue.The shared heap is living in the /tmpfs filesystem, and therefore consumes RAM space. --cpu-affinity cpu[,cpu]… The set of CPUs available for running Xenomai threads created by the application, in absence of explicit pinning of such threads to a particular CPU when they are spawned. Defaults to any online CPU. The argument is a list of valid (i.e. online) CPU numbers separated by commas. This option may appear several times on the command line, cumulating the settings. --main-prio priority Cobalt only. When xenomai_init() is called for bootstrapping the real-time services for the current process, the calling context is automatically turned into a Xenomai thread, managed by the Cobalt kernel. Normally, this call runs over the main() routine, hence the parameter name. By default, the current scheduling policy and priority are kept during the transition. This parameter allows to force new scheduling parameters for the thread invoking xenomai_init() when it enters the Xenomai realm, according to the following rules: if is zero, the calling thread will be assigned the SCHED_OTHER policy. if is greater than zero, the calling thread will be assigned the SCHED_FIFO policy, and the given priority level. if is negative, the scheduling parameters of the calling context will be kept unchanged (default case). 仅Cobalt。 当调用xenomai_init()引导当前进程的实时服务时 调用上下文将自动转换为由Cobalt内核管理的Xenomai线程。 通常此调用在main()例程上运行因此在参数名称上运行。 默认情况下当前的调度策略和优先级在过渡期间保留。 根据以下规则此参数允许为进入xenomai领域的xenomai_init()线程强制新的调度参数 如果为零则将为调用线程分配SCHED_OTHER策略。 如果大于零则将为调用线程分配SCHED_FIFO策略和给定的优先级。 如果为负则调用上下文的调度参数将保持不变默认情况。 --print-buffer-size num-bytes Cobalt only. When symbol wrapping is in effect (default case for applications based on Cobalt’s POSIX API), Xenomai interposes on common output calls from the stdio support such as printf(3) fprintf(3) and puts(3), so that no delay or loss of real-time guarantee is incurred by the caller. The underlying mechanism is based on relay buffers forming an output ring, filled in by real-time threads locklessly, which are periodically flushed by a regular (non real-time) Linux helper thread to the process’s destination stream (stdout, stderr or any other particular stream). This parameter allows to set the size of a typical relay buffer. By default, a relay buffer is 16k large. 仅钴。 当符号换行有效时基于Cobalt的POSIX API的应用程序的默认情况Xenomai插入来自stdio支持的常见输出调用例如printf3fprintf3和puts3这样就不会造成延迟或丢失 呼叫者需要支付实时保证金。 底层机制基于形成输出环的中继缓冲区这些缓冲区由实时线程无锁地填充并由常规非实时Linux帮助程序线程定期将其刷新到进程的目标流stdoutstderr或任何其他对象 特定的流。 此参数允许设置典型中继缓冲区的大小。 默认情况下中继缓冲区为16k。 --print-buffer-count num-buffers Cobalt only. Use this parameter to set the total number of relay buffers (see --print-buffer-size). By default, 4 relay buffers are present in the output ring. --print-sync-delay ms Use this parameter to set the longest delay (in milliseconds) before the output pending into the relay buffers is synchronized (see --print-buffer-size). By default, the output ring is flushed each 100 milliseconds by the helper thread. --[no-]sanity Turn on[/off] sanity checks performed by the Xenomai libraries, mostly during the application startup. Defaults to the value set by the --enable-sanity switch when configuring (which is enabled by default). For instance, running Xenomai libraries built for a uni-processor system over a SMP kernel is detected by such checks. --verbose[level] Set verbosity to the desired level, or 1 if unspecified. The level argument may be interpreted differently depending on the application, however --verbose0 must mean fully quiet. The interpretation of higher levels is application-specific. Defaults to 1. --silent --quiet Same as --verbose0. --trace[level] Set tracing to the desired level, or 1 if unspecified. The level argument may be interpreted differently depending on the application, however --trace0 must disable tracing. Level 1 allows tracing the Xenomai library bootstrap code. The interpretation of higher levels is application-specific. Defaults to 0. --version Get the application and Xenomai version stamps. The program immediately exits with a success code afterwards. --dump-config Dump the settings used for building the Xenomai libraries the application is linked against. --no-mlock Mercury only. This switch disables the implicit mlock() call at init, normally used for locking the calling process’s virtual address space into RAM, in order to avoid the extra latency induced by virtual memory paging. This option does not apply to the Cobalt core, which requires
memory locking from all clients unconditionally.--help Display the help strings.
Accessing the tunables Tunables可调项是在设置系统例如主内存堆的大小或控制其运行时行为例如详细程度时用作配置值的变量。 configuration tunables其中的一些可调参数可能会由应用程序的早期代码更新直到系统开始初始化核心数据结构并启动服务然后从该点开始变为只读状态。 这些称为配置可调参数。 runtime tunables在应用程序生命周期的任何时间点其他可调参数都可以自由更改。 这些称为运行时可调参数。
有一个简单的API用于读取和更新任何可调参数的当前值该参数由{get/set}_config_tunable(name)和{get/set}_runtime_tunable(name)C宏组成。
当--enable-assert对于Xenomai库有效时set_config_tunable()在配置调整阶段之后通过在尝试更改此只读可调参数会引发异常。
每个可调参数都有一个任意的名称它不一定反映实际存储其值的变量的名称。 例如可以定义可调foo最终在后台处理int bar C变量甚至是一组相关变量。
通常更新和读取verbose_level可调参数该参数用来保留应用程序的当前详细程度-如下所示
#include stdio.h
#include xenomai/tunables.hset_runtime_tunable(verbosity_level, 1);
printf(verbosity_level%d\n, get_runtime_tunable(verbosity_level));当配置可调参数与更新相同变量的命令行更新相同的变量命令行优先于set_config_tunable()调用。
Xenomai库定义了以下配置可调参数(configuration tunables):
NAMEDESCRIPTIONDEFAULTcpu_affinitysame as --cpu-affinity optionany online CPUno_mlocksame as --no-mlock optionoffno_sanitysame as --no-sanity option!CONFIG_XENO_SANITYno_registrysame as --no-registry optionoff (i.e. enabled)mem_pool_sizesame as --mem-pool-size option1Mbsession_labelsame as --session optionnone (i.e. anonymous)registry_rootsame as --registry-root optionCONFIG_XENO_REGISTRY_ROOTshared_registrysame as --shared-registry optionoff (i.e. private)
Xenomai库定义了以下运行时可调参数(runtime tunables):
NAMEDESCRIPTIONDEFAULTverbosity_levelsame as --verbose option1trace_levelsame as --trace option0
您可以使用define_{config/runtime}_tunable(name)和read_{config/runtime}_tunable(name)C宏添加自己的可调参数。
define_tunable语法提供了用于更新与可调名称匹配的C值的帮助程序代码。 相反read_tunable语法提供了用于返回与可调名称匹配的C值的帮助程序代码。
应用程序代码应使用{get/set}_config_tunable(name)或{get/set}_runtime_tunable(name)来访问新的可调参数具体取决于其范围。
定义和使用简单的可调参数:
/* Out of line definition. */code.c:int foo_runtime_variable;define_runtime_tunable(foo, int, val)
{/** The code to update the internal variable upon a call to* set_runtime_tunable(foo).*/foo_runtime_variable val;
}read_runtime_tunable(foo, int)
{/** The code to return the current tunable value upon a* call to get_runtime_tunable(foo).*/return foo_runtime_variable;
}header.h:/* Declaration of the manipulation helpers */define_runtime_tunable(foo, int, val);
read_runtime_tunable(foo, int);/* Conversely, we could be using an inline definition */header.h:extern int foo_runtime_variable;static inline define_runtime_tunable(foo, int, val)
{foo_runtime_variable val;
}static inline read_runtime_tunable(foo, int)
{return foo_runtime_variable;
}/* Accessing the new tunable, inverting the value. */int setting get_runtime_tunable(foo);
set_runtime_tunable(foo, !setting);在考虑将它们用于初始化应用程序之前为某些配置可调参数提供自己的出厂默认值可能会很方便。
为了使这种提早进行调整您需要在Xenomai引导程序代码运行的调整处理程序链中插入自己的处理程序然后再开始实际的初始化过程。 可以使用Xenomai设置描述符完成此操作如下所示
#include xenomai/init.h
#include xenomai/tunables.hstatic int foo_tune(void)
{/** We need more than 1MB which is Xenomais default, make* it 16MB before the Xenomai core starts initializing* the whole thing. --mem-pool-sizesize may override* this value.*/set_config_tunable(mem_pool_size, 16MB);/** Also turn verbosity off by default. --verboselevel on the* command line may switch this to verbose mode.*/set_runtime_tunable(verbosity_level, 0);return 0; /* Success, otherwise -errno */
}/** CAUTION: we assume that all omitted handlers are zeroed* due to the static storage class. Make sure to initialize them* explicitly to NULL if the descriptor belongs to the .data* section instead.*/
static struct setup_descriptor foo_setup {.name foo,.tune foo_tune,
};/* Register the setup descriptor. */
user_setup_call(foo_setup);Application entry (C/C)
从用户代码的角度来看每个应用程序都照常在main()例程中启动。
一些用于构建应用程序的链接标志会影响其初始化顺序。 通过调用xeno-config --ldflags检索此类标志并传递应用程序依赖的Xenomai API列表例如xeno-config --posix --alchemy --ldflags。
Xenomai库可以妥善处理此类序列以适当地引导其服务即自动引导automatic bootstrap或将此类职责留给应用程序代码即手动引导manual bootstrap。
Automatic bootstrap
如果使用自动引导程序模式则应用程序在main()函数中接收命令行中非标准xenomai选项的其他选项。 在这种模式下输入main()后所有Xenomai服务都将立即可用。
这是大多数应用程序应使用的默认行为。
Manual bootstrap
在手动引导模式下应用程序将接收未更改的原始参数向量而Xenomai服务未初始化。如果需要在Xenomai服务启动之前进行一些自己的早期初始化则应使用此模式。
通过链接从xeno-config --ldflags --no-auto-init接收到的标志来启用手动引导模式。
在这种模式下应用程序代码必须在初始化步骤中的某个时候调用xenomai_init(argcargv)以引导该进程的Xenomai服务。此函数处理所有标准Xenomai选项然后更新参数以指向从Xenomai选项中删除的原始向量的副本。
之后应用程序代码可以从命令行收集和处理未处理的选项并且可以不受限制地使用Xenomai服务。
Dealing with C static constructors
初始化顺序保证了在主要可执行文件中实例化的对象的C构造函数具有默认优先级将在Xenomai服务以自动模式引导后运行。这意味着来自主要可执行文件的静态对象的类构造函数可以调用Xenomai服务。
由于在手动引导方式下调用xenomai_init()之前Xenomai服务不可用因此在这种情况下直到调用该例程并成功返回之前这种保证不存在。
如通过各个软件层进行的初始化过程所述由共享库实例化的静态对象的C构造函数将无法访问Xenomai服务因为Xenomai引导程序代码稍后运行。
如果您具有非默认的静态构造函数优先级或在可执行文件所依赖的共享库中实例化的静态对象则可能需要提供自己的早期引导程序代码以防构造函数需要调用Xenomai服务。在这些C构造函数调用Xenomai服务之前此代码最终应调用xenomai_init()引导Xenomai服务。
Handling application-defined arguments
您可能需要提供自己的命令行选项以供应用程序代码解释。
如果使用自动引导程序模式则应用程序在main()函数中接收调用时传递的命令行选项集该命令行开关是从Xenomai标准选项中删除的。
使用手动引导程序应用程序将接收在命令行上传递的原始参数向量。然后调用xenomai_init(argcargv)进程会从向量中删除所有标准Xenomai选项然后再返回到调用方。
在这两种情况下可以照常使用getopt(3)解析器检索参数向量中存在的特定于应用程序的选项。
解析特定于应用程序的参数
#include getopt.h
#include stdio.h
#include xenomai/init.hint foo_mode 1; /* Default */static const struct option options[] {{
#define foo_mode1_option 0.name foo1,.flag foo,.val 1,},{
#define foo_mode2_option 1.name foo2,.flag foo,.val 2,},{/* sentinel */}
};int main(int argc, char *const *argv)
{int lindex, ret, opt;#ifdef MANUAL_BOOTSTRAP/* xeno-config --no-auto-init --ldflags was given. */ret xenomai_init(argc, argc);
#endiffor (;;) {lindex -1;opt getopt_long_only(argc, argv, , options, lindex);if (opt EOF)break;switch (lindex) {case foo_mode1_option:case foo_mode2_option:break;default:usage();return 1;}}...
}Under the hood
Xenomai特定的应用程序初始化过程按如下所示引导软件层 app-init-layers
lib/boilerplate/init/bootstrap.c实现了bootstrap处理程序该处理程序作为目标文件粘贴到应用程序的主要可执行文件中因此可以确保在应用程序依赖的任何共享库构造函数之后运行而无论库构造函数如何优先事项。
在自动引导程序模式下xenomai_main()例程插入实际的main()入口点以将经过处理的自变量矢量从Xenomai标准选项中删除传递给它。 此技巧基于链接器的符号换行功能–wrap。
xeno-config发出正确的链接器标志集以启用这种插入除非给出–no-auto-init。
Adding your own setup code
Xenomai代表了粘在应用程序上的引导程序处理程序它实现了一种灵活的机制来有序地运行安装程序代码。
此机制基于安装程序描述符结构setup_descriptor每个描述符定义一组可选的处理程序这些应由Xenomai引导程序代码在初始化过程的不同阶段调用。为每个描述符分配一个优先级该优先级定义了实现同一处理程序的多个描述符之间的调用顺序。相应的C定义和类型应通过包含xenomai/init.h获得。
共有三个初始化阶段按优先顺序列出每个阶段在设置描述符中分配了一个处理程序。 NULL处理程序可用于跳过给定阶段的描述符。
通过setup_descriptor→tune()进行工厂调整步骤。每个设置描述符都有机会为标准或应用程序定义的可调参数分配值。这是我们用于更改默认可调值的处理程序。
通过setup_descriptor→parse_option()进行命令行选项解析。如果存在此处理程序则setup_descriptor→options必须指向getopt3选项数组枚举此描述符定义的有效选项。
→parse_option()处理程序将找到的每个选项的位置传递给命令行该位置与setup_descriptor→options数组中的条目以及接收到的参数值匹配。如果该选项不包含任何参数则将传递NULL。
每当在命令行上传递–help开关时都会调用→help()处理函数。从低优先级到高优先级将依次调用描述符链中的所有帮助处理程序。
选项解析在调整步骤之后进行因此影响可调参数的命令行选项可以覆盖→tune处理程序定义的出厂值。
通过setup_descriptor→init()正确执行初始化步骤。根据从先前步骤获得的当前设置调用此处理程序以调出其提供的功能或服务。
如果成功所有处理程序应返回零如果出错则返回否定的POSIX错误代码。一旦出错引导程序序列将立即终止并且应用程序将退出并显示一条致命消息。
下面的示例在初始化序列中引入了自定义代码用于设置一些基本可调参数然后在启用特定功能之前解析一组本地命令行选项。在触发了同一类别的所有Xenomai处理程序之后将调用这些自定义处理程序。例如此类代码可以是附加到您的应用程序的辅助库的一部分或由您的主要可执行文件实现。
添加自定义设置代码
3.6 AM528移植
1、ipipe补丁
cd Scara_kernel
patch ../ipipe-core-4.4.71-arm-9.patch根据.rej文件解决掉patch中的冲突部分。
2、xenomai补丁
生成xenomai补丁文件
cd xenomai-3.0.10
./scripts/prepare-kernel.sh --linux/home/myc/vx/xenomai/Scara_kernel/ --archarm --outpatch../xenomai-3.0.10.patch对kernel打上补丁
cd Scara_kernel
patch -p1 ../xenomai-3.0.10.patch3、编译内核
make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- tisdk_am57xx-evm_defconfig
make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- am57xx-evm-reva3.dtb
make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- zImage -j44、编译用户态库
./configure CFLAGS-marcharmv7-a -mtunecortex-a15 -mfloat-abihard -mfpuneon -ffast-math --hostarm-linux-gnueabihf --with-corecobalt --enable-smp --enable-psharedmake DESTDIR/home/myc/vx/xenomai/build_fs install5、编译应用
6、测试
rootam57xx-evm:~# latency Sampling period: 1000 usTest mode: periodic user-mode taskAll results in microseconds
warming up...
RTT| 00:00:01 (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| 0.346| 1.050| 6.007| 0| 0| 0.346| 6.007
RTD| 0.319| 0.984| 8.974| 0| 0| 0.319| 8.974
RTD| 0.293| 1.060| 4.826| 0| 0| 0.293| 8.974
RTD| 0.427| 1.060| 4.907| 0| 0| 0.293| 8.974
RTD| 0.263| 0.857| 4.336| 0| 0| 0.263| 8.974
RTD| 0.145| 0.812| 5.591| 0| 0| 0.145| 8.974
RTD| 0.303| 0.845| 6.775| 0| 0| 0.145| 8.974
RTD| 0.254| 0.869| 6.612| 0| 0| 0.145| 8.974
RTD| 0.112| 0.773| 4.904| 0| 0| 0.112| 8.974
RTD| 0.246| 0.810| 6.530| 0| 0| 0.112| 8.974
RTD| 0.405| 0.915| 5.487| 0| 0| 0.112| 8.974
RTD| 0.239| 0.847| 6.692| 0| 0| 0.112| 8.974
RTD| 0.261| 0.825| 4.577| 0| 0| 0.112| 8.974
RTD| 0.397| 0.920| 6.609| 0| 0| 0.112| 8.974
RTD| 0.254| 0.792| 4.627| 0| 0| 0.112| 8.974
RTD| 0.414| 0.939| 4.738| 0| 0| 0.112| 8.974
RTD| 0.249| 0.862| 4.575| 0| 0| 0.112| 8.974
RTD| 0.246| 0.821| 5.607| 0| 0| 0.112| 8.974
RTD| 0.290| 0.955| 5.037| 0| 0| 0.112| 8.974
RTD| 0.238| 0.832| 4.410| 0| 0| 0.112| 8.974
RTD| 0.259| 0.821| 4.458| 0| 0| 0.112| 8.974
RTT| 00:00:22 (periodic user-mode task, 1000 us period, priority 99)3.7 ubuntu移植
1、ipipe补丁
cd linux-4.14.134
patch -p1 ../ipipe-core-4.19.89-x86-9.patch2、xenomai补丁
生成xenomai补丁
cd xenomai-3.0.10
./scripts/prepare-kernel.sh --linux/home/pwl/xenomai/linux-4.19.99 --archx86_64 --outpatch/home/pwl/xenomai/xenomai-3.0.10.patch打上xenomai补丁
cd linux-4.14.134
patch -p1 ../xenomai-3.0.10.patch3、编译内核
pwlpwl-T5:~/xenomai/linux-4.14.134$ make menuconfig
scripts/kconfig/mconf Kconfig
warning: (X86_VSMP HYPERV) selects PARAVIRT which has unmet direct dependencies (HYPERVISOR_GUEST !IPIPE)注意去掉和IPIPE冲突的X86_VSMP HYPERV特性。
make menuconfig
make bzImage modules4、安装内核
make INSTALL_MOD_STRIP1 modules_install
sudo mkinitramfs /lib/modules/4.14.134 -o /boot/initrd.img-4.14.134-xenomai
sudo cp arch/x86/boot/bzImage /boot/vmlinuz-4.14.134-xenomai
sudo cp System.map /boot/System.map-4.14.134-xenomai
sudo update-grub25、编译用户态库并安装
cd xenomai-3.0.10
./configure --with-corecobalt --enable-smp --enable-pshared
make DESTDIR/home/myc/vx/xenomai/build_fs install
sudo make install6、测试