Xenomai编程笔记

    Xenomai 是一种采用双内核机制的Linux 内核的强实时扩展。由于Linux 内核本身的实现方式和复杂度,使得Linux 本身不能使用于强实时应用。在双内核技术下,存在一个支持强实时的微内核,它与Linux 内核共同运行于硬件平台上,实时内核的
优先级高于Linux 内核,它负责处理系统的实时任务,而Linux 则负责处理非实时任务,只有当实时内核不再有实时任务需要处理的时候,Linux 内核才能得到运行的机会。
 
   Xenomai 基于Adeos(Adaptive Domain Environment for Operating System)实现双内核机制,图3.1 显示了Xenomai、Adeos 和Linux 这三个软件实体之间的相互关系。Adeos 是扩展Linux 的基础环境,有必要对其做一个较详细的介绍。 
 
Xenomai 简介 
Adeos 的设计目标是为操作系统提供一个灵活的、可扩展的自适应环境,在这个环境下,多个相同或不同的操作系统可以共存,共享硬件资源。目前,Adeos 是基于Linux 内核实现的,主要的应用是在Linux 的实时化方面,使基于Linux 的系统能满足强实时的要求(例如Xenomai 和RTAI3.2 以上版本都是基于Adeos 实现的)。在基于Adeos 的系统中,每个操作系统都是在独立的域内运行(但不一定所有的域实现的都是操作系统,也可以是完成其它功能的软件实体),每个域可以有独立的地址空间和类似于进程、虚拟内存等的软件抽象层,而且这些资源也可以由不同的域共享。
 
对于一个计算机系统来说,系统的运行是由内部和外部的中断和异常所触发的,例如系统时钟中断对操作系统来说就是最重要的。所以,Adeos 的主要工作就是管理硬件的中断,根据域的优先级依次执行相应域的中断服务程序,从而驱动域内的系统运行;同时,Adeos 还提供域之间的通信机制实现域的调度等。 
 
为了实现对中断的管理和域之间的优先级控制,Adeos 使用了中断管道(Interrupt Pipe)的概念。Adeos 通过中断管道在不同的域之间传播中断,而且提供了相应的机制可以让域改变自己在中断管道中的优先级。 
 
Xenomai 在Adeos 系统中的域优先级高于Linux 域,每当中断到来之后,Adeos先调度Xenomai 对该中断进行处理、执行中断相应的实时任务,只有当Xenomai没有实时任务和中断需要处理的时候,Adeos 才会调度Linux 运行,这就保证了Xenomai的中断响应速度和实时任务不受Linux 的影响,从而提供了实时系统的可确定性。 
 
Xenomai 实时内核为开发强实时应用提供了丰富的功能,主要包括实时线程调度与管理、用户空间实时任务支持、线程同步服务、时钟服务、中断服务、动态内存申请和实时对象注册服务等。 
 
 
Linux用户空间(Linux普通进程,Xenomai用户线程)
 
Linux内核
Xenomai域
Xenomai实
时线程
API
实时内核
硬件抽象层
中断管道    域调度     域管理
Adeos
硬件平台(ARM920T)
 
图3.1 Xenomai、Adeos 和Linux 实体关系图 
 
