术,在发生硬件中断时,实时内核只是把它放到中断记录表中,在没有实时应用运行时才向Linux派发这些被保留的中断。同时实时内核还监控Linux的开/关中断原语,以避免这些操作把实际的中断关闭而影响实时内核的响应时间。主要包括以下几个方面:
①函数替换
首先是Linux的开/关中断等函数被RTAI提供的函数所替代,这样Linux不能真正的关闭中断,而只是一个软件的机制。当外设中断到来时,RTAI的替换函数必须检查硬件中断标志是否关闭和调用是否来自RTAI上下文。在此两种情况之下,不能直接调用Linux的中断处理函数,中断分发器只用于当CPU处于Linux上下文并且Linux开中断时,才调用Linux的中断处理例程(ISR)。
②全局变量
RTAI为每个中断源定义了一个全局的数据结构:
struct linux_irq{struct list_head list;
int irq;
int masked;
int pending;}
其中list_head用于从Linux的中断挂起队列中插入或删除。irq被初始化为此结构体所对应的中断号。masked是一个标志位,可能具有以下3种值:1表示在中断延迟函数中设置;2表示由Linux中断mask函数设置;3表示由Linux中断unmask函数设置。
③中断传递
中断传递可能被RTAI中断分发器或Linux的开中断函数所调用。当Linux打开中断时,检查挂起中断链表是否为空,若不为空,则循环进行处理,直到所有中断都被处理为止。其算法如下:
while(irqlist 不空){
从irqlist队列中取出一个中断;
if(该中断正在被屏蔽) continue;
else{关闭Linux中断;执行中断处理例程;开中断;}}
3.4 RTAI的任务调度
①细粒度定时器的实现
标准Linux的定时器提供10ms的调度粒度,不足以达到实时响应速度的要求。RTAI通过提高系统时钟精度改写了时钟处理程序,使之支持更高分辨率时钟的周期模式,引入了两种定时器模式:periodic(周期性)和one shot(一次性)。对于周期性实时任务应用periodic模式,只需要在初始化时对定时器进行设置,保证了处理效率;对于非周期实时任务应用one shot模式。在任何时刻,时钟的下一次中断间隔由所有定时器中到期最早的一个来决定。一旦定时器到期,内核便能够立刻响应,内核的响应开销只由中断服务的时间所决定,使得实时应用的响应时间可以达到纳秒级的水平,完全可以满足一般工业应用实时控制的要求。
②调度机制
在实时任务之间、实时任务与Linux应用之间提供丰富的通讯机制(如FIFO管道、MBUFF共享内存等)进行通信;Linux应用可以通过这些通讯机制与实时应用交互,同时也可以通过实时内核中的实时应用代理(LXRT)运行实时任务。
任何实时任务的优先级都要高于Linux,只有当没有实时任务运行时,Linux才被调度,从而保证了RTAI的实时性。任务的调度周期在任务初始化时由程序员指定,也可在某个时刻调用API修改。rt_task_struct包含多个双向指针,所有的任务(包括Linux)都包括在各个链表中。如 ready任务链表,其中Linux为链表头,当发生调度时,RTAI在ready链表中搜寻优先级最大的任务并切换执行,当没有实时任务在ready态时,则切换至Linux系统。
4. RTAI在μClinux上的移植
4.1 RTHAL的移植
图2基于RTAI的μClinux应用程序结构
借鉴RTHAL的思想,对μClinux核心进行改动,将其与中断控制器隔离,核心中的所有中断操作指令都被替换成相应的宏。对于RTAI的移植而言,最重要的部分就是RTHAL的移植,RTAI绝大部分与处理器相关的代码都在这里,这里以作者所使用的S3C4510B(ARM7的核)和μClinux环境为例进行说明。由于RTAI已经有ARM处理器上的版本,因此可以参照ARM7处理器的RTHAL来移植到S3C4510B上。由于μClinux为针对没有MMU处理器的操作系统,因此RTAI需要去除与MMU相关的代码。对于S3C4510B和μClinux,其RTHAL主要包括如下数据结构:
{指向IDT的指针;
打开/关闭中断函数(cli,stiflags);
控制中断mask/unmask函数;
中断状态的数据描述符(status,hander,nestedlevel,…);}
4.2定时器的移植
如前面分析,对于一个实时操作系统,必须有精确的计时。在i386体系结构中,有时间标签计数器TSC(Time Stamp Count),在S3C4510B处理器上没有这个寄存器,可以采用计时器2(Timer1)来模拟TSC的功能。每来一个时钟脉冲,Timer1的 TCNT1寄存器减1,减到零后产生时钟中断,再从TDATA1中读TCNT1的值,往复运行。具体的做法是使用一个内核的全局变量,每次时钟中断来以后,在Timer1的寄存器中读出值,计算其增量,为了使系统更精确,必须将Timer1中断设置为最高优先级,这样就可以模拟64位的TSC寄存器,从而得到当前的准确计时。
5.基于RTAI与μClinux的
|