下面简要介绍几类常用的Xenomai 原生API: 
1、任务管理 
Xenomai 本身提供的一系列多任务调度机制,主要有以下一些函数: 
intrt_task_create (RT_TASK *task, const char *name, int stksize, int prio, intmode) ; 任务的创建; 
int rt_task_start(RT_TASK *task, void(*entry)(void *cookie), void *cookie) ;  开始任务调度; 
intrt_task_suspend (RT_TASK *task);              挂起任务; 
intrt_task_delete (RT_TASK *task) ;                删除任务; 
intrt_task_set_periodic (RT_TASK *task, RTIME idate, RTIME period) ;设置任务运行周期; 
intrt_task_wait_period (unsigned long *overruns_r) ;挂起任务到下个周期再运行; 
intrt_task_set_priority (RT_TASK *task, int prio);设置任务优先级; 
2、内存堆服务 
intrt_heap_create (RT_HEAP *heap, const char *name, size_t heapsize, int mode) 创建一个内存堆空间或一个共享内存片段; 
intrt_heap_delete (RT_HEAP *heap)  删除一个内存堆空间或一个共享内存片段; 
int rt_heap_bind(RT_HEAP *heap, const char *name, RTIME timeout)  绑定共享内存空间; 
intrt_heap_unbind (RT_HEAP *heap)  接触共享内存空间的绑定; 
3、信息管道服务 
intrt_pipe_create (RT_PIPE *pipe, const char *name, int minor, size_t poolsize) 创建通讯管道; 
intrt_pipe_delete (RT_PIPE *pipe)  删除通讯管道; 
ssize_t rt_pipe_receive  (RT_PIPE  *pipe,  RT_PIPE_MSG **msgp,  RTIME  timeout) 从管道接受一条信息; 
ssize_trt_pipe_send (RT_PIPE *pipe, RT_PIPE_MSG *msg, size_t size, int mode)  向管道发送一条信息; 
Xenomai 在实时内核之上还提供了多组API 模拟多种不同的实时操作系统和编程规范,包括POSIX、VxWorks 和RTAI 等。这使得实时应用系统的开发和移植变得非常方便。 
3.2.2.2 Xenomai 的移植 
Xenomai  提供了一个与 Linux  无缝结合地实时子系统,所以首先要做的是将Xenomai 作为目标内核的一部分进行编译。Xenomai  提供了一个脚本文件scripts/prepare-kernel.sh  用来进行目标内核的编译。这个脚本文件同样能够应用于Adeos 对于内核的补丁。脚本文件使用方法如下: 
$scripts/preparekernel.sh 
–linux=[adeos=][arch=
--linux 选项指定了目标内核源代码树路径。 
--adeos 选项指定了与目标内核版本很相匹配的Adeos补丁的路径。如果Adeos
已经安装在目标内核中,这个参数选项可以忽略。如果系统侦测到以前安装过Adeos补丁,将不再安装。 
--arch 选项给脚本文件指定了目标板的结构。如果没有说明该选项,编译系统将会侦测并推荐一个合理的默认值。 
   
图  3.2  添加实时子系统后的内核选项图 
下面以x86 和linux2.6.15 架构为例说明配置命令的使用: 
$ cd 
$scripts/preparekernel.sh  
–linux=/usr/src/linux2.6.15ipipe–arch=x86 
adeos=ksrc/arch/i386/patches/adeosipipe2.6.15i3861.201.patch 
建立实时子系统后,需要对Xenomai 内核选项进行配置,其方法与通常Linux 内核的配置方法类似。 
如图3.2 所示,标准内核结合了实时子内核后,将会在内核配置选项中多出一条“Real-time sub-system”选项。用户可在子选项的子菜单中选择或去除相应的功能。 
      配置内核选项后,直接配置Xenomai 部分并编译、安装Linux 内核就成功安装了Xenomai 实时子内核。命令如下: 
      $ mkdir && cd 
$./configure enablex86sep 
$ makeinstall 
以上是以x86 架构为例说明Xenomai 实时子系统的安装,本文中的基于ARM 的目标板实时子系统的安装基本步骤相同,只需在安装后,将生成的库文件即宿主机/usr/Xenomai 目录拷贝至目标板的/usr/目录下,以供应用程序使用。 
3.2.2.3  移植的注意点 
   通过以上章节的分析,移植Xenomai 至Linux 内核的步骤就清晰了,但在其过程中会有很多莫名其妙的错误,大部分都是因为在配置Linux 内核选项时有些选项是必须安装却没有安装,有些选项选择后会对 Xenomai  的编译产生一些致命的错误而导致实时子系统安装的失败,特别是与时间有关的选项。所以,移植 Xenomai  需要仔细阅读相关文档,遇到问题时逐步排除可能产生问题的选项,才能正确安装子系统。 
3.2.2.4  移植正确性验证 
       Xenomai 子系统移植完成后,如系统没有报错即可编写实时程序对系统移植的正确性进行验证。 
      验证程序不需要实现十分复杂的功能,本文中编写的测试程序,使用了Xenomai实时子系统的原生API,该程序创建了任务,指定了任务的优先级,对任务的实体部分进行了简单地实现,部分源代码如下所示: 
      #include  
      #include  
      #define TASK_PRIO 99 /* Highest RT priority */ 
      #define TASK_MODE 0 /* No flags */ 
      #define TASK_STKSZ 0 /* Stack size (use default one) */ 
      #define TASK_PERIOD 100000 /* 100 usc period */ 
      RT_TASK task_desc; 
      void sampling_task (void *cookie) 
      { 
             unsigned long overruns; 
             int err; 
             /* The task will undergo a 100 uscperiodic timeline. */ 
             err = rt_task_set_periodic(NULL,TM_NOW,TASK_PERIOD); 
             ... 
             for (;;) { 
             err =rt_task_wait_period(&overruns); 
             if (err) 
                    break; 
             /* Work for the current period*/ 
             } 
      } 
      int main (int argc, char *argv[]) 
      { 
             int err; 
             /* Disable paging for this program'smemory. */ 
             ... 
             /* Create a real-time task */ 
             err =rt_task_create(&task_desc, 
             "MyTaskName", 
             TASK_STKSZ, 
             TASK_PRIO, 
             TASK_MODE); 
             if (!err) 
             /* If successfully created, start thetask. */ 
            rt_task_start(&task_desc,&sampling_task,NULL); 
             ... 
      } 
       该测试程序编译后运行无误,实时子系统Xenomai 安装正确,用户可进行实时任务的设计和开发。 
3.2.3 实时性能测试 
   实时系统最为重要的特性在于能够在限定的时间内完成指定功能并对外部事件作出正确响应。这一特性要求系统任务响应时间足够少,中断响应足够快。其中,任务响应时间更是主要指标,所以选用任务响应时间作为测试的时间指标。其含义为: 
      任务响应时间:自中断发出处理请求到相应程序即将执行的时间间隔; 
中断响应时间:从中断触发到完成响应并开始执行中断服务例程(interrupt service routine,ISR)第一条指令的时间间隔。 
Xenomai 提供了很多高精度的时间函数,可以获取系统时钟值,测试任务响应时间正是利用了这些函数,关键伪代码如下: 
while(1){ 
      … 
      start = gettime(); 
      wait_np(); 
//理论延时period; 
      end=gettime(); 
      response=end – start – period; 
      //response 可近似认为是任务响应时间; 
      … 

中断响应时间测试思路为:编写一个发生时机可以预知的中断,可以在中断发生前捕获系统当前时间 start,中断发生并调用 ISR  时再次捕获系统当前时间 end,则end-start 的值可近似认为是中断响应时间。 
经测试,Xenomai实时子系统的实时性能达到微秒级的响应,能够很好的满足实时应用的要求。

你可能感兴趣的:(Linux)